Files
nissefolk/src/systems/ResourceSystem.ts
tekki mariani cd171c859c fix depth sorting for world objects by tileY
Fixes #31. All trees, rocks, seedlings and buildings now use
tileY+5 as depth instead of a fixed value, so objects further
down the screen always render in front of objects above them
regardless of spawn order. Build ghost moved to depth 1000/1001.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 19:40:27 +00:00

101 lines
2.9 KiB
TypeScript

import Phaser from 'phaser'
import { TILE_SIZE } from '../config'
import { TileType } from '../types'
import { stateManager } from '../StateManager'
import type { LocalAdapter } from '../NetworkAdapter'
import type { ResourceNodeState } from '../types'
interface ResourceSprite {
sprite: Phaser.GameObjects.Image
node: ResourceNodeState
healthBar: Phaser.GameObjects.Graphics
}
export class ResourceSystem {
private scene: Phaser.Scene
private adapter: LocalAdapter
private sprites = new Map<string, ResourceSprite>()
// Emits after each successful harvest: (message: string)
onHarvest?: (message: string) => void
constructor(scene: Phaser.Scene, adapter: LocalAdapter) {
this.scene = scene
this.adapter = adapter
}
create(): void {
const state = stateManager.getState()
// Spawn sprites for all resources in state
for (const node of Object.values(state.world.resources)) {
this.spawnSprite(node)
}
}
private spawnSprite(node: ResourceNodeState): void {
const x = (node.tileX + 0.5) * TILE_SIZE
const y = (node.tileY + 0.5) * TILE_SIZE
const key = node.kind === 'tree' ? 'tree' : 'rock'
const sprite = this.scene.add.image(x, y, key)
// Trees are taller; offset them upward so trunk sits on tile
if (node.kind === 'tree') {
sprite.setOrigin(0.5, 0.85)
} else {
sprite.setOrigin(0.5, 0.75)
}
sprite.setDepth(node.tileY + 5)
const healthBar = this.scene.add.graphics()
healthBar.setDepth(node.tileY + 6)
healthBar.setVisible(false)
this.sprites.set(node.id, { sprite, node, healthBar })
}
update(delta: number): void {
// Hide all health bars each frame (no player proximity detection)
for (const entry of this.sprites.values()) {
entry.healthBar.setVisible(false)
}
}
private removeSprite(id: string): void {
const entry = this.sprites.get(id)
if (!entry) return
entry.sprite.destroy()
entry.healthBar.destroy()
this.sprites.delete(id)
}
/** Called by VillagerSystem when a villager finishes chopping/mining */
public removeResource(id: string): void {
this.removeSprite(id)
}
/**
* Spawns a sprite for a resource that was created at runtime
* (e.g. a tree grown from a seedling). The resource must already be
* present in the game state when this is called.
* @param node - The resource node to render
*/
public spawnResourcePublic(node: ResourceNodeState): void {
this.spawnSprite(node)
}
/** Called when WorldSystem changes a tile (e.g. after tree removed) */
syncTileChange(tileX: number, tileY: number, worldSystem: { setTile: (x: number, y: number, type: TileType) => void }): void {
const state = stateManager.getState()
const idx = tileY * 512 + tileX // WORLD_TILES = 512
const tile = state.world.tiles[idx] as TileType
worldSystem.setTile(tileX, tileY, tile)
}
destroy(): void {
for (const [id] of this.sprites) this.removeSprite(id)
}
}