feat: HUD overlay via UIScene — health bar, quick slots, inventory info (Phase 4.7)

UIScene renders as overlay on top of GameScene:
- Health bar (top-left) with color transitions green→yellow→red
- 4 quick slots (bottom-center) with active highlight, item symbols and counts
- Inventory weight/slots info (bottom-right)
- Controls hint (top-right)

GameScene pushes state to Phaser registry each frame.
Phase 4 (Player Systems) complete — 222 tests passing.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Денис Шкабатур
2026-02-12 13:36:42 +03:00
parent d173ada466
commit 7e46d1ed1d
5 changed files with 308 additions and 18 deletions

View File

@@ -1,6 +1,6 @@
import Phaser from 'phaser';
import { createGameWorld, updateTime, type GameWorld } from '../ecs/world';
import { Position } from '../ecs/components';
import { Health, Position } from '../ecs/components';
import { movementSystem } from '../ecs/systems/movement';
import { healthSystem } from '../ecs/systems/health';
import { removeGameEntity } from '../ecs/factory';
@@ -154,6 +154,9 @@ export class GameScene extends Phaser.Scene {
this.interactionText.setOrigin(0.5);
this.interactionText.setDepth(100);
this.interactionText.setAlpha(0);
// 11. Launch UIScene overlay
this.scene.launch('UIScene');
}
update(_time: number, delta: number): void {
@@ -243,15 +246,27 @@ export class GameScene extends Phaser.Scene {
}
}
// 13. Stats
// 13. Push shared state to registry for UIScene
this.registry.set('health', Health.current[this.playerEid] ?? 100);
this.registry.set('healthMax', Health.max[this.playerEid] ?? 100);
this.registry.set('quickSlots', this.quickSlots.getAll());
this.registry.set('activeSlot', this.quickSlots.activeIndex);
this.registry.set('invWeight', this.inventory.getTotalWeight());
this.registry.set('invMaxWeight', this.inventory.maxWeight);
this.registry.set('invSlots', this.inventory.slotCount);
// Build counts map for UIScene
const counts = new Map<string, number>();
for (const item of this.inventory.getItems()) {
counts.set(item.id, item.count);
}
this.registry.set('invCounts', counts);
// 14. Debug stats overlay
const fps = delta > 0 ? Math.round(1000 / delta) : 0;
const px = Math.round(Position.x[this.playerEid]);
const py = Math.round(Position.y[this.playerEid]);
const invWeight = Math.round(this.inventory.getTotalWeight());
const invSlots = this.inventory.slotCount;
this.statsText.setText(
`seed: ${this.worldSeed} | ${fps} fps | pos: ${px},${py} | inv: ${invSlots} items, ${invWeight} AMU | WASD/E/F/scroll`,
);
this.statsText.setText(`seed: ${this.worldSeed} | ${fps} fps | pos: ${px},${py}`);
}
/** Try to launch a projectile from active quick slot toward mouse */