🐛 fix Nisse outline only shown when actually occluded
Silhouette now hidden by default and toggled on per frame only when isOccluded() detects a tree, rock or building 1–3 tiles below the Nisse. Adds WorldSystem.hasResourceAt() for O(1) tile lookup. Outline colour changed to light blue (0xaaddff) at scale 1.1. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -125,8 +125,11 @@ export class VillagerSystem {
|
|||||||
const worldDepth = Math.floor(v.y / TILE_SIZE) + 5
|
const worldDepth = Math.floor(v.y / TILE_SIZE) + 5
|
||||||
rt.sprite.setPosition(v.x, v.y).setDepth(worldDepth)
|
rt.sprite.setPosition(v.x, v.y).setDepth(worldDepth)
|
||||||
|
|
||||||
// Outline sprite mirrors position, flip, and angle so the silhouette matches exactly
|
// Show outline only when a world object below the Nisse would occlude them
|
||||||
rt.outlineSprite.setPosition(v.x, v.y).setFlipX(rt.sprite.flipX).setAngle(rt.sprite.angle)
|
const tileX = Math.floor(v.x / TILE_SIZE)
|
||||||
|
const tileY = Math.floor(v.y / TILE_SIZE)
|
||||||
|
const occluded = this.isOccluded(tileX, tileY)
|
||||||
|
rt.outlineSprite.setPosition(v.x, v.y).setFlipX(rt.sprite.flipX).setAngle(rt.sprite.angle).setVisible(occluded)
|
||||||
|
|
||||||
rt.nameLabel.setPosition(v.x, v.y - 22)
|
rt.nameLabel.setPosition(v.x, v.y - 22)
|
||||||
rt.energyBar.setPosition(0, 0)
|
rt.energyBar.setPosition(0, 0)
|
||||||
@@ -583,13 +586,14 @@ export class VillagerSystem {
|
|||||||
* @param v - Villager state to create sprites for
|
* @param v - Villager state to create sprites for
|
||||||
*/
|
*/
|
||||||
private spawnSprite(v: VillagerState): void {
|
private spawnSprite(v: VillagerState): void {
|
||||||
// Silhouette rendered above all world objects so the Nisse is visible even
|
// Silhouette: same texture, white fill, fixed high depth so it shows through
|
||||||
// when occluded by a tree or building.
|
// trees and buildings. Visibility is toggled per frame by isOccluded().
|
||||||
const outlineSprite = this.scene.add.image(v.x, v.y, 'villager')
|
const outlineSprite = this.scene.add.image(v.x, v.y, 'villager')
|
||||||
.setScale(1.3)
|
.setScale(1.1)
|
||||||
.setTintFill(0xffffff)
|
.setTintFill(0xaaddff)
|
||||||
.setAlpha(0.7)
|
.setAlpha(0.85)
|
||||||
.setDepth(900)
|
.setDepth(900)
|
||||||
|
.setVisible(false)
|
||||||
|
|
||||||
// Main sprite depth is updated every frame based on Y position.
|
// Main sprite depth is updated every frame based on Y position.
|
||||||
const sprite = this.scene.add.image(v.x, v.y, 'villager')
|
const sprite = this.scene.add.image(v.x, v.y, 'villager')
|
||||||
@@ -640,6 +644,27 @@ export class VillagerSystem {
|
|||||||
if (rt.workLog.length > WORK_LOG_MAX) rt.workLog.length = WORK_LOG_MAX
|
if (rt.workLog.length > WORK_LOG_MAX) rt.workLog.length = WORK_LOG_MAX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── Occlusion check ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if a world object (tree, rock, or building) with a higher tileY
|
||||||
|
* than the Nisse exists on the same column, meaning the Nisse is visually
|
||||||
|
* behind that object. Checks 1–3 tiles below to account for tall tree canopies.
|
||||||
|
* @param tileX - Nisse's current tile column
|
||||||
|
* @param tileY - Nisse's current tile row
|
||||||
|
*/
|
||||||
|
private isOccluded(tileX: number, tileY: number): boolean {
|
||||||
|
const state = stateManager.getState()
|
||||||
|
for (let dy = 1; dy <= 3; dy++) {
|
||||||
|
const checkY = tileY + dy
|
||||||
|
if (this.worldSystem.hasResourceAt(tileX, checkY)) return true
|
||||||
|
if (Object.values(state.world.buildings).some(
|
||||||
|
b => b.tileX === tileX && b.tileY === checkY && b.kind !== 'stockpile_zone'
|
||||||
|
)) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// ─── Public API ───────────────────────────────────────────────────────────
|
// ─── Public API ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -172,6 +172,16 @@ export class WorldSystem {
|
|||||||
this.resourceTiles.delete(tileY * WORLD_TILES + tileX)
|
this.resourceTiles.delete(tileY * WORLD_TILES + tileX)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if a resource (tree or rock) occupies the given tile.
|
||||||
|
* Uses the O(1) resourceTiles index.
|
||||||
|
* @param tileX - Tile column
|
||||||
|
* @param tileY - Tile row
|
||||||
|
*/
|
||||||
|
hasResourceAt(tileX: number, tileY: number): boolean {
|
||||||
|
return this.resourceTiles.has(tileY * WORLD_TILES + tileX)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts world pixel coordinates to tile coordinates.
|
* Converts world pixel coordinates to tile coordinates.
|
||||||
* @param worldX - World X in pixels
|
* @param worldX - World X in pixels
|
||||||
|
|||||||
Reference in New Issue
Block a user