770 lines
23 KiB
Markdown
770 lines
23 KiB
Markdown
# Race Fields Architecture
|
||
|
||
Этот документ фиксирует текущую архитектуру проекта по фактическим сценам, prefab'ам и скриптам.
|
||
|
||
Главная цель: видеть не просто граф зависимостей, а слои проекта, ответственность каждого блока и места, где архитектура сейчас хрупкая.
|
||
|
||
## Как Читать Диаграммы
|
||
|
||
Главная диаграмма читается сверху вниз:
|
||
|
||
1. `Entry / Scene Layer` - откуда стартует игра.
|
||
2. `Scene Bootstrap Layer` - кто собирает игровую сцену.
|
||
3. `Runtime Entity Layer` - реальные игровые объекты.
|
||
4. `Subsystem Layer` - системы, которые обслуживают player/enemies.
|
||
5. `Asset / Data Layer` - prefab'ы, sprites, render textures, static state.
|
||
|
||
Связи на главной диаграмме показывают только важные runtime-зависимости. Детальные связи вынесены ниже в отдельные диаграммы.
|
||
|
||
## Current Architecture Overview
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph L1["ENTRY / SCENE LAYER"]
|
||
SelectionScene["Selection Scene"]
|
||
DemoScene["Demo Scene"]
|
||
end
|
||
|
||
subgraph L2["SCENE BOOTSTRAP LAYER"]
|
||
SelectionMenu["SelectionMenuController\nвыбор машины / режима / карты"]
|
||
SelectedVehicleSpawner["SelectedVehicleSpawner\nсоздает player и биндует сцену"]
|
||
end
|
||
|
||
subgraph L3["RUNTIME ENTITY LAYER"]
|
||
Player["Player Vehicle Instance\nBuggy prefab clone"]
|
||
Harvester["Harvester Enemy\nHarvester prefab instance"]
|
||
Terrain["Terrain\nTerrainCollider"]
|
||
end
|
||
|
||
subgraph L4["PLAYER SUBSYSTEMS"]
|
||
VehicleControl["ArcadeBuggyController\ninput + physics + wheels + sound + effects"]
|
||
WheelRig["WheelColliders / WheelVisuals"]
|
||
DamageCore["VehicleDamageController\nмодули здоровья"]
|
||
ImpactDamage["VehicleImpactDamageReceiver\nterrain / landing / collision damage"]
|
||
DamageHitboxes["DamageHitbox\nзоны урона"]
|
||
end
|
||
|
||
subgraph L5["SCENE SUBSYSTEMS"]
|
||
FollowCamera["BuggyFollowCamera"]
|
||
RearViewCamera["RearViewMirrorCamera"]
|
||
DamageHUD["VehicleDamageHud"]
|
||
HarvesterAI["HarvesterChaseController"]
|
||
BladeDamage["BladeDamageSource"]
|
||
BladeVisual["HarvesterBladeSpinner"]
|
||
end
|
||
|
||
subgraph L6["ASSET / DATA LAYER"]
|
||
GameSelectionState["GameSelectionState static\nвыбор между сценами"]
|
||
VehiclePrefabs["Player Vehicle Prefabs\nBuggy / Buggy_1 / Buggy_Player"]
|
||
HarvesterPrefab["HarvesterEnemy Prefab"]
|
||
DamageUISprites["MDP_Buggy_1.psb\nHUD base + overlay sprites"]
|
||
RearViewRT["RearViewMirror RenderTexture"]
|
||
end
|
||
|
||
SelectionScene --> SelectionMenu
|
||
SelectionMenu --> GameSelectionState
|
||
SelectionMenu --> DemoScene
|
||
|
||
DemoScene --> SelectedVehicleSpawner
|
||
DemoScene --> Terrain
|
||
DemoScene --> Harvester
|
||
|
||
SelectedVehicleSpawner --> GameSelectionState
|
||
SelectedVehicleSpawner --> VehiclePrefabs
|
||
SelectedVehicleSpawner --> Player
|
||
SelectedVehicleSpawner --> FollowCamera
|
||
SelectedVehicleSpawner --> RearViewCamera
|
||
SelectedVehicleSpawner --> DamageHUD
|
||
|
||
VehiclePrefabs --> Player
|
||
Player --> VehicleControl
|
||
Player --> WheelRig
|
||
Player --> DamageCore
|
||
Player --> ImpactDamage
|
||
Player --> DamageHitboxes
|
||
|
||
VehicleControl --> WheelRig
|
||
ImpactDamage --> DamageCore
|
||
ImpactDamage --> WheelRig
|
||
DamageHitboxes --> DamageCore
|
||
DamageCore --> DamageHUD
|
||
DamageUISprites --> DamageHUD
|
||
|
||
HarvesterPrefab --> Harvester
|
||
Harvester --> HarvesterAI
|
||
Harvester --> BladeVisual
|
||
Harvester --> BladeDamage
|
||
HarvesterAI --> Player
|
||
BladeDamage --> DamageHitboxes
|
||
|
||
FollowCamera --> Player
|
||
RearViewCamera --> Player
|
||
RearViewCamera --> RearViewRT
|
||
```
|
||
|
||
## Main Runtime Flow
|
||
|
||
Это основной путь от выбора машины до gameplay.
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant PlayerInput as Player Input
|
||
participant SelectionMenu as SelectionMenuController
|
||
participant SelectionState as GameSelectionState
|
||
participant UnityScene as Unity SceneManager
|
||
participant DemoScene as Demo Scene
|
||
participant Spawner as SelectedVehicleSpawner
|
||
participant Vehicle as Player Vehicle
|
||
participant Camera as Cameras
|
||
participant HUD as VehicleDamageHud
|
||
participant Enemy as Harvester
|
||
|
||
PlayerInput->>SelectionMenu: left/right/space
|
||
SelectionMenu->>SelectionMenu: choose vehicle, mode, map
|
||
SelectionMenu->>SelectionState: SetSelection(vehiclePrefab, mode, sceneName)
|
||
SelectionMenu->>UnityScene: LoadScene(sceneName)
|
||
UnityScene->>DemoScene: load gameplay scene
|
||
DemoScene->>Spawner: Start()
|
||
Spawner->>SelectionState: read selected prefab
|
||
Spawner->>Vehicle: Instantiate(prefab at spawn point)
|
||
Spawner->>Camera: SetTarget(vehicle)
|
||
Spawner->>HUD: Bind(vehicle.VehicleDamageController)
|
||
Enemy->>Vehicle: auto find / chase target
|
||
```
|
||
|
||
Проблема этого flow:
|
||
|
||
- `GameSelectionState` - static.
|
||
- `SelectedVehicleSpawner` уже не просто spawner, а bootstrap сцены.
|
||
- Камеры, HUD и враг частично умеют искать player сами, частично получают его от spawner.
|
||
|
||
## Scene Composition
|
||
|
||
### Selection Scene
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
subgraph SelectionScene["Selection Scene"]
|
||
MainCamera["Main Camera"]
|
||
Light["Directional Light"]
|
||
PreviewRoot["VehiclePreviewRoot"]
|
||
PreviewFloor["Preview Floor"]
|
||
Canvas["Selection Canvas"]
|
||
EventSystem["EventSystem\nInputSystemUIInputModule"]
|
||
Menu["SelectionMenuController"]
|
||
end
|
||
|
||
Menu --> PreviewRoot
|
||
Menu --> Canvas
|
||
Menu -->|"spawns preview prefab"| PreviewVehicle["Runtime Preview Vehicle"]
|
||
Menu -->|"writes selected data"| GameSelectionState["GameSelectionState"]
|
||
Menu -->|"loads selected map"| SceneManager["SceneManager.LoadScene"]
|
||
```
|
||
|
||
Что важно:
|
||
|
||
- Preview использует настоящий gameplay prefab.
|
||
- После spawn preview отключаются gameplay-компоненты.
|
||
- Это быстро, но preview и gameplay связаны слишком плотно.
|
||
|
||
### Demo Scene
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
subgraph DemoScene["Demo Scene"]
|
||
Terrain["Terrain + TerrainCollider"]
|
||
ExistingBuggy["Buggy_1 scene instance\nтестовый объект"]
|
||
SpawnPoint["Selected Vehicle Spawn Point"]
|
||
Spawner["SelectedVehicleSpawner"]
|
||
FollowCamera["Buggy_ThirdPersonCamera"]
|
||
RearCamera["RearViewMirrorCamera"]
|
||
HudCanvas["Gameplay HUD Canvas"]
|
||
Harvester["Harvester"]
|
||
MachineGun["MachineGun"]
|
||
end
|
||
|
||
Spawner --> SpawnPoint
|
||
Spawner -->|"destroys existing ArcadeBuggyController if enabled"| ExistingBuggy
|
||
Spawner -->|"spawns selected prefab"| SpawnedPlayer["Buggy(Clone)"]
|
||
Spawner --> FollowCamera
|
||
Spawner --> RearCamera
|
||
Spawner --> HudCanvas
|
||
Harvester -->|"chases"| SpawnedPlayer
|
||
```
|
||
|
||
Что важно:
|
||
|
||
- В сцене есть и тестовая машина `Buggy_1`, и spawner.
|
||
- Spawner может удалить старую машину и создать выбранную.
|
||
- Для финальной архитектуры лучше оставить один путь создания player.
|
||
|
||
## Vehicle Prefab Composition
|
||
|
||
Все три player-prefab'а сейчас должны иметь одну и ту же структуру:
|
||
|
||
- `Buggy.prefab`
|
||
- `Buggy_1.prefab`
|
||
- `Buggy_Player.prefab`
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph VehicleRoot["PLAYER VEHICLE PREFAB ROOT"]
|
||
Transform["Transform"]
|
||
Rigidbody["Rigidbody"]
|
||
BoxCollider["BoxCollider"]
|
||
end
|
||
|
||
subgraph Control["CONTROL / PHYSICS"]
|
||
ArcadeBuggyController["ArcadeBuggyController"]
|
||
BuggyWheelSetup["BuggyWheelSetup"]
|
||
WheelColliders["WheelCollider_FL / FR / RL / RR"]
|
||
WheelVisuals["Wheel visuals"]
|
||
VehicleAudio["EngineSound / TireScreechSound"]
|
||
VehicleVFX["Smoke / Skid Trails"]
|
||
end
|
||
|
||
subgraph Damage["DAMAGE"]
|
||
VehicleDamageController["VehicleDamageController"]
|
||
VehicleImpactDamageReceiver["VehicleImpactDamageReceiver"]
|
||
DamageModules["DamageModules"]
|
||
DamageHitboxes["DamageHitboxes"]
|
||
end
|
||
|
||
subgraph Modules["MODULES"]
|
||
Body["Body Module"]
|
||
Engine["Engine Module"]
|
||
FL["FrontLeftWheel Module"]
|
||
FR["FrontRightWheel Module"]
|
||
RL["RearLeftWheel Module"]
|
||
RR["RearRightWheel Module"]
|
||
end
|
||
|
||
subgraph Hitboxes["HITBOXES"]
|
||
BodyBox["Body Hitbox"]
|
||
EngineBox["Engine Hitbox"]
|
||
FLBox["FrontLeftWheel Hitbox"]
|
||
FRBox["FrontRightWheel Hitbox"]
|
||
RLBox["RearLeftWheel Hitbox"]
|
||
RRBox["RearRightWheel Hitbox"]
|
||
end
|
||
|
||
VehicleRoot --> Control
|
||
VehicleRoot --> Damage
|
||
|
||
ArcadeBuggyController --> WheelColliders
|
||
ArcadeBuggyController --> WheelVisuals
|
||
ArcadeBuggyController --> VehicleAudio
|
||
ArcadeBuggyController --> VehicleVFX
|
||
BuggyWheelSetup --> WheelColliders
|
||
|
||
VehicleDamageController --> DamageModules
|
||
DamageModules --> Modules
|
||
DamageHitboxes --> Hitboxes
|
||
DamageHitboxes --> VehicleDamageController
|
||
VehicleImpactDamageReceiver --> VehicleDamageController
|
||
VehicleImpactDamageReceiver --> ArcadeBuggyController
|
||
|
||
FL -->|"destroyed"| ArcadeBuggyController
|
||
FR -->|"destroyed"| ArcadeBuggyController
|
||
RL -->|"destroyed"| ArcadeBuggyController
|
||
RR -->|"destroyed"| ArcadeBuggyController
|
||
```
|
||
|
||
Ключевая проблема:
|
||
|
||
`Damage` зависит от `ArcadeBuggyController`. Это работает только пока все машины устроены как багги. Для нормальной архитектуры нужен wheel adapter/interface.
|
||
|
||
## Damage Architecture
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph DamageInput["DAMAGE INPUT SOURCES"]
|
||
BladeDamageSource["BladeDamageSource\ntrigger damage"]
|
||
ImpactReceiver["VehicleImpactDamageReceiver\nterrain / landing / collision"]
|
||
FutureWeapons["Future Weapons\nbullets / mines / rockets"]
|
||
end
|
||
|
||
subgraph Routing["DAMAGE ROUTING"]
|
||
DamageHitbox["DamageHitbox\nexternal hit -> module type"]
|
||
DamageHit["DamageHit\namount / type / point / direction / source"]
|
||
end
|
||
|
||
subgraph State["DAMAGE STATE"]
|
||
DamageController["VehicleDamageController"]
|
||
ModuleBase["DamageableVehicleModule"]
|
||
WheelModule["VehicleWheelDamageModule"]
|
||
end
|
||
|
||
subgraph Output["DAMAGE OUTPUT"]
|
||
Hud["VehicleDamageHud"]
|
||
WheelDetach["Wheel detach\nvisual + collider + rigidbody"]
|
||
ControllerEffect["ArcadeBuggyController.SetWheelEnabled(false)"]
|
||
end
|
||
|
||
BladeDamageSource --> DamageHitbox
|
||
FutureWeapons --> DamageHitbox
|
||
DamageHitbox --> DamageHit
|
||
ImpactReceiver --> DamageHit
|
||
DamageHit --> DamageController
|
||
DamageController --> ModuleBase
|
||
ModuleBase --> WheelModule
|
||
DamageController --> Hud
|
||
WheelModule --> WheelDetach
|
||
WheelModule --> ControllerEffect
|
||
```
|
||
|
||
### Damage Rules Сейчас
|
||
|
||
External damage:
|
||
|
||
- `BladeDamageSource` ищет `DamageHitbox`.
|
||
- `DamageHitbox` знает `VehicleModuleType`.
|
||
- `VehicleDamageController` передает damage в конкретный module.
|
||
|
||
Terrain / impact damage:
|
||
|
||
- `VehicleImpactDamageReceiver` висит на root машины.
|
||
- Считает collision damage через `OnCollisionEnter`.
|
||
- Считает landing damage по каждому `WheelCollider`.
|
||
- Отправляет damage напрямую в `VehicleDamageController`.
|
||
|
||
HUD:
|
||
|
||
- `VehicleDamageHud` слушает `VehicleDamageController.ModuleStateChanged`.
|
||
- Красит overlay:
|
||
- healthy - transparent;
|
||
- damaged - red;
|
||
- destroyed/detached - black.
|
||
|
||
## Enemy Architecture
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph HarvesterPrefab["HARVESTER PREFAB"]
|
||
HarvesterRoot["Root\nRigidbody + BoxCollider"]
|
||
Chase["HarvesterChaseController"]
|
||
HarvesterWheels["WheelColliders + WheelVisuals"]
|
||
Blades["Blades"]
|
||
Spinner["HarvesterBladeSpinner"]
|
||
BladeDamage["BladeDamageSource"]
|
||
end
|
||
|
||
subgraph Target["TARGET"]
|
||
PlayerVehicle["ArcadeBuggyController player"]
|
||
PlayerHitboxes["Player DamageHitboxes"]
|
||
end
|
||
|
||
Chase --> HarvesterWheels
|
||
Chase -->|"FindFirstObjectByType / target"| PlayerVehicle
|
||
Blades --> Spinner
|
||
Blades --> BladeDamage
|
||
BladeDamage --> PlayerHitboxes
|
||
```
|
||
|
||
Проблема:
|
||
|
||
- Harvester сам ищет player.
|
||
- Нет `EnemyDirector`.
|
||
- Нет единого `TargetProvider`.
|
||
- При нескольких машинах враг может выбрать не ту.
|
||
|
||
## Camera And HUD Binding
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
Spawner["SelectedVehicleSpawner"]
|
||
Player["Spawned Player Vehicle"]
|
||
|
||
subgraph CameraSystem["CAMERA SYSTEM"]
|
||
FollowCamera["BuggyFollowCamera"]
|
||
RearViewCamera["RearViewMirrorCamera"]
|
||
RearViewRT["RearViewMirror RenderTexture"]
|
||
RearViewImage["Rear View UI Image"]
|
||
end
|
||
|
||
subgraph HUDSystem["HUD SYSTEM"]
|
||
DamageHud["VehicleDamageHud"]
|
||
HudBase["DamageHUD_BaseLayers"]
|
||
HudOverlays["DamageHUD_DamageOverlays"]
|
||
end
|
||
|
||
Spawner --> Player
|
||
Spawner -->|"SetTarget"| FollowCamera
|
||
Spawner -->|"SetTarget"| RearViewCamera
|
||
RearViewCamera --> RearViewRT
|
||
RearViewRT --> RearViewImage
|
||
|
||
Player -->|"VehicleDamageController"| DamageHud
|
||
DamageHud --> HudBase
|
||
DamageHud --> HudOverlays
|
||
```
|
||
|
||
Проблема:
|
||
|
||
- Камеры и HUD умеют искать player сами.
|
||
- Spawner тоже задает им player.
|
||
- Нужно выбрать один путь. Лучше: bind только через bootstrap.
|
||
|
||
## Current Dependency Table
|
||
|
||
| System | Owns | Depends On | Problem |
|
||
|---|---|---|---|
|
||
| `SelectionMenuController` | UI выбора, preview, load scene | `GameSelectionState`, real vehicle prefab | Preview завязан на gameplay prefab |
|
||
| `GameSelectionState` | выбранная машина/режим/карта | static global state | нет lifecycle, нет reset/session |
|
||
| `SelectedVehicleSpawner` | spawn player, bind camera/HUD | `GameSelectionState`, cameras, HUD, damage | делает больше, чем spawner |
|
||
| `ArcadeBuggyController` | input, drive, wheels, audio, VFX | wheel objects, audio, particles | слишком широкий класс |
|
||
| `VehicleDamageController` | health modules | modules array | ок, но нужен profile/config |
|
||
| `VehicleImpactDamageReceiver` | terrain/collision damage | `ArcadeBuggyController`, `VehicleDamageController` | damage зависит от конкретной машины |
|
||
| `VehicleWheelDamageModule` | wheel destruction | `ArcadeBuggyController` | damage знает controller |
|
||
| `VehicleDamageHud` | module damage UI | `VehicleDamageController`, scene UI sprites | mapping зашит в scene |
|
||
| `HarvesterChaseController` | enemy movement | player search, wheel colliders | нет EnemyDirector |
|
||
| `BladeDamageSource` | blade damage | `DamageHitbox` | нормальная связь для source damage |
|
||
| `BuggyFollowCamera` | follow camera | player search or external target | два способа binding |
|
||
| `RearViewMirrorCamera` | rear view | player search or external target | два способа binding |
|
||
|
||
## Architecture Problems To Fix Before Scaling
|
||
|
||
### 1. Нужен GameBootstrap
|
||
|
||
Сейчас gameplay-сцена собирается через `SelectedVehicleSpawner`, но по факту он уже делает bootstrap.
|
||
|
||
Нужно:
|
||
|
||
```text
|
||
GameBootstrap
|
||
-> read session request
|
||
-> create player
|
||
-> bind cameras
|
||
-> bind HUD
|
||
-> start enemies
|
||
-> start game mode
|
||
```
|
||
|
||
### 2. Нужен GameSession
|
||
|
||
Сейчас состояние между сценами хранится в static `GameSelectionState`.
|
||
|
||
Нужно:
|
||
|
||
```text
|
||
GameSession
|
||
selected vehicle
|
||
selected map
|
||
selected game mode
|
||
player instance
|
||
active enemies
|
||
session state
|
||
```
|
||
|
||
### 3. Нужен VehicleDefinition
|
||
|
||
Сейчас selection хранит `GameObject prefab`.
|
||
|
||
Лучше:
|
||
|
||
```text
|
||
VehicleDefinition
|
||
display name
|
||
gameplay prefab
|
||
preview settings
|
||
damage profile
|
||
HUD damage layout
|
||
audio profile
|
||
```
|
||
|
||
### 4. Нужен Wheel Rig Adapter
|
||
|
||
Damage не должен знать `ArcadeBuggyController`.
|
||
|
||
Нужно:
|
||
|
||
```csharp
|
||
public interface IVehicleWheelRig
|
||
{
|
||
WheelCollider GetWheelCollider(WheelSlot slot);
|
||
Transform GetWheelVisual(WheelSlot slot);
|
||
void SetWheelEnabled(WheelSlot slot, bool enabled);
|
||
bool IsWheelGrounded(WheelSlot slot);
|
||
}
|
||
```
|
||
|
||
Тогда:
|
||
|
||
- `VehicleImpactDamageReceiver` зависит от `IVehicleWheelRig`;
|
||
- `VehicleWheelDamageModule` зависит от `IVehicleWheelRig`;
|
||
- конкретная багги просто предоставляет реализацию.
|
||
|
||
### 5. Нужен Input Layer
|
||
|
||
Сейчас `ArcadeBuggyController` сам читает keyboard.
|
||
|
||
Нужно:
|
||
|
||
```text
|
||
IPlayerInputSource
|
||
Throttle
|
||
Steering
|
||
Handbrake
|
||
|
||
KeyboardInputSource
|
||
GamepadInputSource
|
||
ArcadeCabinetInputSource
|
||
AIInputSource
|
||
```
|
||
|
||
### 6. Нужны Game Modes
|
||
|
||
Сейчас есть enum:
|
||
|
||
- `Arena`
|
||
- `SurvivalRace`
|
||
|
||
Но нет runtime-режимов.
|
||
|
||
Нужно:
|
||
|
||
```text
|
||
IGameMode
|
||
ArenaMode
|
||
SurvivalRaceMode
|
||
```
|
||
|
||
Game mode должен отвечать за:
|
||
|
||
- правила старта;
|
||
- enemy spawn rules;
|
||
- win/lose;
|
||
- scoring;
|
||
- timer;
|
||
- map-specific logic.
|
||
|
||
## Target Architecture
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph Entry["ENTRY"]
|
||
Selection["Selection Scene"]
|
||
SessionRequest["GameSessionRequest"]
|
||
end
|
||
|
||
subgraph Data["DATA / DEFINITIONS"]
|
||
VehicleDefinition["VehicleDefinition"]
|
||
MapDefinition["MapDefinition"]
|
||
GameModeDefinition["GameModeDefinition"]
|
||
DamageProfile["VehicleDamageProfile"]
|
||
HudDefinition["VehicleHudDefinition"]
|
||
end
|
||
|
||
subgraph Bootstrap["GAMEPLAY BOOTSTRAP"]
|
||
GameBootstrap["GameBootstrap"]
|
||
GameSession["GameSession"]
|
||
VehicleFactory["VehicleFactory"]
|
||
CameraBinder["CameraRigBinder"]
|
||
HudBinder["HudBinder"]
|
||
EnemyDirector["EnemyDirector"]
|
||
GameModeRunner["GameModeRunner"]
|
||
end
|
||
|
||
subgraph Runtime["RUNTIME OBJECTS"]
|
||
Player["Player Vehicle"]
|
||
Enemies["Enemies"]
|
||
World["Map / Terrain / Hazards"]
|
||
end
|
||
|
||
subgraph VehicleSystems["VEHICLE SYSTEMS"]
|
||
InputSource["IPlayerInputSource"]
|
||
VehicleController["IVehicleController"]
|
||
WheelRig["IVehicleWheelRig"]
|
||
DamageController["VehicleDamageController"]
|
||
ImpactReceiver["VehicleImpactDamageReceiver"]
|
||
VehicleAudio["VehicleAudioController"]
|
||
VehicleVFX["VehicleEffectsController"]
|
||
end
|
||
|
||
Selection --> SessionRequest
|
||
SessionRequest --> GameBootstrap
|
||
|
||
GameBootstrap --> GameSession
|
||
GameBootstrap --> VehicleFactory
|
||
GameBootstrap --> CameraBinder
|
||
GameBootstrap --> HudBinder
|
||
GameBootstrap --> EnemyDirector
|
||
GameBootstrap --> GameModeRunner
|
||
|
||
GameSession --> VehicleDefinition
|
||
GameSession --> MapDefinition
|
||
GameSession --> GameModeDefinition
|
||
|
||
VehicleDefinition --> DamageProfile
|
||
VehicleDefinition --> HudDefinition
|
||
VehicleFactory --> Player
|
||
|
||
Player --> InputSource
|
||
Player --> VehicleController
|
||
Player --> WheelRig
|
||
Player --> DamageController
|
||
Player --> ImpactReceiver
|
||
Player --> VehicleAudio
|
||
Player --> VehicleVFX
|
||
|
||
EnemyDirector --> Enemies
|
||
GameModeRunner --> Enemies
|
||
GameModeRunner --> World
|
||
CameraBinder --> Player
|
||
HudBinder --> Player
|
||
HudBinder --> HudDefinition
|
||
```
|
||
|
||
## Recommended Refactor Plan
|
||
|
||
### Step 1 - Rename / Split Spawner
|
||
|
||
Current:
|
||
|
||
```text
|
||
SelectedVehicleSpawner
|
||
```
|
||
|
||
Target:
|
||
|
||
```text
|
||
GameBootstrap
|
||
VehicleFactory
|
||
CameraRigBinder
|
||
HudBinder
|
||
```
|
||
|
||
Minimum first change:
|
||
|
||
- оставить spawn в `SelectedVehicleSpawner`;
|
||
- вынести camera/HUD binding в отдельные компоненты;
|
||
- или переименовать `SelectedVehicleSpawner` в `GameBootstrap` и явно признать его ответственность.
|
||
|
||
### Step 2 - Replace Static Selection With Session Request
|
||
|
||
Current:
|
||
|
||
```text
|
||
GameSelectionState static
|
||
```
|
||
|
||
Target:
|
||
|
||
```text
|
||
GameSessionRequest
|
||
GameSession
|
||
```
|
||
|
||
### Step 3 - Introduce VehicleDefinition
|
||
|
||
Current:
|
||
|
||
```text
|
||
SelectionMenuController.VehicleOption -> GameObject prefab
|
||
```
|
||
|
||
Target:
|
||
|
||
```text
|
||
SelectionMenuController.VehicleOption -> VehicleDefinition
|
||
VehicleDefinition -> gameplay prefab / preview / damage / HUD / audio
|
||
```
|
||
|
||
### Step 4 - Decouple Damage From ArcadeBuggyController
|
||
|
||
Current:
|
||
|
||
```text
|
||
VehicleImpactDamageReceiver -> ArcadeBuggyController
|
||
VehicleWheelDamageModule -> ArcadeBuggyController
|
||
```
|
||
|
||
Target:
|
||
|
||
```text
|
||
VehicleImpactDamageReceiver -> IVehicleWheelRig
|
||
VehicleWheelDamageModule -> IVehicleWheelRig
|
||
ArcadeBuggyController or BuggyWheelRig -> IVehicleWheelRig
|
||
```
|
||
|
||
### Step 5 - Split ArcadeBuggyController
|
||
|
||
Current:
|
||
|
||
```text
|
||
ArcadeBuggyController
|
||
input
|
||
physics
|
||
wheel visuals
|
||
audio
|
||
VFX
|
||
wheel API for damage
|
||
```
|
||
|
||
Target:
|
||
|
||
```text
|
||
ArcadeBuggyController / VehicleMotor
|
||
VehicleInputSource
|
||
VehicleWheelVisuals
|
||
VehicleAudioController
|
||
VehicleEffectsController
|
||
BuggyWheelRig
|
||
```
|
||
|
||
## What Is Safe To Add Now
|
||
|
||
Можно добавлять без сильного риска:
|
||
|
||
- tuning параметров машины;
|
||
- tuning damage thresholds;
|
||
- улучшение HUD;
|
||
- настройка harvester movement;
|
||
- новые визуальные эффекты;
|
||
- простые hazards, если они наносят урон через `DamageHitbox`.
|
||
|
||
## What Should Wait
|
||
|
||
Лучше не добавлять до bootstrap/session/refactor:
|
||
|
||
- оружие;
|
||
- несколько видов enemies;
|
||
- power-ups;
|
||
- полноценные game modes;
|
||
- scoring/results;
|
||
- несколько player vehicles;
|
||
- сохранение прогресса;
|
||
- arcade cabinet input;
|
||
- VR-specific gameplay.
|
||
|
||
Причина: все это сейчас будет цепляться к static state, scene object search и прямым ссылкам.
|
||
|
||
## Summary
|
||
|
||
Текущая архитектура рабочая для prototype, но главный риск уже виден:
|
||
|
||
```text
|
||
Нет единого runtime-контекста.
|
||
```
|
||
|
||
Сейчас обязанности размазаны между:
|
||
|
||
- `GameSelectionState`;
|
||
- `SelectedVehicleSpawner`;
|
||
- камерами, которые сами ищут player;
|
||
- harvester, который сам ищет player;
|
||
- HUD, который сам ищет damage controller.
|
||
|
||
Нормальная точка сборки должна выглядеть так:
|
||
|
||
```text
|
||
Selection Scene
|
||
-> GameSessionRequest
|
||
-> Demo Scene
|
||
-> GameBootstrap
|
||
-> GameSession
|
||
-> Player / Cameras / HUD / Enemies / GameMode
|
||
```
|
||
|
||
После этого новые системы будут подключаться через session/bootstrap, а не случайно искать друг друга по сцене.
|