Внутреннее устройство сражений: подробный разбор
Это руководство предназначено для пользователей редакций Source и Studio, имеющих доступ ко всему исходному коду MCE на C#.
Пятнадцать модулей, один оркестратор. BattleManager не содержит собственной боевой логики — он задаёт
вопросы, а конечный автомат решает, что будет спрошено дальше.
Этот документ подробно рассматривает архитектуру BattleManager, его 15 модулей, BattleStateMachine, формулы, которые использует сражение, и способы добавления новых боевых возможностей. О публичных членах см. API BattleManager.
Архитектура BattleManager
BattleManager следует модульному паттерну композиции. Вместо монолитного класса на тысячи строк боевая логика разделена между специализированными модулями, которые живут на одном GameObject и общаются через центр — BattleManager. Менеджер объявляет их через [RequireComponent], поэтому добавление BattleManager на GameObject добавляет весь набор:
[RequireComponent(typeof(BattleStateMachine))]
[RequireComponent(typeof(BattleManagerBattlersModule))]
[RequireComponent(typeof(BattleManagerBattlerSwitchModule))]
[RequireComponent(typeof(BattleManagerBattlerStatsModule))]
[RequireComponent(typeof(BattleManagerHealthModule))]
[RequireComponent(typeof(BattleManagerMovesModule))]
[RequireComponent(typeof(BattleManagerItemsModule))]
[RequireComponent(typeof(BattleManagerCaptureModule))]
[RequireComponent(typeof(BattleManagerRostersModule))]
[RequireComponent(typeof(BattleManagerAIModule))]
[RequireComponent(typeof(BattleManagerScenariosModule))]
[RequireComponent(typeof(BattleManagerStatusesModule))]
[RequireComponent(typeof(BattleManagerCharactersModule))]
[RequireComponent(typeof(BattleManagerAnimationModule))]
[RequireComponent(typeof(BattleManagerAudioModule))]
[RequireComponent(typeof(BattleManagerMegaModule))]
public class BattleManager : OpenMonBehaviour<BattleManager>, IBattleManager, IPlayerDataReceiver
{
// Module accessors, resolved from sibling components:
internal BattleManagerBattlersModule Battlers => GetCachedComponent<BattleManagerBattlersModule>();
internal BattleManagerHealthModule BattlerHealth => GetCachedComponent<BattleManagerHealthModule>();
internal BattleManagerMovesModule Moves => GetCachedComponent<BattleManagerMovesModule>();
// ...BattleManagerBattlerSwitch, BattlerStats, Items, Capture, Rosters, AI,
// Scenario, Statuses, Characters, Animation, Audio and Megas.
}
Базовый класс BattleManagerModule
Все модули наследуют от обобщённого BattleManagerModule<T>:
public abstract class BattleManagerModule<T> : OpenMonBehaviour<T>
where T : BattleManagerModule<T>
{
protected BattleManager BattleManager => GetCachedComponent<BattleManager>();
// The same accessors the manager has, so modules can call into each other:
protected BattleManagerBattlersModule Battlers => BattleManager.Battlers;
protected BattleManagerHealthModule BattlerHealth => BattleManager.BattlerHealth;
protected BattleManagerMovesModule Moves => BattleManager.Moves;
// ...
}
Поэтому модулю не нужны ни код регистрации, ни вызов Initialize: это MonoBehaviour на GameObject сражения, и он обращается к остальным через унаследованные аксессоры. GetCachedComponent<T>() (из OpenMonBehaviour) находит любой соседний компонент.