2D Game Engine

Szybki start

Od instalacji do pierwszej sceny i produkcyjnego builda — krok po kroku, z konfiguracją projektu JSON i opcjonalnym WASM.

Wymagania#

  • Node.js ≥ 20
  • npm (projekt używa workspaces)

Instalacja i uruchomienie#

  1. Zainstaluj zależności
    bash
    npm install
    
  2. Uruchom serwer deweloperski
    bash
    npm run dev
    

    Vite uruchamia apps/playground pod http://localhost:5173. Przykładowa gra ładuje się z menu do rozgrywki.
  3. Uruchom testy i typecheck
    bash
    npm test
    npm run typecheck
    

Pierwsza scena#

Utwórz plik apps/playground/src/scenes/MyScene.ts:

tsMyScene.ts
import { Scene } from '@engine'

export class MyScene extends Scene {
  constructor() {
    super('my')
  }

  create() {
    this.createText('hello', 640, 360, 'Cześć!', { fontSize: '24px', color: '#fff' })
      .setOrigin(0.5, 0.5)
  }

  update(dt: number) {
    if (this.getInput().isActionPressed('interact')) {
      this.getEvents().emit('request:scene', { to: 'game' })
    }
  }
}

Zarejestruj scenę w main.ts i wystartuj ją:

tsmain.ts
import { createEngine } from '@engine'
import { MyScene } from './scenes/MyScene'

const engine = createEngine({ parent: 'app', width: 1280, height: 720 })
engine.registerScene(new MyScene())
engine.start('my')

Informacja

Scena dostaje menedżery przez gettery (getInput(), getAudio(), getTweens()…), a nie przez globalny stan. Dzięki temu scenę można testować w izolacji.

Konfiguracja projektu JSON#

Silnik czyta wersjonowany format projektu. Utwórz project.json:

jsonproject.json
{
  "formatVersion": 2,
  "name": "MyGame",
  "game": {
    "width": 1280,
    "height": 720,
    "scaleMode": "fit",
    "backgroundColor": "#0f1419"
  },
  "assets": [
    { "id": "hero", "type": "image", "src": "/assets/hero.png" }
  ]
}

Załaduj i zweryfikuj go w kodzie:

ts
import { parseProjectJson } from '@engine'

const res = parseProjectJson(await fetch('/project.json').then((r) => r.text()))
if (!res.valid) throw new Error(res.errors.join('\n'))

Pełny opis formatu znajdziesz w Formacie projektu.

Build produkcyjny#

bash
npm run build

Statyczne pliki trafiają do dist/ — wrzuć je na dowolny hosting (Netlify, Vercel, S3, GitHub Pages). Build używa względnych ścieżek (base: './'), więc gra działa też w podkatalogu. Szczegóły i gotowe konfiguracje hostingu: Wdrożenie.

Debugowanie#

Włącz nakładkę debug w konfiguracji:

ts
const engine = createEngine({ parent: 'app', debug: true })

Overlay pokazuje FPS, czas klatki, liczbę obiektów, ciał fizyki i pamięć. pauseOnHidden: true (domyślnie) clampuje deltaTime po powrocie z innej karty. Więcej: Debugowanie.

Opcjonalny WASM#

Jeśli potrzebujesz ciężkiego compute (np. pathfinding A*):

ts
const engine = createEngine({
  parent: 'app',
  width: 800,
  height: 600,
  wasm: { wasmUrl: '/wasm/core.wasm', required: false }
})

await engine.getWasm().load()
const path = engine.getWasm().call<Vec2i[]>('findPathAStar', grid, start, goal)

WASM tylko z pomiarem

Most WASM jest przygotowany, ale MVP go nie wymaga. Dodaj moduł dopiero wtedy, gdy benchmark TS vs WASM wykaże korzyść. Szczegóły: WebAssembly.

Przydatne komendy#

KomendaDziałanie
npm run devSerwer deweloperski z HMR
npm run buildBuild produkcyjny + release.json
npm testTesty jednostkowe (Vitest)
npm run typecheckSprawdzenie typów
npm run benchBenchmarki Node → benchmarks/latest.json
npm run bench:checkPorównanie z baseline (próg 40%)
npm run build:singleplayground.html — jeden plik, bez sieci
npm run export:gamerelease/game + gotowe konfiguracje hostingu