Задача
Морской бой стал моей первой задачей на проекте.
Главная цель была простой: перенести оригинальную настольную игру на Cristalix. Игра должна была войти в состав отдельного режима, который так и называется - «Настолки».
Как режим собирался
Я решил вести разработку поэтапно. В целом этапы достаточно типичные для любой клиент-серверной игры:
- настроить проект;
- подключить библиотеки;
- реализовать основную логику;
- собрать обратную связь от команды тестирования;
- отполировать режим;
- довести до релиза.
Но с точки зрения кодовой базы всё оказалось интереснее. Важно помнить, что работа шла уже в контексте существующей игры, а не в пустом проекте.
Мне пришлось решать много задач:
- правильно отображать контент для игроков, соперников и наблюдателей: корабли не должны быть видны тем, кому их видеть нельзя;
- показать сломанные и повреждённые корабли так, чтобы это было понятно с точки зрения UX;
- сохранить правила оригинальной игры, не потеряв тонкости разработки под Minecraft;
- учитывать, что часть игроков может не успеть расставить корабли или сделать ход;
- проверять режим как со стороны активного игрока, так и в режиме наблюдателя.
Интересные технические решения
По моему травмирующему опыту, в подобных играх крайне трудно эмулировать действия соперника для отладки. Особенно когда нужно проверять не только механику, но и визуальное состояние с другой стороны.
Чтобы решить эту проблему, я почти сразу написал бота для DEV-режима настольной игры. Его действия были простыми: расставить корабли, стрелять в разное время и иногда использовать случайные снаряды.
Чем помогло?
Это решение помогло удобно проверить:
- покупаемые выстрелы с точки зрения соперника: бот чередовал разные эффекты выстрела;
- полный цикл стадий от ожидания до результата;
- отображение моделей соперника;
- состояние поля, когда партия идёт без постоянного ручного участия второго игрока.
Из всех решений это, пожалуй, сильнее всего упростило мне жизнь.
Что было сложнее всего
Самая заметная сложность - читаемость арены и управления.
Морской бой построен на точности: игрок должен понимать, какую клетку выбирает, на какую кнопку может нажать и что произошло после действия. Если визуальный эффект красивый, но мешает прочитать поле, он работает против игрового опыта и быстро отсекает онлайн.
Вторая сложность - состояние самого игрока и контента, который за ним закреплён. Это не обычный PvP, где игрок просто бегает по карте.
В нашем режиме его нужно аккуратно провести через ожидание, расстановку, бой, результат, выход и режим наблюдателя, доступный через лобби. Каждый переход может оставить лишний UI, неправильное состояние или случайно подсказать сопернику расположение нужных объектов.
Третья сложность - обратная связь. Выстрел должен ощущаться событием, но не перегружать контент. После действия игрок должен почти мгновенно понять результат. На мой взгляд, такие действия должны быстро закрепляться в механической памяти пользователя.
Полировка
Ближе к финалу работа сместилась в мелочи:
- улучшение боевых эффектов;
- результат матча;
- небольшие правки интерфейса под дизайн-систему;
- рефакторинг частей, которые стали слишком тесно связаны друг с другом. Привет классу на 1.5к строк кода :)
Это одна из самых приятных частей разработки: иногда несколько правок делают режим заметно привлекательнее для потенциального игрока.
Итог
Разработка дала мне много навыков:
- работа с внутренними библиотеками и изучение существующей кодовой базы;
- работа с клиентским состоянием и его оптимизацией;
- более точное понимание того, какие данные, кому и когда нужно отправлять;
- отладка и тестирование клиент-серверного игрового режима.
Скриншоты

