Минимальный набор шагов, чтобы получить работающее приложение на движке.
apps/my-game/
index.html
vite.config.ts # alias @rpg/engine -> ../../packages/engine/src/index.ts
src/
main.ts # bootstrap
Game.ts # общий контекст игры (опционально, но удобно)
scenes/ # сцены игры
vite.config.ts:
import { defineConfig } from 'vite';
export default defineConfig({
resolve: {
alias: { '@rpg/engine': '../../packages/engine/src/index.ts' }
}
});
import { Engine, computeScale, type EngineOptions } from '@rpg/engine';
import { BootScene } from './scenes/BootScene';
const VW = 480, VH = 270; // виртуальное разрешение
async function main(): Promise<void> {
const container = document.getElementById('game')!;
const options: EngineOptions = {
virtualWidth: VW,
virtualHeight: VH,
scale: computeScale(VW, VH, window.innerWidth, window.innerHeight),
background: 0x0b0b12,
fixedFps: 60,
parent: container
};
const engine = new Engine(options);
await engine.init(); // WebGL + ввод + оверлей переходов
engine.input.bindActions({ // «действия» вместо кодов клавиш
advance: ['Space', 'Enter'],
menu: ['Escape'],
up: ['KeyW', 'ArrowUp'],
down: ['KeyS', 'ArrowDown']
});
engine.input.bindGamepad({ // те же действия на геймпаде (кнопки стандартной карты)
advance: [0], // A
menu: [9], // Start
up: [12],
down: [13]
});
await engine.scenes.push(new BootScene(engine));
await engine.start();
}
void main();
Ресайз окна обрабатывается автоматически (autoResize: true по умолчанию): масштаб пересчитывается, виртуальное разрешение не меняется.
Сцена — экран игры. Минимальная:
import { Container, Text, type Scene } from '@rpg/engine';
export class TitleScene implements Scene {
private view = new Container();
constructor(engine: Engine) {
const t = new Text({ text: 'Моя игра', style: { fill: 0xffffff, fontSize: 16, fontFamily: 'monospace' } });
this.view.addChild(t);
engine.renderer.uiRoot.addChild(this.view);
}
enter(): void {}
exit(): void { this.view.destroy({ children: true }); }
update(dt: number): void {
if (engine.input.isActionJustPressed('advance')) {
void engine.scenes.replace(new GameScene(engine), { duration: 0.4 });
}
}
render(): void {}
}
Стек сцен: push (открыть поверх), pop (закрыть), replace (заменить верхнюю). Любой метод принимает { duration, color } — fade-затемнение между сценами.
import { AssetLoader } from '@rpg/engine';
const assets = new AssetLoader((key) => `assets/${key}.png`);
await assets.load(['tiles/grass', 'chars/hero'], (p) => console.log(`${Math.round(p * 100)}%`));
const tex = assets.texture('tiles/grass');
// Атлас (Spritesheet JSON + PNG):
const sheet = await assets.loadAtlas('chars/hero_sheet');
const walkFrames = assets.frames('chars/hero_sheet', 'hero_walk');
Смотрите assets-audio-save.md.
import { ensurePixelFont, PixelText } from '@rpg/engine';
await ensurePixelFont('fonts/VT323-Regular.ttf'); // до создания текста
const label = new PixelText({ text: 'Привет', size: 10, color: 0xf0d878 });
npm run dev # dev-сервер npm run build # прод-сборка npm run typecheck # движок + игра npm test # Vitest