Игры (GameDev)

Sniper

Десктопный 3D-симулятор стрелкового тира на Unity 6, предназначенный для тренировок и проведения соревнований. Продукт объединяет три самостоятельных подсистемы: визуальный редактор сценариев (огневые рубежи, мишени, препятствия, окружение), игровой движок стрельбы с баллистикой на рейкастах и зачетной системой по зонам, а также режим до 5 участников одновременно на разделенном экране. По итогам упражнения автоматически формируется протокол результатов с выгрузкой в Excel - то есть инструменту нашлось применение не только как игре, но и как рабочему инструменту с отчетностью.
Unity C#

Задача

Требовалось создать законченный продукт, в котором непрограммист может самостоятельно собирать стрелковые упражнения любой сложности - без правки кода, без участия разработчика и без пересборки приложения. Ключевые требования:
  • Редактор уровней как в профессиональных движках: расстановка объектов мышью, перетаскивание, поворот, копирование, отмена действий, мини-карта.
  • Гибкая параметризация каждого элемента сцены: дистанция до мишени, время на рубеж, количество выстрелов, штрафы, звуковое сопровождение, поведение мишеней - десятки настроек, у каждого типа объекта свои.
  • Соревновательный режим на одном ПК с честным разделением экрана и полной изоляцией игроков друг от друга.
  • Разнородная физика мишеней: статичные, движущиеся, вращающиеся, биатлонные с падающими створками, сбиваемые.
  • Сохранение сценариев и статистики между сессиями, кроссплатформенный запуск, формирование отчетности для инструктора.
Сложность не в отдельных фичах, а в том, что все они должны работать в единой системе, где данные сценария - один источник правды и для редактора, и для игрового режима, и для отчета.

Решение

Реализован единый декларативный слой данных (Target / Param), который описывает любой объект сцены как набор типизированных параметров (range, rangefloat, bool, dropdown, категория). Этот слой стал ядром всей системы:
  • Редактор автоматически генерирует UI настроек из списка параметров объекта - добавление новой настройки не требует ни строчки UI-кода.
  • Игровой движок читает те же параметры в рантайме и применяет их к камере, таймерам, подсчету очков и звуку.
  • Модуль отчетов сериализует результаты по той же модели и выгружает их в форматированный Excel-документ.
Поверх этого ядра построены полноценный редактор сценариев (drag-and-drop, мультивыделение, привязка мишеней к объектам, undo/redo, copy/paste, авторасчет дистанций, 2D-мини-карта, превью вида от лица стрелка) и движок стрельбы (рейкаст-баллистика, зонный подсчет от центра мишени, декали от попаданий, переключение огневых рубежей по таймеру и лимиту выстрелов, штрафы за чужие мишени и промахи).

Архитектура и сложности

1. Data-driven конфигурация вместо хардкода.
Каждый объект несет List<Param> - самоописывающуюся схему настроек. Редакторский UI на UI Toolkit строится из этой схемы динамически (ListView с виртуализацией), а при множественном выделении вычисляется пересечение общих параметров, чтобы редактировать сразу несколько объектов. Это полностью развязало геймдизайн и программирование: новые упражнения создаются в визуальном редакторе, а не в коде.
2. Корректный undo/redo - задача глубокого копирования.
История изменений хранится в двух стеках снимков сцены (Stack<List<Target>>). Наивная реализация ломается из-за ссылочного аллиасинга: снимки начинают ссылаться на одни и те же объекты, и откат портит текущее состояние. Проблема решена конструкторами глубокого копирования на всех уровнях модели (TVector, Param, Target.Clone()) - каждый снимок полностью независим, что делает откат/повтор предсказуемым даже после сложных пакетных операций.
3. Честный сплит-скрин с полной изоляцией игроков.
Самая нетривиальная подсистема. Для каждого из участников динамически создается отдельная камера, своя область вьюпорта и индивидуальный слой рендеринга (Player{i}Layer) с culling mask - так каждый стрелок видит только свои мишени и свои следы от пуль, хотя сцена общая. Дополнительно вводится математическая коррекция FOV под изменившееся соотношение сторон узкого вьюпорта (atan(tan(fov/2)/width)*2), иначе при разделении экрана картинка визуально сплющивается. Поддержаны два режима - параллельный (соревнование) и последовательный (поочередный по игрокам).
4. Гетерогенная физика мишеней под общим интерфейсом.
Вращающиеся мишени удерживают минимальную угловую скорость через подкрутку момента в FixedUpdate и получают импульс при попадании; движущиеся ходят по PingPong с фазовым смещением; биатлонные закрывают створки корутиной по попаданию; сбиваемые переключаются в некинематические и получают импульс в точку удара. Все типы конфигурируются через тот же параметрический слой.
5. Зонный подсчет и устойчивые декали.
Очки считаются по нормализованной дистанции от центра коллайдера мишени к точке попадания (6 зон, 10-5), что не зависит от масштаба мишени. Декали выносятся вдоль нормали поверхности на микро-смещение для борьбы с z-fighting и приписываются к слою конкретного игрока.
6. Кроссплатформенный бутстрап данных и персистентность.
При первом запуске эталонные данные копируются из StreamingAssets в persistentDataPath, причем на Android/iOS - через UnityWebRequest (упакованные ассеты недоступны как файлы), а на десктопе - прямым чтением. Сценарии и статистика хранятся в бинарном формате, рекорды игроков обновляются по лучшему результату.
7. Отчетность производственного качества.
По завершении упражнения формируется многосекционный Excel-протокол (итоги, разбивка по рубежам, по выстрелам) средствами EPPlus с автошириной колонок и автоматическим открытием файла - готовый документ для инструктора.
Дополнительно: редактируемая раскладка управления (ремап клавиш в PlayerPrefs), валидация лицензии по HMAC-SHA256, рантайм-смена типа местности (грунт/снег/лес/помещение с подменой текстуры террейна и активацией систем частиц), а также редакторский инструмент процедурной генерации леса - расстановка 1000+ деревьев рейкастом по рельефу за один проход.

Результат

  • Собран законченный продукт из трех интегрированных подсистем (редактор, игровой движок, отчетность), работающих поверх единой модели данных.
  • Время сборки нового упражнения сократилось с ручной работы программиста до нескольких минут в визуальном редакторе - создание контента полностью перешло к пользователю.
  • Поддержано до 5 участников одновременно на разделенном экране с полной визуальной изоляцией и без искажений картинки.
  • Реализовано 5+ типов объектов сцены и 4 типа местности, переключаемых в рантайме; 6 зачетных зон с масштабонезависимым подсчетом.
  • Полноценный редактор уровня профессиональных инструментов: undo/redo, copy/paste, мультивыделение, привязки, мини-карта, превью от лица стрелка.
  • Автоматическая выгрузка протоколов в Excel превратила симулятор в рабочий инструмент с отчетностью, а не только в игру.
  • Архитектура «один источник правды» обеспечила расширяемость без затрат: новый параметр или тип мишени добавляется в модель и сразу подхватывается редактором, движком и отчетом.

Стек

Движок: Unity 6 (6000.0.40f1), C#
UI: Unity UI Toolkit (UXML/USS, динамические ListView, кастомные тултипы и диалоги)
Графика и сцена: Unity Terrain (рантайм-подмена слоев), Post-processing, Cinemachine, системы частиц, glTF (UnityGLTF)
Физика: Unity Physics - Raycast, OverlapBox, Rigidbody, моменты/импульсы для мишеней
Данные: бинарная сериализация (BinaryFormatter), StreamingAssets-persistentData бутстрап, конструкторы глубокого копирования
Интеграции: EPPlus (экспорт в Excel), Newtonsoft.Json, UnityWebRequest/HttpClient для сетевого слоя
Прочее: HMAC-SHA256 (лицензирование), Burst, кастомные Editor-инструменты (генератор леса), ремап управления через PlayerPrefs 
Сюда Туда