Architektura
Warstwy silnika, izolacja adaptera przez porty, przepływ klatki, granice modułów i zasady wydajności, które pilnują testy.
Warstwy#
┌───────────────┐ ┌──────────────────────────────┐ ┌──────────────────┐
│ Kod gry │ │ Engine │ │ Adapter │
│ Sceny │──▶│ Config + Time + EventBus │──▶│ PhaserRenderLayer│──▶ Phaser.Game
│ Komponenty │ │ SceneManager ObjectIndex │ │ PhaserPhysics │──▶ Arcade
│ Obiekty │ │ AssetManager InputManager │ │ PhaserCamera │──▶ Camera
└───────────────┘ │ PhysicsManager CameraManager│ │ PhaserInput │──▶ Keyboard
│ AudioManager TweenManager │ │ PhaserAudio │──▶ WebAudio
└──────────────┬───────────────┘ │ PhaserAssets │──▶ Loader
│ └──────────────────┘
core/ports.ts (6 interfejsów) │
▼
┌──────────────────┐
│ WASM (opcjonalnie)│
└──────────────────┘
| Katalog | Zna Phasera | Zawartość |
|---|---|---|
core | nie | Engine, Scene, GameObject, Component, ObjectIndex, Time, porty |
components | nie | Transform |
animation | nie | Easing (28 krzywych), Tween, TweenManager, sekwencje |
audio | nie | AudioManager, kanały, SoundHandle, kolejka autoplay |
systems | nie | EventBus, AssetManager, InputManager, PhysicsManager, CameraManager, Logger |
debug | nie | LogBuffer, LogPanel, DebugViews, Profiler, Diagnostics |
plugins | nie | PluginHost, rejestry, manifest, parser zakresów wersji |
adapters | tak | PhaserAdapter + backendy i warstwa renderu |
Izolacja adaptera#
Rdzeń nie importuje Phasera. Pilnują tego dwa mechanizmy:
- Reguła ESLint
no-restricted-imports. - Test
tests/unit/PublicApi.test.ts, który skanuje źródła i wywala się na import Phasera lub kataloguadapters/wcore/.
Cały dostęp do runtime idzie przez sześć interfejsów z core/ports.ts:
interface RuntimeAdapter {
render: RenderPort
physics: PhysicsPort
camera: CameraPort
input: InputPort
audio: AudioPort
assets: AssetBackend
}
Nowy backend = sześć nowych implementacji. Metody opcjonalne są wykrywane przez supports* i wołane z ?? false / ?? null, więc minimalny adapter nie wywala się w runtime.
GameObject to encja domenowa
GameObject trzyma tagi, grupy, transform lokalny, hierarchię i komponenty oraz deskryptory render i body — nigdy instancję Phasera. Renderer dostaje deskryptor, nie obiekt sceny.
Przepływ klatki#
Kolejność faz internalUpdate sceny:
applyPhysicsPositions odczyt pozycji z fizyki
→ tweenManager.update tweeny mutują zwykłe właściwości
→ komponenty input faza wejścia
→ Scene.update(dt) logika gry
→ komponenty behavior zachowania
→ komponenty physics ciała
→ komponenty animation klatki animacji
→ komponenty render przygotowanie renderu
→ kolejka pendingDestroy usuwanie obiektów
→ syncRender tylko obiekty brudne
→ debug overlay, panel, profiler
Cykl życia obiektu#
createObject → render.create → aktywacja w drzewie → aktualizacje
→ destroyObject → potomkowie liść-pierwszy → component.onDestroy
→ usunięcie z indeksu → render.destroy
Zasoby i zapisy#
- Assety:
declareAssets→AssetManifest(id, duplikaty, referencje, budżet rozmiaru) →AssetBackend.load→ statusyidle/queued/loading/ready/failed→ refcount właściciela zwalniany wshutdown. - Zapisy:
validateProject→exportProject(koperta + suma kontrolna) →ProjectRepository(tmp → odczyt zwrotny → backup → commit) lubPlayerSaveRepository→SaveStore.
SaveStore to pięć metod (read, write, remove, keys, clear). SqlSaveStore przyjmuje dowolny obiekt z query(sql, params) — dzięki temu w bundlu gry nie ma pg ani mysql2.
Wydajność#
- Brak alokacji w gorącej pętli poza jedną kopią listy subskrybentów w
EventBus.emiti przebudową listy komponentów po zmianie struktury. - Render dostaje tylko obiekty brudne — scena z 79 obiektami wysyła w klatce zwykle 1–3.
- Odczyt
worldjest O(1) po przeliczeniu; zmiana transformacji unieważnia tylko poddrzewo. - Aktualizacja komponentów: 0,72 ms na klatkę dla 20 000 obiektów, czyli ok. 0,07 ms dla 2 000.
- Profiler jest wyłączony domyślnie — wtedy
begin/endzwracają się natychmiast.
Więcej w Wydajność i benchmarki.
Decyzje architektoniczne#
Każda decyzja, której cofnięcie kosztowałoby więcej niż tydzień pracy, ma swój rekord ADR: izolacja adaptera, wersjonowany JSON, brak ECS, opcjonalny WASM, brak SPA fallback. Pełna lista: Decyzje architektoniczne.