Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
- Рефакторинг системы подсветки: вместо длительности в секундах теперь используется количество циклов (float). Добавлена таблица длительности циклов эффектов `LightCycleDurations` для пересчёта циклов в секунды. Префикс команд подсветки изменён с `85` на `86`. - `LightSequence`: добавлены `Pause()` / `Resume()` с запоминанием текущего шага последовательности; возобновление продолжает с сохранённой позиции. - `LightController`: добавлены `PauseAll()` / `ResumeAll()` для приостановки и восстановления подсветки и мигания шляпы при отключении/переподключении платы. Свойства `IsSequencePaused`, `IsBlinkPaused`. - `ComDeviceClient`: после успешной авторизации отправляются команды `890003` и `8600`. Добавлен запрос MAC-адреса через команду `06` (ответ — 12 hex-символов без префикса). Новое событие `ConnectionLost` при начале KeepAlive-реконнекта. - `ComHub`: очередь `_disconnectedQueue` с типом `DeviceDisconnectMessage` (DeviceId + Role + Mac) — сохраняет идентификатор устройства до его удаления из словаря. Подписка на `ConnectionLost`. Добавлен `GetDeviceMac()`. - `ComSystemManager`: при инициализации, если плата не обнаружена, подсветка сразу ставится на паузу. При отвале дефолтного устройства — `PauseAll()`, при переподключении — сравнение по MAC и роли через `IsSameDevice()`: та же плата → `ResumeAll()`, другая → `Blink()` с нуля. Добавлены событие `OnDeviceDisconnected` и метод `GetDeviceMac()`. - `COMInput`: при событии `OnDeviceDisconnected` сбрасываются все состояния кнопок через `ResetAllButtons()`, генерируя `buttonUp` для зажатых кнопок. Устраняет баг залипания управления после переподключения платы. - `GameManager`: расширена последовательность световых эффектов в меню (добавлены `DiagonalWave3`, `WaveUp`, `OrangeWave`); вызовы `SetLight` для game over/won переведены на float-циклы. - Обновлены `ARCHITECTURE.md` и `README.md`: переписана документация на актуальную структуру проекта и текущие возможности игры.
521 lines
23 KiB
Markdown
521 lines
23 KiB
Markdown
# 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` отвечает на вопрос "что умеет игра", то этот документ отвечает на вопрос "как именно это собрано и где это менять".
|