Saltar al contenido principal

Arquitectura del sistema de batalla

El sistema de batalla de MCE está construido sobre una arquitectura modular de componentes. El BattleManager está en un GameObject junto con 15 módulos especializados, cada uno responsable de un único aspecto del combate. Un BattleStateMachine impulsa el bucle de turnos, y todo el sistema se conecta mediante inyección de dependencias de Zenject.

Una batalla en curso

Todo lo que hay en esa pantalla es un módulo distinto que informa: las dos barras de salud, el menú de acciones, los sprites y su animación de entrada, y el orden de turnos que decidió quién mueve primero. El BattleManager no es dueño de nada de eso directamente: pregunta a cada módulo por turno y el bucle de la batalla decide qué viene después.

Descripción general de la arquitectura​

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​

El BattleManager es el coordinador central. No contiene lógica de batalla propia, sino que delega en sus módulos. Sus responsabilidades son:

  • Inicializar todos los módulos cuando empieza una batalla.
  • Proporcionar un punto de referencia compartido para la comunicación entre módulos (cada módulo llega a sus hermanos a través de él).
  • Recibir órdenes de la interfaz (acciones del jugador) y de la IA (acciones del enemigo).
  • Señalizar los eventos de inicio y fin de la batalla.

El BattleManager implementa IBattleManager. Expone el BattleType (SingleBattle o DoubleBattle) y el EnemyType (Wild o Trainer) de la batalla en curso. Consulta la API de BattleManager para ver sus miembros.

BattleStateMachine​

El BattleStateMachine es un único bucle de corrutina. En cada turno:

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]

hasta IsBattleOver. Entonces reproduce la animación final, reparte el dinero del premio (o cobra el dinero de la derrota) y ejecuta los callbacks de fin de batalla. Cuando una batalla es autoritativa en el servidor (MCE Online), el turno lo resuelve el servidor en lugar de hacerlo localmente: el bucle envía las acciones y muestra lo que vuelve.

Análisis a fondo de los módulos de batalla​

BattleManagerBattlersModule​

Gestiona las instancias de Battler de ambos bandos. Un Battler extiende MonsterInstance con el estado en batalla:

  • Niveles de estadísticas (StatStage, BattleStatStage), nivel de crítico, sustituto, estados volátiles.
  • La lista de combatientes contra los que luchó, los objetos consumidos, el último movimiento que usó y que recibió.
  • Estadísticas efectivas (base + IV + EV + naturaleza + niveles de estadística) mediante MonsterMathHelper.

BattleManagerHealthModule​

Gestiona todos los cambios de HP mediante ChangeLife (daño y curación, con la animación y el sonido del golpe), y la detección y procesamiento de los combatientes debilitados.

BattleManagerMovesModule​

Ejecuta los movimientos (PerformMove): comprobaciones de precisión y evasión, los efectos del movimiento y su animación. El daño en sí lo calcula el propio movimiento (DamageMove) usando la fórmula de Movimientos.

BattleManagerItemsModule​

Uso de objetos en batalla (objetos curativos, curas de estado, objetos X) consumidos de la mochila del jugador. Los entrenadores tienen su propia Bag.

BattleManagerCaptureModule​

Captura de monstruos salvajes (TryCaptureMonster):

  • Cálculo de la tasa de captura según la tasa de captura de la especie, el HP actual, el estado alterado y la bola (BattleUtils.CalculateShakeProbability).
  • La animación de sacudida de la bola, con varias comprobaciones de sacudida antes de la captura o el escape.
  • Agrega el monstruo capturado al equipo o al almacenamiento del jugador.

BattleManagerAIModule​

Mantiene una estrategia BattleAI conectable por equipo:

  • Recibe el estado actual de la batalla.
  • Devuelve una BattleAction (usar un movimiento, cambiar, usar un objeto, huir).
  • Consulta IA de batalla para ver las estrategias integradas y cómo encadenarlas o escribirlas.

BattleManagerStatusesModule​

Gestiona todo tipo de estados:

  • Estados alterados (uno a la vez por combatiente): quemadura, congelación, parálisis, veneno, veneno grave, sueño.
  • Estados volátiles (VolatileStatus, en un combatiente): confusión, retroceso, atrapado y más.
  • Estados de bando (SideStatus) y estados globales (GlobalStatus) para efectos que cubren un lado del campo o todo él. El clima y el terreno de la batalla pertenecen al escenario (BattleManagerScenariosModule).

Cada estado aplica sus efectos en el momento correcto del turno mediante TriggerStatusesCountdown y los callbacks a su alrededor (p. ej., el daño por quemadura al final del turno, la parálisis antes de un movimiento).

BattleManagerBattlerStatsModule​

Gestiona las modificaciones de niveles de estadística:

  • Los niveles de estadística van de -6 a +6.
  • Los niveles de Ataque, Defensa, Ataque especial, Defensa especial y Velocidad aplican un multiplicador: +1 = 1,5x, +2 = 2,0x, ... +6 = 4,0x y -1 = 0,67x, -2 = 0,5x, ... -6 = 0,25x. La precisión y la evasión usan su propia tabla.
  • Las habilidades pueden reaccionar a los cambios de nivel (el Battler ofrece los ganchos OnStatChange y AfterStatChanged).

BattleManagerMegaModule​

Soporte para la Megaevolución:

  • Comprueba si la especie del combatiente tiene una forma Mega disponible (CanSwitchToMegaForm).
  • Permite una Megaevolución por equipo y batalla.
  • Reproduce el cambio de forma y aplica los datos de la forma Mega.

BattleManagerCharactersModule​

Da a cada bando sus personajes: los sprites de entrenador (BattleTrainerSprite), el dinero del premio y el de la derrota. Consulta Sprites de espalda del entrenador y el lanzamiento para saber cómo se dibuja y se anima la espalda del jugador.

Ejemplo de flujo de batalla​

Esto es lo que ocurre cuando el jugador selecciona "Fight" y elige un movimiento:

  1. Request actions -- El jugador elige un movimiento en el panel de movimientos mientras la IA elige por el otro equipo.
  2. Orden -- Todas las acciones se ordenan por prioridad del movimiento y después por Velocidad (el más alto va primero, con un desempate aleatorio).
  3. Ejecución del movimiento (para el combatiente más rápido):
    • Comprobar la precisión: ¿acierta el movimiento?
    • Calcular el daño (si es dañino): ((2*Level/5+2) * Power * Atk/Def) / 50 + 2
    • Aplicar los factores: número de objetivos, clima, terreno, golpe crítico, tirada aleatoria (0,85-1,0), STAB, efectividad de tipo, estado y los añadidos de habilidades, objetos y estados de bando.
    • Aplicar los efectos secundarios (cambios de estadísticas, estados alterados).
  4. Ejecución del movimiento (para el combatiente más lento, si sigue en pie).
  5. Callbacks de fin de turno y cuenta atrás de estados -- Daño de clima y de estados, efectos de objetos equipados, activación de habilidades.
  6. Procesamiento de debilitamientos -- Si un combatiente tiene 0 HP, se procesa el debilitamiento (dar XP/EV, comprobar la evolución) y se piden reemplazos.

Batallas salvajes frente a batallas de entrenador​

AspectoBatalla salvajeBatalla de entrenador
EnemyTypeWildTrainer
Se puede capturarSíNo
Se puede huirSí, si ningún enemigo que luche es un alfa (CanPlayerRun)No
Dinero de premioNoSí
IALa IA por defecto del lanzador, salvo que la batalla traiga la suyaLa misma
RevanchaEncuentro aleatorioCon guion (CommandGraph)

Torre de Batalla y entrenadores anónimos​

La Battle Tower del menú de pausa (TowerController) ejecuta una progresión PvE interminable: valida el equipo del jugador contra un TowerRuleSet, lanza una batalla contra un oponente de IA generado mediante IBattleLauncher y, desde el propio callback de fin de esa batalla, aplica el resultado y vuelve a lanzar el siguiente combate, hasta que hay una derrota. Consulta la guía de Bases secretas y gimnasios de jugador para ver el flujo orientado al jugador y el equilibrio por defecto.

Los oponentes de la torre son anónimos: generados a partir de las referencias del equipo del jugador, no llevan CharacterData ni Bag. El sistema de batalla tolera a esos entrenadores en lugar de lanzar una excepción:

  • BattleManagerCharactersModule protege el conjunto de sprites de entrenador enemigo: un CharacterData nulo significa que el equipo sigue luchando, solo que sin sprite de entrenador (y sin aportar dinero de premio).
  • BattleManagerItemsModule sustituye una Bag vacía cuando la mochila del enemigo es nula, de modo que la IA recibe una mochila válida pero sin objetos.

Eso es lo que permite que un oponente generado, sin escena y sin identidad, luche exactamente como un entrenador creado a mano.

Configuración de la batalla​

Dos capas configuran las batallas:

  • El BattleConfigurationFile (Create > MCE > Battle > Configuration) contiene los ajustes de batalla orientados al jugador: el Battle Style y el Battle Animation Speed Up (de 1 a 8). Se lee mediante BattleManager.Configuration y de él proviene BattleSpeed.
  • El asset BattleLauncher contiene la escena de batalla, la música de batalla salvaje y de entrenador y la Default AI.

Las reglas de dificultad de captura y de experiencia viven en el asset MCESettings y en los datos globales del juego.

Escuchar los eventos de batalla​

Sin código fuente​

El lanzador de batalla está enlazado en la inyección de dependencias y notifica cuando se lanza una batalla, está a punto de descargarse y termina:

[Inject] private IBattleLauncher battleLauncher;

battleLauncher.SubscribeToBattleLaunched(() => Debug.Log("Battle launched"));
battleLauncher.SubscribeToBattleEnded(result => Debug.Log($"Battle ended, won: {result.PlayerWon}"));

IBattleSystem (engine.Battle, con OnBattleStarted y OnBattleEnded) es el contrato propio del SDK, pero el motor todavía no lo alimenta: consulta IBattleSystem.

Con código fuente (ediciones Source y Studio)​

Con acceso al código fuente puedes suscribirte mediante BattleManager.SubscribeToBattleInitialized y SubscribeToBattleFinished, o agregar tu propio módulo junto al BattleManager (consulta Internos de la batalla).