# TECHDOC ## Назначение документа Этот файл описывает технические решения проекта `Danro` на уровне runtime-логики, архитектуры и эксплуатационных ограничений. В отличие от `README.md`, здесь собраны детали, важные для разработки, сопровождения и дальнейшего расширения проекта. ## 1. Общая техническая картина Проект представляет собой 2D-платформер на Unity с двумя режимами эксплуатации: - обычный игровой режим с клавиатурным управлением; - аркадный режим с внешним COM-устройством, кредитами, балансом, световыми эффектами и опциональной призовой механикой. Архитектурно игра построена вокруг одного постоянного `GameManager`, набора глобальных сервисов из prefab `Globals`, сценовой компонентной логики и отдельной подсистемы настроек. ## 2. Стек и зависимости ### Движок и язык - `Unity 6000.3.8f1` - `C#` ### Основные Unity-пакеты По `Packages/manifest.json` проект использует: - `com.unity.inputsystem` - `com.unity.ugui` - `com.unity.cinemachine` - `com.unity.render-pipelines.universal` - `com.unity.visualeffectgraph` - `com.unity.feature.2d` - `com.unity.test-framework` Дополнительно подключен `NuGetForUnity`, а также `com.unity.ai.inference`, но ключевой gameplay-код завязан в первую очередь на стандартные Unity-подсистемы. ## 3. Сцены и структура запуска ### Активные сцены в Build Settings Сейчас включены: - `Assets/Scenes/MainMenu.unity` - `Assets/Scenes/Level UI.unity` - `Assets/Scenes/Levels/1-1.unity` - `Assets/Scenes/Levels/1-2.unity` - `Assets/Scenes/Levels/1-3.unity` Это означает, что фактическая игровая цепочка на текущий момент состоит из трех игровых уровней. Старые сцены в `Assets/Scenes/Levels/Old` в билд не включены. ### Принцип загрузки `GameManager.LoadScene()` использует такую схему: - основная сцена загружается как active scene; - при `useUI = true` отдельно догружается `Level UI` в additive-режиме; - для сцен без игрового UI (например, меню) игрок не спавнится. ### Схема именования уровней Переход между уровнями завязан на шаблон имени сцены `world-stage`, например: - `1-1` - `1-2` - `1-3` `GameManager.NextLevel()` инкрементирует `Stage`, а при переполнении переходит к следующему `World`. Проверка наличия следующей сцены выполняется через `SceneManager.sceneCountInBuildSettings`. Если следующей сцены нет, игра считается завершенной. Это важное ограничение: любое изменение схемы названий уровней потребует правки логики переходов. ## 4. Точка входа и жизненный цикл ### `GameManager` Главный runtime-координатор находится в `Assets/Scripts/Managers/GameManager.cs`. Ключевые особенности: - создается автоматически через `RuntimeInitializeOnLoadMethod`; - живет между сценами через `DontDestroyOnLoad`; - хранит глобальное состояние игровой сессии; - поднимает базовые подсистемы при старте приложения. ### Что инициализирует `GameManager` В `Awake()` он: - создает и настраивает `CompositeLogger` с файловым логгером в `game.log`; - создает `AudioManager`; - загружает `Resources/Prefabs/Global/Globals`; - получает ссылки на `SettingsManager`, `PaymentManager`, `BalanceManager`, `ComSystemManager`; - создает `InactivityManager`; - подцепляет `LightController` из COM-подсистемы; - подписывается на события настроек и оплаты. ### Runtime-события `GameManager` `GameManager` публикует верхнеуровневые события: - `PauseStateChanged` - `PlayerSpawned` - `CoinsChanged` - `MaxLivesChanged` - `LivesChanged` - `GameOverEvent` - `GameWonEvent` Эти события используются UI-слоем и другими системами для синхронизации без жесткой связности. ## 5. Глобальные сервисы ### `Globals` prefab Проект зависит от prefab `Resources/Prefabs/Global/Globals`. Это контейнер долгоживущих компонентов, которые должны быть доступны независимо от текущей сцены. Если структура этого prefab изменится, инициализация игры может сломаться, потому что `GameManager` ожидает получить из него конкретные компоненты. ### `AudioManager` Отвечает за: - запуск и паузу музыки; - управление SFX; - реакцию на глобальную паузу. `GameManager.SetPause()` меняет `Time.timeScale` и вызывает `Audio.SmoothPauseMusic(pause)`. ### `InactivityManager` Используется для аркадного режима: - включается при старте игры; - выключается при победе или поражении; - предназначен для реакции на бездействие игрока и возврата в безопасное состояние. ### Логирование Используется `CompositeLogger`, который пишет в `game.log` в корне проекта. Это отдельная эксплуатационная подсистема, полезная при отладке инсталляции и поведения железа. ## 6. Игровой цикл ### Старт новой игры `GameManager.NewGame()` выполняет: 1. Проверку режима `free game`. 2. Проверку достаточности баланса для старта. 3. Расчет числа стартовых жизней. 4. Списание текущего баланса. 5. Сброс монет и статистики. 6. Включение игрового светового режима. 7. Включение контроля бездействия. 8. Загрузку уровня `1-1`. ### Расчет жизней Текущая логика такая: - первая оплата дает `StartingLives`; - каждая дополнительная оплата добавляет `LivesIncrement`; - итоговое число жизней рассчитывается от накопленного баланса и стоимости импульса оплаты. Таким образом, жизни завязаны не только на gameplay, но и на экономику аркадной установки. ### Поражение При поражении: - вычисляется полное время сессии; - отключается проверка бездействия; - включается специальный световой сценарий; - вызывается `GameOverEvent`. Дальше UI показывает `LoseBannerController`, где игрок может: - продолжить игру, если хватает баланса; - дождаться завершения таймера и вернуться в меню. ### Победа При победе: - вычисляется время сессии; - отключается контроль бездействия; - запускается финальный световой режим; - вызывается `GameWonEvent`. Победный экран показывает итоговое время и, при наличии данных, QR-коды призовой системы. ## 7. Спавн, смерть и чекпоинты ### Первый спавн После загрузки игровой сцены `GameManager` ищет `PlayerSpawn`: - если точка найдена, берет ее позицию и направление; - если нет, использует запасную позицию `(0, 1.3, 0)`. Игрок создается из prefab `Resources/Prefabs/Player_New`, если ссылка не задана в инспекторе. ### Респавн `GameManager.RespawnPlayer()`: - уменьшает число жизней; - при нуле жизней завершает сессию; - ищет активный чекпоинт через `CheckpointSystem`; - телепортирует игрока или создает его заново; - сбрасывает скорость `Rigidbody2D`; - восстанавливает здоровье через `Health.ResetHealth()`. ### Что не сбрасывается В текущей реализации при респавне: - уровень не перезагружается; - монеты не обнуляются. Это заметное отличие от старой модели `ResetLevel()`, которая помечена как устаревшая. ## 8. Игровые сущности и сцена ### Основные gameplay-компоненты Ключевая сценовая логика лежит в `Assets/Scripts/Behaviour` и `Assets/Scripts/Entities`. Реализованы: - враги (`EnemyController`); - игрок (`PlayerController`); - здоровье (`Health`); - завершение уровня (`LevelFinish`); - система монет и статистики (`ScoreSystem`); - сообщения и сценарные последовательности (`MessageController`, `Sequencer`); - снаряды игрока и врагов; - VFX-пулы и окружение. ### Интерактивные объекты В `Assets/Scripts/Entities/Props` и подкаталогах находятся: - монеты и другие коллектаблы; - ловушки; - рычаги; - прозрачный передний план; - платформы разных типов. Поддерживаются: - `MovingPlatform` - `ShiftingPlatform` - `TrajectoryPlatform` - `TriggeringPlatform` - `HidingTriggeringPlatform` - `VanishingPlatform` Это означает, что уровень собирается из компонентов с локальной логикой, а не из одного большого контроллера. ## 9. Система ввода ### Абстракция ввода Ввод изолирован в `Assets/Scripts/Controls`. Центральная идея: - игровой код не должен знать, пришел сигнал с клавиатуры или с внешней платы; - источник ввода скрыт за фасадом `In.cs`. ### Поддерживаемые источники В проекте присутствуют: - `KeyboardInput` - `COMInput` - адаптер `ComInputToInputSystemAdapter` для интеграции с `Unity Input System` Это дает два параллельных слоя совместимости: - gameplay-код может работать с абстракцией собственного ввода; - UI и часть действий могут работать через стандартные `InputActionReference`. ### COM-подсистема В `Assets/Scripts/Controls/Inputs/ComSystem` собраны: - подключение COM-устройств; - handshake и маршрутизация; - работа с кредитами; - управление подсветкой; - поддержка призовой стойки. Ключевые классы: - `ComSystemManager` - `ComHub` - `ComDeviceClient` - `LightController` - `PrizeStandController` - `PrizeSystem` Это один из самых чувствительных участков проекта: он завязан на внешнее железо и требует особенно аккуратных изменений. ## 10. Платежная модель, кредиты и баланс ### `PaymentManager` `PaymentManager` хранит и синхронизирует число кредитов. Он: - реагирует на события COM-подсистемы; - умеет добавлять кредиты вручную для тестирования; - поддерживает free play; - уведомляет другие системы через `UnityEvent`. Ключевые события: - `OnCreditsChanged` - `OnCreditAdded` - `OnCreditRemoved` ### `BalanceManager` `BalanceManager` является более высоким уровнем экономики. Он: - хранит числовой баланс; - начисляет его за импульсы оплаты; - списывает баланс за старт и продолжение; - кеширует значения из настроек; - синхронизирует количество кредитов с COM-системой. Важный нюанс: в текущем `GameManager.NewGame()` при старте списывается весь накопленный баланс, а не только фиксированная стоимость старта. Это сознательно влияет на число выдаваемых жизней и на модель одной игровой сессии. ### Free Play Если в настройках включен `payment.freeGame`: - старт игры доступен без баланса; - продолжение доступно без списаний; - часть UI-ограничений отключается. ## 11. Настройки ### Новая система настроек Подсистема находится в `Assets/Scripts/Settings`. Она состоит из: - `SettingsDatabase` - схема настроек; - `SettingsManager` - загрузка, хранение и события; - `SettingsApplier` - применение значений к runtime; - `SettingsUIGenerator` и binder-классов - построение UI. ### Типы настроек В коде поддерживаются: - `Bool` - `Int` - `Float` - `String` - `Button` - `OptionPicker` Это позволяет хранить не только значения, но и описывать кнопочные действия и enum-подобные селекторы в одной общей схеме. ### Хранение и валидация Система: - использует схему из `SettingsDatabase`; - валидирует значения через `Sanitize`; - приводит значения к диапазонам; - сохраняет настройки в JSON в `persistentDataPath`. ### Практическое применение По текущему коду настройки влияют как минимум на: - стартовые жизни; - дополнительные жизни; - free play; - стоимость импульса оплаты; - стоимость старта; - стоимость продолжения; - номер поддержки; - описание суперприза; - номер телефона для призовой системы. Это уже не декоративный UI, а реально рабочая конфигурационная подсистема. ## 12. Пользовательский интерфейс ### Основные UI-экраны В `Assets/Scripts/UI` реализованы: - `MainMenu` - `PauseMenu` - `SettingsUI` - `LevelSelectModal` - `GameEndUIController` - `WinBannerController` - `LoseBannerController` ### Что делает UI На текущий момент UI умеет: - блокировать старт игры при недостаточном балансе; - показывать платежные подсказки; - открывать настройки; - собирать список уровней из `Build Settings`; - показывать время сессии на экранах победы/поражения; - разрешать продолжение только при достаточном балансе; - динамически создавать QR-коды на победном экране. ### Статистика Есть два отдельных режима статистики: - `StatsWindowUIController` - простой просмотр; - `AdminStatsWindowUIController` - просмотр плюс сброс обнуляемых счетчиков. Статистика хранится через `PlayerPrefs`. ## 13. Призовая система и QR-коды ### `PrizeSystemManager` Эта подсистема: - читает параметры из настроек; - готовит номер телефона; - генерирует QR-коды заранее; - может инициировать выдачу приза через hopper. ### Отображение QR Актуальная логика показа QR-кодов перенесена в `WinBannerController`: - при победе он получает `Texture2D[]` из `PrizeSystemManager`; - создает `Image`-элементы динамически; - очищает их при закрытии окна. `QRCodeUIController` помечен как устаревший и использовать его больше не нужно. ## 14. Система ресурсов и зависимости от `Resources` Проект по-прежнему опирается на `Resources.Load` для критичных runtime-объектов: - `Prefabs/Global/Globals` - `Prefabs/Player_New` - `Audio/Master` Это удобно для ранней инициализации, но создает ограничения: - переименование ассетов требует обновления строковых путей; - ошибки проявляются только в runtime; - часть связности остается строковой, а не ссылочной. ## 15. Ключевые технические риски ### 1. Жесткая зависимость от `Globals` Если из prefab убрать или переименовать нужный компонент, `GameManager` потеряет доступ к базовым сервисам. ### 2. Завязка на соглашения по именам сцен Переход между уровнями работает только для формата `world-stage`. ### 3. Связь с внешним железом Любые изменения вокруг COM-контуров, кредита, подсветки и призовой стойки нужно тестировать отдельно от обычного desktop-режима. ### 4. Смешение аркадной экономики и gameplay Количество жизней напрямую зависит от баланса и стоимости импульсов, поэтому изменения в экономике автоматически меняют сложность игры. ### 5. Частичное хранение данных в `PlayerPrefs` Баланс, статистика и часть служебного состояния могут сохраняться между сессиями. Это нужно учитывать при тестах и при подготовке демо-сборок. ## 16. Практические правила для изменений При изменениях в проекте стоит проверять: 1. Загружается ли `Globals` и поднимаются ли `SettingsManager`, `BalanceManager`, `PaymentManager`. 2. Не сломалась ли загрузка `MainMenu`, `Level UI` и уровней `1-1`..`1-3`. 3. Работает ли старт новой игры при обычном и `free play` режимах. 4. Корректно ли доступны респавн, чекпоинты и завершение уровня. 5. Не нарушился ли сценарий продолжения после поражения. 6. Не перестали ли отображаться QR-коды на победе. 7. Не нарушилась ли совместимость клавиатуры и COM-ввода. ## 17. Карта основных директорий - `Assets/Scripts/Managers` - глобальные менеджеры и orchestration. - `Assets/Scripts/Settings` - схема, хранение и UI настроек. - `Assets/Scripts/Controls` - ввод и интеграция с COM-оборудованием. - `Assets/Scripts/Behaviour` - игровая логика на сценах. - `Assets/Scripts/Entities` - интерактивные сущности и платформы. - `Assets/Scripts/UI` - меню, модальные окна, баннеры и служебные панели. - `Assets/Scripts/Utilities` - логирование, утилиты и вспомогательный код. ## 18. Итог Текущее техническое решение проекта можно описать так: - gameplay сделан как набор независимых Unity-компонентов; - orchestration централизован в `GameManager`; - аркадные функции вынесены в отдельные менеджеры; - конфигурация постепенно переводится в самостоятельную систему настроек; - проект уже ориентирован не только на домашний запуск, но и на работу в аппаратной инсталляции. Если `README.md` отвечает на вопрос "что умеет игра", то этот документ отвечает на вопрос "как именно это собрано и где это менять".