Files
dflike/server/src/game/GameLoop.ts
T
2026-03-06 18:53:19 -05:00

77 lines
2.3 KiB
TypeScript

import { TICK_RATE, BROADCAST_EVERY_N_TICKS } from '@dflike/shared';
import { World } from '../ecs/World.js';
import { GameMap } from '../map/GameMap.js';
import { needsDecaySystem } from '../systems/needsDecaySystem.js';
import { npcBrainSystem } from '../systems/npcBrainSystem.js';
import { movementSystem } from '../systems/movementSystem.js';
import { spawnNPC } from './spawner.js';
export class GameLoop {
readonly world: World;
readonly map: GameMap;
private tick = 0;
private interval: ReturnType<typeof setInterval> | null = null;
private onBroadcast: (() => void) | null = null;
constructor() {
this.world = new World();
this.map = new GameMap();
this.setupMap();
this.spawnInitialNPCs(8);
}
private setupMap(): void {
// Add some obstacle clusters for pathfinding interest
for (let x = 10; x <= 14; x++) for (let y = 10; y <= 12; y++) this.map.setObstacle(x, y);
for (let x = 30; x <= 33; x++) for (let y = 25; y <= 28; y++) this.map.setObstacle(x, y);
for (let x = 50; x <= 53; x++) for (let y = 40; y <= 43; y++) this.map.setObstacle(x, y);
// Points of interest
this.map.addPointOfInterest({ type: 'food', position: { x: 15, y: 15 } });
this.map.addPointOfInterest({ type: 'food', position: { x: 45, y: 30 } });
this.map.addPointOfInterest({ type: 'rest', position: { x: 8, y: 8 } });
this.map.addPointOfInterest({ type: 'rest', position: { x: 55, y: 50 } });
}
private spawnInitialNPCs(count: number): void {
for (let i = 0; i < count; i++) {
spawnNPC(this.world, this.map);
}
}
setBroadcastHandler(handler: () => void): void {
this.onBroadcast = handler;
}
start(): void {
const tickInterval = 1000 / TICK_RATE;
this.interval = setInterval(() => this.update(), tickInterval);
console.log(`Game loop started at ${TICK_RATE} ticks/sec`);
}
stop(): void {
if (this.interval) {
clearInterval(this.interval);
this.interval = null;
}
}
private update(): void {
this.tick++;
// Run systems in order
needsDecaySystem(this.world);
npcBrainSystem(this.world, this.map);
movementSystem(this.world);
// Broadcast state periodically
if (this.tick % BROADCAST_EVERY_N_TICKS === 0 && this.onBroadcast) {
this.onBroadcast();
}
}
getTick(): number {
return this.tick;
}
}