Пошаговые битвы элементалей

Общее описание

Модуль "Пошаговые битвы элементалей" реализует основную игровую механику, где игрок выбирает локацию, элемент и конкретного элементаля для сражения, после чего проходит пошаговый бой с визуальными анимациями и отображением результатов. Эта часть отвечает за управление фазами игры, взаимодействие с пользователем при подготовке к бою и демонстрацию анимаций и итогов поединка.

Данный модуль решает задачи:


Структура и взаимодействие компонентов

Пошаговые битвы реализованы через три основных React-компонента:

Все эти компоненты получают и передают данные через пропсы, взаимодействуя с состоянием игры (gameState), а бизнес-логика и игровые правила сосредоточены в gameLogic.ts.

Взаимодействие можно представить так:

flowchart LR
    A[BattleComponent] -->|Выбор локации, элемента, элементаля| B[gameLogic.ts]
    A -->|Запуск боя| C[BattleAnimationPixi]
    C -->|Окончание анимации| D[BattleResultPage]
    D -->|Возврат в меню| A
    B -->|Расчёт результатов боя| D

Этапы и ключевая функциональность

1. Выбор и подготовка боя (BattleComponent.tsx)

Компонент BattleComponent управляет несколькими фазами игры:

Компонент поддерживает удобную навигацию с клавиатуры (стрелки, Enter, Backspace, Escape), а также управляет состояниями фокуса и подсказок для повышения UX.

Важные особенности:

Фрагмент для выбора локации иллюстрирует работу с кнопками и подсказками:

{locations.map(([key, location], index) => {
  const isAffordable = canAffordLocation(player.mana, key as Location);
  return (
    <button
      key={key}
      disabled={!isAffordable}
      onClick={() => isAffordable && onSelectLocation(key as Location)}
      aria-label={`${location.name} location, ${location.mana} mana cost${!isAffordable ? ', insufficient mana' : ''}`}
      ...
    >
      {location.emoji} {location.name} - {location.mana} Mana
      {!isAffordable && <small>Need {location.mana - player.mana} more mana</small>}
    </button>
  );
})}

2. Анимация и эффекты боя (BattleAnimationPixi.tsx и BattleEffects.tsx)

BattleAnimationPixi отвечает за визуализацию битвы, реализованную с использованием PixiJS, что позволяет создавать плавные и эффектные 2D-анимации.

Основные этапы анимации:

Внутри фазы elementals выделены подфазы — поочередное появление игрока и оппонента, бой и объявление победителя.

Компонент также адаптируется под мобильные устройства, снижая количество частиц и упрощая эффекты для производительности.

Компонент BattleEffects добавляет элементно-специфичные визуальные эффекты (огонь, вода, земля) поверх анимации битвы:

Пример создания эффекта искр для огня в BattleEffects:

const createSparkle = () => {
  const sparkle = new PIXI.Graphics();
  sparkle.beginFill(colors.secondary);
  // Форма звезды или ромба в зависимости от устройства
  sparkle.drawPolygon(points);
  sparkle.endFill();
  ...
  const animate = () => {
    sparkle.y -= moveSpeed;
    sparkle.alpha -= alphaSpeed;
    sparkle.rotation += rotationSpeed;
    if (sparkle.alpha <= 0 || sparkle.y < -20) {
      app.stage.removeChild(sparkle);
      sparkle.destroy();
    } else {
      requestAnimationFrame(animate);
    }
  };
  animate();
};

3. Отображение результатов (BattleResultPage.tsx)

После завершения анимаций вызывается BattleResultPage, отображающий:

Компонент использует данные из gameState.battleLog и gameState.currentOpponent, получая подробности боя из бизнес-логики.

Пример отображения изменения маны:

<span className={`results-stat-value ${isVictory ? 'victory' : isDefeat ? 'defeat' : 'primary'}`}>
  {battleLog.baseWager === 0 ? 'No change (free)' : `${battleLog.finalChange > 0 ? '+' : ''}${battleLog.finalChange}`}
</span>

Взаимодействие с бизнес-логикой (gameLogic.ts)

Вся логика определения правил боя и результатов сосредоточена в модуле gameLogic.ts. Он включает:

Например, функция определения победителя по стихиям реализована так:

export const getWinner = (element1: Element, element2: Element): BattleResult => {
  if (element1 === element2) return 'draw';

  const winConditions: Record<Element, Element> = {
    earth: 'water', // Земля поглощает воду
    water: 'fire',  // Вода тушит огонь
    fire: 'earth',  // Огонь сжигает землю
  };

  return winConditions[element1] === element2 ? 'player' : 'opponent';
};

Расчёт результата с учётом защиты элементалей:

export const calculateBattleResult = (
  baseWager: number,
  playerElement: Element,
  playerElemental: ElementalRarity | null,
  opponentElement: Element,
  opponentElemental: ElementalRarity | null,
  playerCollection?: ElementalCollection
): {
  playerManaChange: number;
  opponentManaChange: number;
  winner: BattleResult;
  protectionSaved: number;
} => {
  ...
  // Логика вычисления итогов с учётом защиты
};

Таким образом, компоненты пользовательского интерфейса делегируют ключевые вычисления и принятие решений этому модулю, обеспечивая разделение ответственности и удобство поддержки.


Визуальная структура взаимодействия компонентов битвы

sequenceDiagram
    participant User as Игрок
    participant BattleComp as BattleComponent
    participant GameLogic as gameLogic.ts
    participant BattleAnim as BattleAnimationPixi
    participant BattleResult as BattleResultPage

    User->>BattleComp: Выбрать локацию
    BattleComp->>GameLogic: Проверить доступность локации
    BattleComp->>User: Показать выбор элемента
    User->>BattleComp: Выбрать элемент
    BattleComp->>User: Показать выбор элементаля
    User->>BattleComp: Выбрать элементаля
    BattleComp->>BattleAnim: Запустить анимацию боя
    BattleAnim->>GameLogic: Запросить данные боя
    BattleAnim->>User: Показать анимацию сражения
    BattleAnim->>BattleComp: Сообщить о завершении анимации
    BattleComp->>BattleResult: Показать результаты боя
    User->>BattleResult: Нажать "Бой снова" или "В меню"
    BattleResult->>BattleComp: Возврат к выбору

Итог

Модуль "Пошаговые битвы элементалей" объединяет пользовательский интерфейс и визуализацию с бизнес-логикой игры, формируя интерактивный процесс подготовки, проведения и отображения битв. Его архитектура обеспечивает плавный пользовательский опыт, доступность, поддержку туториалов и адаптацию под разные устройства. Взаимодействие между BattleComponent, BattleAnimationPixi, BattleEffects, BattleResultPage и gameLogic.ts позволяет создать цельный и расширяемый функционал пошаговых боёв.