← 返回作品列表
Unity 2022.3 LTS 回合制战棋 强化学习 AI 个人项目

回合战旗·单車破阵

一款把「确定性战斗内核」放在第一位的回合制战棋。同一个战斗规则同时跑在 Unity 客户端和独立的 .NET 模拟器里,用批量对局喂出强化学习 AI, 再用联赛 Elo 量化每个单位的强度。

  • 当前版本v0.4.5
  • 引擎Unity 2022.3.62f3c1
  • 单位规模16 单位 + 坟墓
  • 逻辑帧率固定 60 Hz

项目简介

我在做什么,以及为什么这么做

玩法

  • ATB 行动条:速度决定出手频率,速度 225 的单位一回合内能行动 2.25 次,速度同时还是回复与机动的来源。
  • 网格战棋:单位占地、BFS 寻路、2×2 大型单位与身体格交叉判定。
  • 非对称阵营:人类 10 个单位靠冲锋与装甲打爆发;死灵 6 个单位靠瘟疫、汲取与魂体打消耗。
  • 三场景流程:主菜单 → 选将布阵 → 战斗,可单战也可连战。

为什么强调「确定性」

  • 战斗逻辑只有一个时间入口,固定步长 1/60 秒,逻辑层禁止读取 Time.deltaTime。
  • 这样同一套输入在任何帧率下结果完全一致,才能让模拟器和客户端对得上账。
  • 历史上踩过坑:流血曾按真实时间计时、按渲染帧扣血,结果 13fps 下总伤害只剩 1/4,240fps 下却翻了 4 倍。这条约束就是那次事故换来的。

战斗结算公式

全部以代码为准,Unity 与模拟器双端共用同一套常量

机制公式 / 规则
普通伤害max(ATK - DEF, 1),护甲单位先按减伤率折算,再扣护甲、最后扣血
移动力1 + max(⌊log(速度/100)/log(1.5)⌋, 0),阈值 150→2 格、225→3 格
ATB 频率行动条 += 速度 × dt × 60,与速度成正比
冲锋增伤伤害 × (1 + 0.5 × 本回合移动步数)
能量上限智力 × 10
回合结束回复生命 剩余移动力 × 1% 最大生命;能量 剩余移动力 × 0.5 × 智力
护甲建筑 最大生命 × 1(减伤 50%);装甲 最大生命 × 4(减伤 60%)
反震近战且目标 DEF 更高时:原始伤害 × min((目标DEF - 自身DEF)/自身DEF, 1)
远程偏折50% 概率伤害 × 0.5
锋锐流血破甲活物:20 帧 DOT,每帧 实际伤害 × 5%,合计约 100%
钝击目标 DEF 减半、无视护甲减伤;对无甲活物触发骨折(速度 ×0.3)
汲取伤害 = 智力 × 0.75,无视 DEF 与魂体减伤,对活物回血,固定耗能 15
瘟疫每层 3% 最大生命 DOT / 20 帧,四正向传播全层、四斜向传播半层;亡灵免疫伤害但仍可传播
魂体90% 普通减伤、免疫骨折、无反震、穿透移动与攻击
唤灵领域影响力 512 / 2^(距离-1),从坟墓复活亡灵

单位图鉴

16 个可用单位 + 1 个建筑。数值取自工程内的原型资源,胜率来自 1000 局启发式对局实测

人类系

活物 · 10 单位 · 全部 1×1 占地
战车
SS

冲锋装甲坦克

活物冲锋装甲
速度225
HP150
ATK35
DEF25
INT5
范围1
总胜 45%
外战 22%
机枪
SS

远程据点堡垒

活物远程钝击据点
速度100
HP100
ATK40
DEF10
INT10
范围5
总胜 26%
外战 8%
骑兵
A+

冲锋骑兵

活物冲锋
速度150
HP120
ATK25
DEF15
INT10
范围1.5
总胜 32%
外战 14%
剑士
A

横扫锋锐主力

活物横扫锋锐
速度80
HP100
ATK30
DEF10
INT10
范围1.5
总胜 25%
外战 9%
枪客
A

拦截锋锐

活物锋锐拦截
速度80
HP100
ATK30
DEF10
INT10
范围2
总胜 24%
外战 9%
医者
A-

仁心治疗师

活物仁心
速度60
HP120
ATK10
DEF15
INT20
范围2
总胜 26%
外战 14%
棍棒
A-

横扫钝击战士

活物横扫钝击
速度70
HP100
ATK25
DEF20
INT5
范围1.5
总胜 30%
外战 10%
旗帜
B+

鼓舞坦克

活物鼓舞
速度50
HP200
ATK20
DEF20
INT15
范围1.5
总胜 26%
外战 9%
弓手
B

远程锋锐

活物锋锐远程
速度80
HP80
ATK25
DEF5
INT10
范围3
总胜 25%
外战 8%
白卒
B--

基础步兵

活物
速度100
HP80
ATK20
DEF5
INT10
范围1
总胜 26%
外战 8%

死灵系

亡灵 · 6 单位 + 坟墓建筑
祭司
S+

唤灵汲取核心

亡灵远程汲取唤灵
速度80
HP150
ATK0
DEF0
INT50
范围3
总胜 80%
外战 81%
巫妖
S

瘟疫汲取领主

亡灵远程汲取瘟疫
速度60
HP250
ATK10
DEF15
INT40
范围4
总胜 88%
外战 90%
血魔
A

汲取恐吓突击手

亡灵恐吓汲取
速度120
HP120
ATK25
DEF5
INT20
范围1.5
总胜 91%
外战 90%
幽魂
A-

魂体骚扰者

亡灵恐吓魂体
速度150
HP20
ATK20
DEF0
INT5
范围1.5
总胜 84%
外战 87%
僵尸
B+

瘟疫肉盾

亡灵瘟疫
速度40
HP200
ATK10
DEF20
INT0
范围1
总胜 89%
外战 91%
骷髅
B--

亡灵炮灰

亡灵
速度75
HP40
ATK20
DEF2
INT0
范围1
总胜 84%
外战 85%
坟墓
体系单位

建筑尸体(唤灵载体)

建筑尸体
速度100
HP生成时=原25%
ATK—
DEF5
INT0
范围0
体系单位 · 由唤灵机制生成

平衡实测与已知问题

HeuristicModel 1000 局自动对战统计 —— 包括对自己不利的结论

模型局数总胜率vs 人类专精vs 死灵专精vs 综合
人类专精50024.4%—21.6%27.2%
死灵专精50073.0%78.0%—68.0%
综合模型75049.1%72.4%28.4%46.4%
人类系单位选取率总胜内战外战
战车63%45%100%22%
机枪58%26%65%8%
骑兵56%32%71%14%
剑士59%25%62%9%
枪客62%24%65%9%
医者62%26%63%14%
棍棒58%30%81%10%
旗帜70%26%76%9%
弓手69%25%72%8%
白卒68%26%78%8%
死灵系单位选取率总胜内战外战
祭司69%80%77%81%
巫妖71%88%83%90%
血魔83%91%93%90%
幽魂81%84%78%87%
僵尸83%89%82%91%
骷髅85%84%82%85%
已知问题:阵营严重失衡。 无论哪种模型配对,人类 vs 死灵的外战胜率都落在 8% ~ 22% 区间。 从单位维度看,人类系内部胜负关系是合理的(内战 62%~100%), 说明这是阵营级而非单兵级的问题——亡灵的治疗反转、瘟疫免疫与坟墓续航形成了系统性优势。 这条结论我保留在文档里没有改口径,它也是下一版平衡改动的首要依据。

技术实现

这个项目里我认为最有价值的部分

双端共用的确定性内核

Unity 客户端与 .NET 9 模拟器各自实现一遍战斗逻辑,但共用同一套公式常量。逻辑层只有唯一的固定步长入口,帧率、垂直同步、卡顿都不会改变任何数值判定。这是模拟结果能反哺游戏平衡的前提。

独立离线模拟器

脱离 Unity 的纯 C# 工程,复现了 13 项战斗机制,用于批量自动对战与联赛评估。实测 500 局连续运行零崩溃——它比在编辑器里跑对局快几个数量级,是训练数据的主要来源。

PyTorch 训练管线

CNN + MLP + Attention 的混合网络,约 190 万参数。先做行为克隆(BC)达到 63% 决策准确率,导出 ONNX 后由 C# 端直接推理,PPO 流程也已跑通验证。

用 Elo 而不是「胜率」评估强度

早期用「对教师模型的胜率」衡量强弱,口径混乱且不可比。现在统一改用联赛 Elo,所有模型放进同一个池子里对局排名,跨版本的数据才真正可比。

版本历程

从能打到能被量化

  • v0.1 – v0.3战斗循环、网格与寻路、单位特性系统成型;补齐操作按钮面板与路径规划滤镜
  • v0.4.0独立 C# 模拟器(13 项机制全复现)、PyTorch 训练管线、BC 训练 + ONNX 导出、选将布阵系统
  • v0.4.12×2 单位移动/攻击范围 BFS 修复、瘟疫包围盒传播算法、连战/单战双模式
  • v0.4.3恐吓机制重做(智力可负、负能量清算)、三场景架构、跨场景数据桥
  • v0.4.5待命跳过回合的回复丢失修复;能量消耗判定统一为固定 15;全量审计所有扣能路径