跳到主要内容

战斗系统架构

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” 并选定一个招式时发生的事:

  1. Request actions —— 玩家从招式面板选择招式,同时 AI 为另一支队伍选择。
  2. 顺序 —— 所有行动按招式优先级排序,然后按速度(高者先行,平局时随机)。
  3. 招式执行(对较快的战斗者):
    • 检查命中 —— 招式命中吗?
    • 计算伤害(如果是伤害招式):((2*Level/5+2) * Power * Atk/Def) / 50 + 2
    • 应用各项系数:目标数、天气、地形、暴击、随机浮动(0.85-1.0)、本系加成、属性相克、状态,以及来自特性、道具和己方场地状态的附加项。
    • 应用次要效果(能力变化、异常状态)。
  4. 招式执行(对较慢的战斗者,如果仍然站着)。
  5. 回合结束回调与状态倒计时 —— 天气和状态伤害、携带道具效果、特性触发。
  6. 濒死处理 —— 如果某个战斗者 HP 为 0,则处理濒死(给予经验/努力值,检查进化)并请求替换。

野生战斗与训练师战斗​

方面野生战斗训练师战斗
EnemyTypeWildTrainer
可以捕捉是否
可以逃跑是,如果正在战斗的敌人中没有首领(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 旁边添加你自己的模块(参见战斗内部机制)。