Skip to content

Latest commit

 

History

History
331 lines (294 loc) · 22.3 KB

README.md

File metadata and controls

331 lines (294 loc) · 22.3 KB

Battle Module

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

Текущий проект является переписыванием с нуля старой версии боевой системы, написанной в 2017 году, посмотреть которую в работе можно на сайте игры.

Установка и запуск демо-боя

git clone https://github.com/WalkWeb/Battle-Module.git battle

cd battle

composer install

cd public/

php -S localhost:8000

В браузере открываем http://localhost:8000/ - отобразится пример боя. Вы можете отредактировать параметры юнитов демо-боя в файле public/index.php

Пример (1 на 1)

use Battle\BattleFactory;
use Battle\Container\Container;
use Battle\Response\Statistic\Statistic;

$data = [
    [
        'id'                           => '81941b8a-f7ca-447e-8951-36777ae6e79e',
        'name'                         => 'Warrior',
        'level'                        => 3,
        'avatar'                       => '/images/avas/humans/human001.jpg',
        'life'                         => 110,
        'total_life'                   => 110,
        'mana'                         => 60,
        'total_mana'                   => 60,
        'melee'                        => true,
        'class'                        => 1,
        'race'                         => 1,
        'command'                      => 1,
        'add_concentration_multiplier' => 0,
        'cunning_multiplier'           => 0,
        'add_rage_multiplier'          => 0,
        'abilities'                    => [],
        'offense'      => [
            'damage_type'         => 1,
            'weapon_type'         => 2,
            'physical_damage'     => 25,
            'fire_damage'         => 0,
            'water_damage'        => 0,
            'air_damage'          => 0,
            'earth_damage'        => 0,
            'life_damage'         => 0,
            'death_damage'        => 0,
            'attack_speed'        => 0.8,
            'cast_speed'          => 0,
            'accuracy'            => 200,
            'magic_accuracy'      => 100,
            'block_ignoring'      => 0,
            'critical_chance'     => 10,
            'critical_multiplier' => 200,
            'damage_multiplier'   => 100,
            'vampirism'           => 0,
            'magic_vampirism'     => 0,
        ],
        'defense'      => [
            'physical_resist'     => 20,
            'fire_resist'         => 10,
            'water_resist'        => 0,
            'air_resist'          => 0,
            'earth_resist'        => 0,
            'life_resist'         => 20,
            'death_resist'        => 0,
            'defense'             => 120,
            'magic_defense'       => 80,
            'block'               => 0,
            'magic_block'         => 0,
            'mental_barrier'      => 0,
            'max_physical_resist' => 75,
            'max_fire_resist'     => 75,
            'max_water_resist'    => 75,
            'max_air_resist'      => 75,
            'max_earth_resist'    => 75,
            'max_life_resist'     => 75,
            'max_death_resist'    => 75,
            'global_resist'       => 0,
            'dodge'               => 0,
        ],
    ],
    [
        'id'                           => 'bf75c4a3-b866-4787-88c7-8db57daf3d64',
        'name'                         => 'Skeleton',
        'level'                        => 2,
        'avatar'                       => '/images/avas/monsters/005.png',
        'life'                         => 65,
        'total_life'                   => 65,
        'mana'                         => 0,
        'total_mana'                   => 0,
        'melee'                        => true,
        'class'                        => null,
        'race'                         => 8,
        'command'                      => 2,
        'add_concentration_multiplier' => 0,
        'cunning_multiplier'           => 0,
        'add_rage_multiplier'          => 0,
        'abilities'                    => [],
        'offense'      => [
            'damage_type'         => 1,
            'weapon_type'         => 1,
            'physical_damage'     => 0,
            'fire_damage'         => 0,
            'water_damage'        => 0,
            'air_damage'          => 0,
            'earth_damage'        => 0,
            'life_damage'         => 0,
            'death_damage'        => 20,
            'attack_speed'        => 1.2,
            'cast_speed'          => 0,
            'accuracy'            => 240,
            'magic_accuracy'      => 140,
            'block_ignoring'      => 0,
            'critical_chance'     => 6,
            'critical_multiplier' => 200,
            'damage_multiplier'   => 100,
            'vampirism'           => 0,
            'magic_vampirism'     => 0,
        ],
        'defense'      => [
            'physical_resist'     => 10,
            'fire_resist'         => 30,
            'water_resist'        => 30,
            'air_resist'          => 0,
            'earth_resist'        => 0,
            'life_resist'         => 0,
            'death_resist'        => 70,
            'defense'             => 150,
            'magic_defense'       => 30,
            'block'               => 0,
            'magic_block'         => 0,
            'mental_barrier'      => 0,
            'max_physical_resist' => 75,
            'max_fire_resist'     => 75,
            'max_water_resist'    => 75,
            'max_air_resist'      => 75,
            'max_earth_resist'    => 75,
            'max_life_resist'     => 75,
            'max_death_resist'    => 75,
            'global_resist'       => 0,
            'dodge'               => 0,
        ],
    ],
];

$statistic = new Statistic();
$container = new Container();
$container->set('Statistic', $statistic);

$battle = BattleFactory::create($data, $container);

$response = $battle->handle();

$view = $battle->getContainer()->getViewFactory()->create();
echo $view->renderHead(); // example layout styles
echo $view->renderBattle($response);

Как выглядит бой (4 игрока против босса)

alt text

Итоговая статистика

Alchemist во время боя призвал Fire Elemental в свою команду – по этому в статистике появился дополнительный юнит

alt text

100% покрытие кода unit-тестами

alt text

GitLab CI

alt text

Архитектурные принципы

Модуль написан на принципах DDD:

  • Имеет свой, независимый неймспейс Battle
  • Написан полностью независимым от фреймворков, и прочих тяжелых зависимостей
  • Изолированно выполняет свою задачу: принимает данные по сражающимся юнитам (это может быть как бой 1 на 1 так и команда на команду), обрабатывает бой и возвращает результат, на основании которого можно отобразить бой на фронте
  • Классы в модуле полностью соответствуют «бизнес»-сущностям, а именно:
    • Бой обрабатывается в классе Battle
    • Сражающиеся две команды реализованы в классах Command
    • Команды состоят из юнитов (это могут быть как персонажи игроков, так и монстры), реализованных в классе Unit
    • Процесс боя проходит в раундах – классе Round в котором каждый живой юнит должен совершить свой ход. После того, как все юниты походили, начинается новый раунд
    • Раунд состоит из ходов одного юнита, и эти ходы реализованы в классах Stroke
    • Взаимодействие между юнитами построено на обмене абстрактных Action – это может быть как удар, так и лечение, так и использование способности. При этом для внешних объектов совершенно не важно, что это – просто у одного юнита запрашивается коллекция его действий, и выполняется. При этом само действие определяет, на кого оно должно примениться.
    • Результат боя сохраняется в Response
    • Статистика по бою сохраняется в Statistic
    • Класс отвечающий за мультиязычность – Translation
  • Все важные зависимости завязаны на интерфейсы, а не на конкретные классы
  • Большое внимание уделено тестам и проработке исключительных ситуаций. Покрытие кода тестами 100%

Планы

  • Ошибка: если юнит умер от эффекта, то способность активирующаяся при смерти не срабатывает
  • Добавить перевод имен монстров и боссов
  • Систематизировать создание иконки оружия/расы
  • Добавить монстра-босса, который при смерти делится на 2 части, а те, в свою очередь, также делятся на 2 части при смерти
  • Добавить монстра-босса, который имеет 80% вероятность при смерти не умереть, а восстановить 100% здоровья
  • Добавить монстра-босса, который не имеет обычной атаки, но призывает новых монстров на способностях концентрации и ярости
  • Иконкам эффектов добавить описание через
  • Добавить механику отключения базовой атаки у юнита (возможно, просто через 0 скорость атаки). Это позволит делать, например, юниты-стены, которые просто находятся в первом ряду и защищают юнитов с дальней атакой. Или, например, паучье гнездо – юнит, который не атакует, а только призывает новых пауков в свою команду.
  • Реализовать механику применения эффекта на всю команду (на всю вражескую команду реализовано, осталось сделать на всю свою команду)
  • Подумать над реализацией эффектов, которые могут активироваться/деактивироваться при определенном параметре юнита
  • EffectAction добавить параметр buff: true/false указывающий на то, является ли это положительный или отрицательный эффект
  • Добавить CancelBuffAction и CancelDebuffAction – отменяющие все положительные или все отрицательные эффекты
  • Добавить способностям параметр актуальности, чтобы в случае одновременной активации двух способностей – использовалась наиболее актуальная
  • Сделать сайт-пример с боем
  • Сделать все аватары повернутыми вправо, а у правой команды через css разворачивать их по горизонтали, таким образом все юниты будут смотреть друг на друга
  • Добавить развертывание через Docker
  • Перевести все комментарии в коде на английский
  • Фиксированное количество сражающихся команд увеличить на любое, больше 2-х – это позволит делать не только бой 1 на 1 или команда на команду, а например бои с 5 участниками в формате каждый сам за себя
  • Доработать механику attack_speed/cast_speed в способностях, сейчас этот параметр никак не задействован - способность атакующие способности применяются один раз
  • Реализовать механику рефлекта урона
  • Реализовать механику, при которой юнита из вражеской команды можно на несколько ходов переманить в свою команду
  • Добавить особый тип способности, когда юнит может создавать копию себя, с % от своих характеристик, и с опцией, копировать или нет способности. В случае копирования способностей, копии также смогут вызывать свои копии
  • Добавить механику, при которой способностям в требованиях можно указывать не только наличие определенного типа оружия, но и наличие надетого щита
  • И многое другое

Характеристики юнитов

По этому списку можно оценить навороченность боевой механики.

  • id – id юнита
  • side – Сторона (правая или левая) за которую сражается юнит
  • row – 1 или 2 ряд в бою. Юниты ближнего боя располагаются в 1 ряду, юниты дальнего боя - во 2 ряду
  • already action – Этот параметр указывает, ходил ли юнит в текущем раунде
  • avatar – Путь к аватару юнита
  • name – Имя юнита
  • level – Уровень юнита
  • life – Текущий и максимальный запас здоровья юнита
  • mana – Текущий и максимальный запас маны юнита.
  • mental barrier – Если юнит имеет ментальный барьер, то урон вначале будет идти по мане, и только потом по здоровью
  • physical damage – Физический урон
  • fire damage – Урон стихией огня
  • water damage – Урон стихией вод
  • air damage – Урон стихией воздуха
  • earth damage – Урон стихией земли
  • life damage – Урон магией жизни
  • death damage – Урон магией смерти
  • physical resist – Сопротивление физическому урону
  • fire resist – Сопротивление урону огнем
  • water resist – Сопротивление урону водой
  • air resist – Сопротивление урону воздухом
  • earth resist – Сопротивление урону землей
  • life resist – Сопротивление урону магией жизни
  • death resist – Сопротивление урону магией смерти
  • physical max resist – Максимальное сопротивление физическому урону
  • fire max resist – Максимальное сопротивление урону огнем
  • water max resist – Максимальное сопротивление урону водой
  • air max resist – Максимальное сопротивление урону воздухом
  • earth max resist – Максимальное сопротивление урону землей
  • life max resist – Максимальное сопротивление урону магией жизни
  • death max resist – Максимальное сопротивление урону магией смерти
  • accuracy – Меткость, влияет на шанс попадания по противнику атаками
  • magic accuracy – Магическая меткость, влияет на шанс попадания по противнику заклинаниями
  • defense – Защита, влияет на шанс уклониться от удара противника
  • magic defense – Магическая защита, влияет на шанс уклониться от заклинания противника
  • critical chance – Шанс критического удара
  • critical multiplier – Сила критического удара
  • damage multiplier – Общий множитель наносимого урона
  • damage type – Тип удара: атака или заклинание
  • weapon type – Тип используемого оружия. Некоторые типы оружия могут при ударе наложить на цель дополнительный эффект, например: кинжалы могут вызвать кровотечение, а дробящее оружие оглушить врага
  • attack speed – Скорость атаки. Рассчитывается следующим образом: attack speed 1.3 означает, что юнит 100% нанесет один удар в своем ходе, и с 30% вероятностью еще один удар в этом же ходу. А attack speed 0.7 означает, что юнит с 70% вероятностью нанесет урон, а с 30% вероятностью ничего не сделает, а в чате отобразится сообщение «юнит готовится к атаке»
  • cast speed – Скорость создания заклинаний. Механика аналогична скорости атаки, только относится к типу удара заклинание
  • block – Шанс заблокировать атаку противника
  • magic block – Шанс заблокировать заклинание противника
  • block ignoring – Игнорирование блока. Некоторые типы оружия настолько тяжелые, что могут полностью игнорировать блок
  • dodge – Уклонение. Вероятность избежать удара или заклинания противника. Не зависит от меткости противника
  • concentration – Концентрация. Постепенно накапливается в бою и при полном заполнении позволяет использовать способности требующую концентрацию
  • cunning – Хитрость. С некоторой вероятностью позволяет активировать способности относящихся к типу хитрости. Базовое значение: 15
  • rage – Ярость. Постепенно накапливается в бою и при полном заполнении позволяет использовать способности требующие ярость
  • add concentration multiplier – Множитель получаемой концентрации
  • cunning multiplier – Множитель хитрости
  • add rage multiplier – Множитель получаемой ярости
  • race name – Название расы юнита
  • race color – Цвет расы юнита. Используется для цветового выделения имени юнита
  • race ability – Способности расы
  • class name – Название класса юнита
  • class abilities – Способности класса
  • global resist – Общий множитель получаемого урона
  • vampirism – Позволяет воровать часть нанесенного урона в здоровье
  • magic vampirism – Позволяет воровать часть нанесенного урона в ману

Всего 60 характеристик. Вместе с гибкой системой эффектов это позволит создавать практически неограниченное количество игровых механик.