整体架构、核心玩法与回合流程设计
主力项目 · 独立开发
ThirdBattleLine
一款围绕五行元素、元素反应与天气机制展开的 Unity 卡牌对战游戏。重点不只在卡牌数量,而在可扩展的效果组合、稳定的结算顺序与移动端可读性。

- 项目类型
- 游戏项目
- 开发时间
- 个人长期项目
- 我的职责
- 独立开发 / 系统、玩法与 UI
- 当前状态
- 持续开发
01 / BACKGROUND
项目背景与目标
项目源于对传统卡牌战斗系统的拆解实践。我希望用五行元素、天气与反制机制形成可推演的对局,同时让新增卡牌尽量通过配置完成,而不是持续堆叠特殊判断。
- →建立可扩展的数据驱动卡牌系统
- →保证连锁效果、事件响应和表现播放顺序清晰
- →完成单机与 AI 对局闭环
- →在移动端维持卡牌信息的可读性与操作反馈
02 / RESPONSIBILITY
我负责的部分
卡牌配置、运行时状态和效果系统开发
事件结算、表现队列与 AI 决策链路
卡牌 UI、交互反馈与移动端适配
核心规则测试、性能热点定位与渐进式重构
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
开发难点与解决过程
多个效果连续触发时,逻辑结算与动画播放容易互相阻塞。
拆分规则队列与表现队列,规则先产生明确结果,再由表现层消费指令;跨系统事件按优先级响应。
结果结算职责更清晰,新效果接入时不必直接控制整段动画流程。
卡牌数量增加后,大量继承类和条件判断难以维护。
将静态配置、运行时状态、执行动作与触发条件分离,通过 ScriptableObject 组合效果。
结果相似效果可以复用,配置与运行时修改互不污染。
移动屏幕上同时展示费用、名称、属性、攻防与描述会造成拥挤。
建立统一信息层级,关键数值固定位置,次要说明使用分区排版,并针对手机触控尺寸调整交互区域。
05 / RESULT
最终效果
- ✓完成单机与 AI 对局链路
- ✓建立核心规则 EditMode 测试
- ✓形成卡牌配置、运行时状态、效果结算和表现播放的完整链路
- ✓已提供 TapTap 试玩版本与玩家反馈记录
06 / MEDIA
项目截图与演示
07 / RETROSPECTIVE
项目复盘
系统扩展性不能只依赖抽象层数量,新增一张卡牌所需的修改范围更能检验架构。
逻辑和表现解耦后,需要更明确的事件生命周期与取消策略。
下一阶段将继续验证网络化边界和更完整的对局内容。