Модуль командного, пошагового боя для браузерной игры. Так как вся игра пошаговая, и придерживается принципа ненапряженного геймплея, который можно в любой момент прекратить, а потом, когда будет удобно – продолжить, бои проходят в автоматическом режиме, а игроку лишь воспроизводится результат. Т.е. прямого управления над боем нет.
Текущий проект является переписыванием с нуля старой версии боевой системы, написанной в 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
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);
Alchemist во время боя призвал Fire Elemental в свою команду – по этому в статистике появился дополнительный юнит
Модуль написан на принципах 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 характеристик. Вместе с гибкой системой эффектов это позволит создавать практически неограниченное количество игровых механик.