165 lines
5.4 KiB
TypeScript
165 lines
5.4 KiB
TypeScript
|
|
import Phaser from 'phaser'
|
||
|
|
import { TILE_SIZE } from '../config'
|
||
|
|
import { TileType } from '../types'
|
||
|
|
import { stateManager } from '../StateManager'
|
||
|
|
import type { VillagerSystem } from './VillagerSystem'
|
||
|
|
import type { WorldSystem } from './WorldSystem'
|
||
|
|
|
||
|
|
/** All data collected each frame for the debug panel. */
|
||
|
|
export interface DebugData {
|
||
|
|
fps: number
|
||
|
|
mouseWorld: { x: number; y: number }
|
||
|
|
mouseTile: { tileX: number; tileY: number }
|
||
|
|
tileType: string
|
||
|
|
resourcesOnTile: Array<{ kind: string; hp: number }>
|
||
|
|
buildingsOnTile: string[]
|
||
|
|
cropsOnTile: Array<{ kind: string; stage: number; maxStage: number }>
|
||
|
|
nisseTotal: number
|
||
|
|
nisseByState: { idle: number; walking: number; working: number; sleeping: number }
|
||
|
|
jobsByType: { chop: number; mine: number; farm: number }
|
||
|
|
activePaths: number
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Human-readable names for TileType enum values. */
|
||
|
|
const TILE_NAMES: Record<number, string> = {
|
||
|
|
[TileType.DEEP_WATER]: 'DEEP_WATER',
|
||
|
|
[TileType.SHALLOW_WATER]: 'SHALLOW_WATER',
|
||
|
|
[TileType.SAND]: 'SAND',
|
||
|
|
[TileType.GRASS]: 'GRASS',
|
||
|
|
[TileType.DARK_GRASS]: 'DARK_GRASS',
|
||
|
|
[TileType.FOREST]: 'FOREST',
|
||
|
|
[TileType.ROCK]: 'ROCK',
|
||
|
|
[TileType.FLOOR]: 'FLOOR',
|
||
|
|
[TileType.WALL]: 'WALL',
|
||
|
|
[TileType.TILLED_SOIL]: 'TILLED_SOIL',
|
||
|
|
[TileType.WATERED_SOIL]: 'WATERED_SOIL',
|
||
|
|
}
|
||
|
|
|
||
|
|
export class DebugSystem {
|
||
|
|
private scene: Phaser.Scene
|
||
|
|
private villagerSystem: VillagerSystem
|
||
|
|
private worldSystem: WorldSystem
|
||
|
|
private pathGraphics!: Phaser.GameObjects.Graphics
|
||
|
|
private active = false
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param scene - The Phaser scene this system belongs to
|
||
|
|
* @param villagerSystem - Used to read active paths for visualization
|
||
|
|
* @param worldSystem - Used to read tile types under the mouse
|
||
|
|
*/
|
||
|
|
constructor(scene: Phaser.Scene, villagerSystem: VillagerSystem, worldSystem: WorldSystem) {
|
||
|
|
this.scene = scene
|
||
|
|
this.villagerSystem = villagerSystem
|
||
|
|
this.worldSystem = worldSystem
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Creates the world-space Graphics object used for pathfinding visualization.
|
||
|
|
* Starts hidden until toggled on.
|
||
|
|
*/
|
||
|
|
create(): void {
|
||
|
|
this.pathGraphics = this.scene.add.graphics().setDepth(50)
|
||
|
|
this.pathGraphics.setVisible(false)
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Toggles debug mode on or off.
|
||
|
|
* Shows or hides the pathfinding overlay graphics accordingly.
|
||
|
|
*/
|
||
|
|
toggle(): void {
|
||
|
|
this.active = !this.active
|
||
|
|
this.pathGraphics.setVisible(this.active)
|
||
|
|
if (!this.active) this.pathGraphics.clear()
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Returns whether debug mode is currently active. */
|
||
|
|
isActive(): boolean {
|
||
|
|
return this.active
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Redraws pathfinding lines for all currently walking Nisse.
|
||
|
|
* Should be called every frame while debug mode is active.
|
||
|
|
*/
|
||
|
|
update(): void {
|
||
|
|
if (!this.active) return
|
||
|
|
this.pathGraphics.clear()
|
||
|
|
|
||
|
|
const paths = this.villagerSystem.getActivePaths()
|
||
|
|
this.pathGraphics.lineStyle(1, 0x00ffff, 0.65)
|
||
|
|
|
||
|
|
for (const entry of paths) {
|
||
|
|
if (entry.path.length === 0) continue
|
||
|
|
this.pathGraphics.beginPath()
|
||
|
|
this.pathGraphics.moveTo(entry.x, entry.y)
|
||
|
|
for (const step of entry.path) {
|
||
|
|
this.pathGraphics.lineTo(
|
||
|
|
(step.tileX + 0.5) * TILE_SIZE,
|
||
|
|
(step.tileY + 0.5) * TILE_SIZE,
|
||
|
|
)
|
||
|
|
}
|
||
|
|
this.pathGraphics.strokePath()
|
||
|
|
|
||
|
|
// Mark the destination tile
|
||
|
|
const last = entry.path[entry.path.length - 1]
|
||
|
|
this.pathGraphics.fillStyle(0x00ffff, 0.4)
|
||
|
|
this.pathGraphics.fillRect(
|
||
|
|
last.tileX * TILE_SIZE,
|
||
|
|
last.tileY * TILE_SIZE,
|
||
|
|
TILE_SIZE,
|
||
|
|
TILE_SIZE,
|
||
|
|
)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Collects and returns all debug data for the current frame.
|
||
|
|
* Called by UIScene to populate the debug panel.
|
||
|
|
* @param ptr - The active pointer, used to resolve world position
|
||
|
|
* @returns Snapshot of game state for display
|
||
|
|
*/
|
||
|
|
getDebugData(ptr: Phaser.Input.Pointer): DebugData {
|
||
|
|
const state = stateManager.getState()
|
||
|
|
const villagers = Object.values(state.world.villagers)
|
||
|
|
const tileX = Math.floor(ptr.worldX / TILE_SIZE)
|
||
|
|
const tileY = Math.floor(ptr.worldY / TILE_SIZE)
|
||
|
|
const tileType = this.worldSystem.getTileType(tileX, tileY)
|
||
|
|
|
||
|
|
const nisseByState = { idle: 0, walking: 0, working: 0, sleeping: 0 }
|
||
|
|
const jobsByType = { chop: 0, mine: 0, farm: 0 }
|
||
|
|
|
||
|
|
for (const v of villagers) {
|
||
|
|
nisseByState[v.aiState as keyof typeof nisseByState]++
|
||
|
|
if (v.job && (v.aiState === 'working' || v.aiState === 'walking')) {
|
||
|
|
jobsByType[v.job.type as keyof typeof jobsByType]++
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const resourcesOnTile = Object.values(state.world.resources)
|
||
|
|
.filter(r => r.tileX === tileX && r.tileY === tileY)
|
||
|
|
.map(r => ({ kind: r.kind, hp: r.hp }))
|
||
|
|
|
||
|
|
const buildingsOnTile = Object.values(state.world.buildings)
|
||
|
|
.filter(b => b.tileX === tileX && b.tileY === tileY)
|
||
|
|
.map(b => b.kind)
|
||
|
|
|
||
|
|
const cropsOnTile = Object.values(state.world.crops)
|
||
|
|
.filter(c => c.tileX === tileX && c.tileY === tileY)
|
||
|
|
.map(c => ({ kind: c.kind, stage: c.stage, maxStage: c.maxStage }))
|
||
|
|
|
||
|
|
return {
|
||
|
|
fps: Math.round(this.scene.game.loop.actualFps),
|
||
|
|
mouseWorld: { x: ptr.worldX, y: ptr.worldY },
|
||
|
|
mouseTile: { tileX, tileY },
|
||
|
|
tileType: TILE_NAMES[tileType] ?? `UNKNOWN(${tileType})`,
|
||
|
|
resourcesOnTile,
|
||
|
|
buildingsOnTile,
|
||
|
|
cropsOnTile,
|
||
|
|
nisseTotal: villagers.length,
|
||
|
|
nisseByState,
|
||
|
|
jobsByType,
|
||
|
|
activePaths: this.villagerSystem.getActivePaths().length,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|