← 返回全部作品

主力项目 · 独立开发

ThirdBattleLine

一款围绕五行元素、元素反应与天气机制展开的 Unity 卡牌对战游戏。重点不只在卡牌数量,而在可扩展的效果组合、稳定的结算顺序与移动端可读性。

Unity 2022 LTSC#ScriptableObjectURPAddressablesDOTween
TapTap 页面GitHub 源码 · 私有仓库,暂未公开
ThirdBattleLine 项目封面
项目类型
游戏项目
开发时间
个人长期项目
我的职责
独立开发 / 系统、玩法与 UI
当前状态
持续开发

01 / BACKGROUND

项目背景与目标

项目源于对传统卡牌战斗系统的拆解实践。我希望用五行元素、天气与反制机制形成可推演的对局,同时让新增卡牌尽量通过配置完成,而不是持续堆叠特殊判断。

  • 建立可扩展的数据驱动卡牌系统
  • 保证连锁效果、事件响应和表现播放顺序清晰
  • 完成单机与 AI 对局闭环
  • 在移动端维持卡牌信息的可读性与操作反馈

02 / RESPONSIBILITY

我负责的部分

01

整体架构、核心玩法与回合流程设计

02

卡牌配置、运行时状态和效果系统开发

03

事件结算、表现队列与 AI 决策链路

04

卡牌 UI、交互反馈与移动端适配

05

核心规则测试、性能热点定位与渐进式重构

03 / SYSTEMS

核心玩法与技术架构

数据驱动卡牌

使用 CardSO 保存静态配置,RuntimeCard 承载对局状态;EffectSO、ActionSO 与 ConditionSO 组合复用卡牌效果。

效果与事件结算

主流程通过队列顺序结算,跨系统响应通过事件机制分发;将战斗逻辑和动画表现拆开,避免动画时长反向影响规则。

五行与天气

元素克制、元素反应和天气共同改变对局条件,使牌序、站位与触发时机成为可规划的决策。

AI 对局

按照动作生成、规则过滤、局面评分和执行拆分决策流程,方便单独测试并逐步调整策略。

04 / ENGINEERING EVIDENCE

创新代码与核心实现

以下内容来自项目实际仓库,经过脱敏和节选,用于说明设计思路与工程取舍,而不是用代码行数制造复杂感。

创新机制

五行反应的可预测结算内核

ElementalHitSystem.cs

把元素组合、伤害来源、天气快照、概率与随机结果收束为不可变结果对象;同一入口既能用于正式结算,也能用于 AI 预演与测试注入。

  • 显式传入 WeatherSnapshot,避免读取易变的全局天气状态
  • rollPercent 可注入,使概率逻辑能够稳定复现并编写单元测试
  • 配置数据库与 FallbackRules 双路径,兼顾数据驱动和资源缺失兜底
public readonly struct ElementalReactionResult
{
    public readonly bool Triggered;
    public readonly ElementalReactionType ReactionType;
    public readonly int ChancePercent;
    public readonly int RollPercent;
}

public static ElementalReactionResult PreviewCombat(
    RuntimeCard attacker,
    RuntimeCard defender,
    WeatherSnapshot weather,
    int? rollPercent = null)
{
    var result = Preview(
        attacker.NativeElement,
        defender.NativeElement,
        DamageSourceType.Combat,
        attacker.CurrentAttack,
        weather,
        rollPercent);

    return IsSuppressedByExtinguish(attacker, defender, result)
        ? ElementalReactionResult.NoReaction
        : result;
}
核心框架

效果逻辑与视觉表现的提交点分离

EffectPresentationService / EffectContext

法术、部署、持续触发、普攻和死亡共用同一表现入口。表现层在命中关键帧调用 onImpact,规则层不需要知道弹道、全屏动画或目标锚点如何实现。

  • Projectile、SpawnAtTarget、Fullscreen、CardCollision 与自定义 Presenter 统一分发
  • EffectContext 保存逻辑语义,PresentationProfile 保存视觉语义
  • 旧资源字段可自动解析为新 Profile,支持渐进式迁移而非一次性重写
IEnumerator PlayRoutine(
    EffectPresentationRequest request,
    Func<IEnumerator> onImpact = null,
    Action onComplete = null);

// 表现层只在命中关键帧提交规则结算
yield return presentationService.PlayRoutine(
    request,
    onImpact: () => ResolveSpellImpactRoutine(context),
    onComplete: () => ReleasePresentation(request));
网络架构

Nakama Relay 与对局编排器

Networking/Core + Networking/DTO

网络层通过独立程序集接入 Nakama,将玩家意图 PlayerCommandDto 与服务器/Relay 结果 GameEventDto 分开处理,再由 NetworkGameOrchestrator 负责入队、去重和远端回放。

  • 设备认证、Session 缓存、Socket、Matchmaker 与 Relay 已形成隔离封装
  • OpCode、DTO 与序列化集中管理,降低客户端和服务端协议漂移风险
  • NetworkCardLocator 使用 runtimeCardId、手牌索引与 sourceCardId 多级定位远端卡牌
public interface IMatchNetworkClient
{
    event Action<PlayerCommandDto> OnPlayerCommand;
    event Action<GameEventDto> OnGameEvent;

    Task ConnectAsync();
    Task SendCommandAsync(PlayerCommandDto command);
}

// Orchestrator 统一接收、去重并排队回放
private void HandleRemoteCommand(PlayerCommandDto command)
{
    if (!processedCommandIds.Add(command.commandId)) return;
    pendingCommands.Enqueue(command);
}

04 / PROBLEM SOLVING

开发难点与解决过程

问题 01

多个效果连续触发时,逻辑结算与动画播放容易互相阻塞。

解决方案

拆分规则队列与表现队列,规则先产生明确结果,再由表现层消费指令;跨系统事件按优先级响应。

结果

结算职责更清晰,新效果接入时不必直接控制整段动画流程。

问题 02

卡牌数量增加后,大量继承类和条件判断难以维护。

解决方案

将静态配置、运行时状态、执行动作与触发条件分离,通过 ScriptableObject 组合效果。

结果

相似效果可以复用,配置与运行时修改互不污染。

问题 03

移动屏幕上同时展示费用、名称、属性、攻防与描述会造成拥挤。

解决方案

建立统一信息层级,关键数值固定位置,次要说明使用分区排版,并针对手机触控尺寸调整交互区域。

05 / RESULT

最终效果

  • 完成单机与 AI 对局链路
  • 建立核心规则 EditMode 测试
  • 形成卡牌配置、运行时状态、效果结算和表现播放的完整链路
  • 已提供 TapTap 试玩版本与玩家反馈记录

06 / MEDIA

项目截图与演示

实机剪辑:回合流程、卡牌部署与效果结算
单位牌示例:费用、攻防、关键词与描述层级
单位牌示例
角色卡牌示例
TapTap 试玩反馈截图,分数为截图当时记录

07 / RETROSPECTIVE

项目复盘

01

系统扩展性不能只依赖抽象层数量,新增一张卡牌所需的修改范围更能检验架构。

02

逻辑和表现解耦后,需要更明确的事件生命周期与取消策略。

03

下一阶段将继续验证网络化边界和更完整的对局内容。

NEXT PROJECT《余光》