战斗系统架构
MCE 的战斗系统建立在模块化组件架构之上。BattleManager 与 15 个专用模块位于同一个 GameObject 上,每个模块负责战斗的一个方面。BattleStateMachine 驱动回合循环,整个系统通过 Zenject 依赖注入连接在一起。

那个画面上的一切都是不同模块汇报的结果:两条血条、行动
菜单、精灵及其入场动画,以及决定谁先行动的出手顺序。
BattleManager 并不直接拥有其中任何一项 —— 它依次询问每个模块,而战斗
循环决定接下来发生什么。
架构概览
BattleLauncher (ScriptableObject, loads the battle scene)
└─ BattleManager (orchestrator, on the battle scene's GameObject)
├─ BattleStateMachine (turn loop)
├─ BattleManagerBattlersModule (battler lookup, sprites, forms)
├─ BattleManagerHealthModule (HP, fainting)
├─ BattleManagerMovesModule (move execution)
├─ BattleManagerItemsModule (in-battle items)
├ ─ BattleManagerCaptureModule (catch mechanics)
├─ BattleManagerAIModule (enemy decisions)
├─ BattleManagerAnimationModule (intro and flow animations)
├─ BattleManagerAudioModule (music, SFX)
├─ BattleManagerStatusesModule (burn, poison, sleep, field effects...)
├─ BattleManagerBattlerStatsModule (stat stages)
├─ BattleManagerBattlerSwitchModule (party switching)
├─ BattleManagerRostersModule (party management)
├─ BattleManagerScenariosModule (weather, terrain, scenario setup)
├─ BattleManagerMegaModule (Mega Evolution)
└─ BattleManagerCharactersModule (trainer characters and sprites)
BattleManager
BattleManager 是中央协调者。它本身不包含战斗逻辑,而是委托给它的模块。它的职责是:
- 战 斗开始时初始化所有模块。
- 为模块间通信提供共享的参照点(每个模块通过它访问其同级模块)。
- 接收来自界面(玩家行动)和 AI(敌方行动)的命令。
- 发出战斗开始和结束事件的信号。
BattleManager 实现了 IBattleManager。它公开当前战斗的 BattleType(SingleBattle 或 DoubleBattle)和 EnemyType(Wild 或 Trainer)。其成员参见 BattleManager API。
BattleStateMachine
BattleStateMachine 是一个协程循环。每个回合它会:
Update which battlers have fought
→ Request actions (the player's menu, the AI of every other roster)
→ Determine the order (move priority, then speed)
→ Perform the actions
→ After-turn callbacks (before and after the status countdown)
→ Status countdown (weather, burn, poison...)
→ Check and process fainted battlers (XP, replacements)
→ [next turn]
直到 IsBattleOver。然后它播放结束动画,发放奖金(或扣除战败金),并运行战斗结束回调。当战斗是服务器权威的(MCE Online)时,回合由服务器而不是本地解析:循环发送行动并展示返回的结果。
战斗模块深入解析
BattleManagerBattlersModule
管理双方的 Battler 实例。Battler 通过战斗中的状态扩展了 MonsterInstance:
- 能力等级(
StatStage、BattleStatStage)、暴击等级、替身、易变状态。 - 它交战过的战斗者列表、消耗的道具、它使用过和承受过的上一个招式。
- 通过
MonsterMathHelper计算的有效能力值(基础值 + 个体值 + 努力值 + 性格 + 能力等级)。
BattleManagerHealthModule
通过 ChangeLife 处理所有 HP 变化(伤害与治疗,带有受击动画和音效),并负责检测与处理濒死的战斗者。
BattleManagerMovesModule
执行招式(PerformMove):命中与闪避检查、招式的效果和动画。伤害本身由招式(DamageMove)使用招式中的公式计算。
BattleManagerItemsModule
战斗中的道具使用 —— 恢复道具、异常状态治疗、X 道具 —— 从玩家的背包中消耗。训练师有自己的 Bag。
BattleManagerCaptureModule
野生怪物的捕捉(TryCaptureMonster):
- 根据物种的捕获率、当前 HP、异常状态和球(
BattleUtils.CalculateShakeProbability)计算捕获率。 - 球的摇晃动画,在捕获或逃脱之前进行多次摇晃判定。
- 把捕获的怪物加入玩家的队伍或存储。
BattleManagerAIModule
为每支队伍保存一个可插拔的 BattleAI 策略:
- 接收当前战斗状态。
- 返回一个
BattleAction(使用招式、替换、使用道具、逃跑)。 - 内置策略以及如何串联或编写它们,参见战斗 AI。
BattleManagerStatusesModule
管理各种状态:
- 异常状态(每个战斗者同时只有一个):灼伤、冰冻、麻痹、中毒、剧毒、睡眠。
- 易变状态(
VolatileStatus,位于战斗者上):混乱、畏缩、被困等。 - 己方场地状态(
SideStatus)和全场状态(GlobalStatus),用于覆盖场地一侧或全场的效果。战斗的天气和地形属于场景设定(BattleManagerScenariosModule)。
每种状态都通过 TriggerStatusesCountdown 及其前后的回调,在回合的正确时刻施加效果(例如回合结束时的灼伤伤害、招式前的麻痹)。
BattleManagerBattlerStatsModule
处理能力等级的修改:
- 能力等级范围为 -6 到 +6。
- 攻击、防御、特攻、特防和速度的等级会应用一个倍率:+1 = 1.5 倍,+2 = 2.0 倍,…… +6 = 4.0 倍,以及 -1 = 0.67 倍,-2 = 0.5 倍,…… -6 = 0.25 倍。命中和闪避使用各自的表。
- 特性可以对等级变化做出反应(
Battler提供OnStatChange和AfterStatChanged钩子)。
BattleManagerMegaModule
Mega 进化支持:
- 检查战斗者的物种是否有可用的 Mega 形态(
CanSwitchToMegaForm)。 - 允许每场战斗每支队伍一次 Mega 进化。
- 播放形态变化并应用 Mega 形态的数据。
BattleManagerCharactersModule
为双方提供角色:训练师精灵(BattleTrainerSprite)、奖金和战败金。关于玩家背面如何绘制和播放动画,参见训练师背面精灵与投球。
战斗流程示例
下面是玩家选择 “Fight” 并选定一个招式时发生的事:
- Request actions —— 玩家从招式面板选择招式,同时 AI 为另一支队伍选择。
- 顺序 —— 所有行动按招式优先级排序,然后按速度(高者先行,平局时随机)。
- 招式执行(对较快的战斗者):
- 检查命中 —— 招式命中吗?
- 计算伤害(如果是伤害招式):
((2*Level/5+2) * Power * Atk/Def) / 50 + 2 - 应用各项系数:目标数、天气、地形、暴击、随机浮动(0.85-1.0)、本系加成、属性相克、状态,以及来自特性、道具和己方场地状态的附加项。
- 应用次要效果(能力变化、异常状态)。
- 招式执行(对较慢的战斗者,如果仍然站着)。
- 回合结束回调与状态倒计时 —— 天气和状态伤害、携带道具效果、特性触发。
- 濒死处理 —— 如果某个战斗者 HP 为 0,则处理濒死(给予经验/努力值,检查进化)并请求替换。
野生战斗与训练师战斗
| 方面 | 野生战斗 | 训练师战斗 |
|---|---|---|
EnemyType | Wild | Trainer |
| 可以捕捉 | 是 | 否 |
| 可以逃跑 | 是,如果正在战斗的敌人中没有首领(CanPlayerRun) | 否 |
| 奖金 | 无 | 有 |
| AI | 启动器的默认 AI,除非战斗自带 | 相同 |
| 再战 | 随机遭遇 | 脚本化(CommandGraph) |
对战塔与匿名训练师
暂停菜单中的 Battle Tower(TowerController)运行一个无尽的 PvE 进程:它根据 TowerRuleSet 验证玩家的队伍,通过 IBattleLauncher 发起与生成的 AI 对手的战斗,并在该战斗自己的结束回调中应用结果并重新发起下一场战斗 —— 持续到战败为止。面向玩家的流程和默认平衡,参见秘密基地与玩家道馆指南。
塔中的对手是匿名的:它们根据玩家的队伍引用生成,没有 CharacterData 也没有 Bag。战斗系统容忍这类训练师,而不是抛出异常:
BattleManagerCharactersModule保护敌方训练师精灵集合 ——CharacterData为 null 意味着队伍仍会战斗,只是没有训练师精灵(也不提供奖金)。BattleManagerItemsModule在敌方背包为 null 时用一个空的Bag代替,因此 AI 得到的是一个有效但没有道具的背包。
这就是让一个没有场景、没有身份、凭空生成的对手,能够像精心设计的训练师一样战斗的原因。
战斗配置
两层配置战斗:
BattleConfigurationFile(Create > MCE > Battle > Configuration)保存面向玩家的战斗 设置:Battle Style 和 Battle Animation Speed Up(1 到 8)。它通过BattleManager.Configuration读取,BattleSpeed就来自这里。BattleLauncher资产保存战斗场景、野生与训练师的战斗音乐以及 Default AI。
捕捉难度和经验规则位于 MCESettings 资产和游戏的全局数据中。
监听战斗事件
无需源码
战斗启动器在依赖注入中绑定,并在战斗启动、即将卸载和结束时发出通知:
[Inject] private IBattleLauncher battleLauncher;
battleLauncher.SubscribeToBattleLaunched(() => Debug.Log("Battle launched"));
battleLauncher.SubscribeToBattleEnded(result => Debug.Log($"Battle ended, won: {result.PlayerWon}"));
IBattleSystem(engine.Battle,带有 OnBattleStarted 和 OnBattleEnded)是 SDK 自己的契约,但引擎尚未向它提供数据:参见 IBattleSystem。
拥有源码(Source 与 Studio 版本)
拥有源码访问权限时,你可以通过 BattleManager.SubscribeToBattleInitialized 和 SubscribeToBattleFinished 订阅,或在 BattleManager 旁边添加你自己的模块(参见战斗内部机制)。