Fixed coprse bug
This commit is contained in:
@@ -140,10 +140,13 @@ export class DungeonRenderer {
|
||||
console.log(`[DungeonRenderer] Creating ECS sprites...`);
|
||||
const spriteEntities = this.ecsWorld.getEntitiesWith("position", "sprite");
|
||||
for (const entId of spriteEntities) {
|
||||
// Skip player as it's handled separately
|
||||
// Skip combatants as they are handled separately (player and enemies)
|
||||
const player = this.ecsWorld.getComponent(entId, "player");
|
||||
if (player) continue;
|
||||
|
||||
const actorType = this.ecsWorld.getComponent(entId, "actorType");
|
||||
if (actorType) continue;
|
||||
|
||||
const pos = this.ecsWorld.getComponent(entId, "position");
|
||||
const spriteData = this.ecsWorld.getComponent(entId, "sprite");
|
||||
if (pos && spriteData) {
|
||||
@@ -282,79 +285,84 @@ export class DungeonRenderer {
|
||||
const pos = this.ecsWorld.getComponent(trapId, "position");
|
||||
const spriteData = this.ecsWorld.getComponent(trapId, "sprite");
|
||||
|
||||
if (pos && spriteData) {
|
||||
// Bounds check
|
||||
if (pos.x < 0 || pos.x >= this.world.width || pos.y < 0 || pos.y >= this.world.height) {
|
||||
sprite.setVisible(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
const i = idx(this.world, pos.x, pos.y);
|
||||
const isSeen = seen[i] === 1;
|
||||
const isVis = visible[i] === 1;
|
||||
|
||||
sprite.setVisible(isSeen);
|
||||
|
||||
// Update position (with simple smoothing)
|
||||
const targetX = pos.x * TILE_SIZE + TILE_SIZE / 2;
|
||||
const targetY = pos.y * TILE_SIZE + TILE_SIZE / 2;
|
||||
|
||||
if (sprite.x !== targetX || sprite.y !== targetY) {
|
||||
// Check if it's far away (teleport) or nearby (tween)
|
||||
const dist = Phaser.Math.Distance.Between(sprite.x, sprite.y, targetX, targetY);
|
||||
if (dist > TILE_SIZE * 2) {
|
||||
this.scene.tweens.killTweensOf(sprite);
|
||||
sprite.setPosition(targetX, targetY);
|
||||
} else if (!this.scene.tweens.isTweening(sprite)) {
|
||||
this.scene.tweens.add({
|
||||
targets: sprite,
|
||||
x: targetX,
|
||||
y: targetY,
|
||||
duration: GAME_CONFIG.rendering.moveDuration,
|
||||
ease: 'Power1'
|
||||
});
|
||||
}
|
||||
// Handle missing components (entity destroyed)
|
||||
if (!pos || !spriteData) {
|
||||
sprite.destroy();
|
||||
this.trapSprites.delete(trapId);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Bounds check
|
||||
if (pos.x < 0 || pos.x >= this.world.width || pos.y < 0 || pos.y >= this.world.height) {
|
||||
sprite.setVisible(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
const i = idx(this.world, pos.x, pos.y);
|
||||
const isSeen = seen[i] === 1;
|
||||
const isVis = visible[i] === 1;
|
||||
|
||||
sprite.setVisible(isSeen);
|
||||
|
||||
// Update position (with simple smoothing)
|
||||
const targetX = pos.x * TILE_SIZE + TILE_SIZE / 2;
|
||||
const targetY = pos.y * TILE_SIZE + TILE_SIZE / 2;
|
||||
|
||||
if (sprite.x !== targetX || sprite.y !== targetY) {
|
||||
// Check if it's far away (teleport) or nearby (tween)
|
||||
const dist = Phaser.Math.Distance.Between(sprite.x, sprite.y, targetX, targetY);
|
||||
if (dist > TILE_SIZE * 2) {
|
||||
this.scene.tweens.killTweensOf(sprite);
|
||||
sprite.setPosition(targetX, targetY);
|
||||
} else if (!this.scene.tweens.isTweening(sprite)) {
|
||||
this.scene.tweens.add({
|
||||
targets: sprite,
|
||||
x: targetX,
|
||||
y: targetY,
|
||||
duration: GAME_CONFIG.rendering.moveDuration,
|
||||
ease: 'Power1'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update sprite frame in case trap was triggered
|
||||
const isStandalone = spriteData.texture === "mine_cart" || spriteData.texture === "ceramic_dragon_head";
|
||||
if (!isStandalone && sprite.frame.name !== String(spriteData.index)) {
|
||||
sprite.setFrame(spriteData.index);
|
||||
}
|
||||
// Update sprite frame in case trap was triggered
|
||||
const isStandalone = spriteData.texture === "mine_cart" || spriteData.texture === "ceramic_dragon_head";
|
||||
if (!isStandalone && sprite.frame.name !== String(spriteData.index)) {
|
||||
sprite.setFrame(spriteData.index);
|
||||
}
|
||||
|
||||
// Dim if not currently visible
|
||||
if (isSeen && !isVis) {
|
||||
sprite.setAlpha(0.4);
|
||||
sprite.setTint(0x888888);
|
||||
} else {
|
||||
// Flickering effect for Fire
|
||||
const name = this.ecsWorld.getComponent(trapId, "name");
|
||||
if (name?.name === "Fire") {
|
||||
const flicker = 0.8 + Math.sin(this.scene.time.now / 100) * 0.2;
|
||||
sprite.setAlpha(flicker);
|
||||
sprite.setScale(0.9 + Math.sin(this.scene.time.now / 150) * 0.1);
|
||||
// Dim if not currently visible
|
||||
if (isSeen && !isVis) {
|
||||
sprite.setAlpha(0.4);
|
||||
sprite.setTint(0x888888);
|
||||
} else {
|
||||
// Flickering effect for Fire
|
||||
const name = this.ecsWorld.getComponent(trapId, "name");
|
||||
if (name?.name === "Fire") {
|
||||
const flicker = 0.8 + Math.sin(this.scene.time.now / 100) * 0.2;
|
||||
sprite.setAlpha(flicker);
|
||||
sprite.setScale(0.9 + Math.sin(this.scene.time.now / 150) * 0.1);
|
||||
|
||||
// Tint based on underlying tile
|
||||
const tileIdx = idx(this.world, pos.x, pos.y);
|
||||
const worldTile = this.world.tiles[tileIdx];
|
||||
// Tint based on underlying tile
|
||||
const tileIdx = idx(this.world, pos.x, pos.y);
|
||||
const worldTile = this.world.tiles[tileIdx];
|
||||
|
||||
if (worldTile === TileType.GRASS) {
|
||||
sprite.setTint(0xff3300); // Bright red-orange for burning grass
|
||||
} else if (worldTile === TileType.DOOR_CLOSED || worldTile === TileType.DOOR_OPEN) {
|
||||
// Pulse between yellow and red for doors
|
||||
const pulse = (Math.sin(this.scene.time.now / 150) + 1) / 2;
|
||||
const r = 255;
|
||||
const g = Math.floor(200 * (1 - pulse));
|
||||
const b = 0;
|
||||
sprite.setTint((r << 16) | (g << 8) | b);
|
||||
} else {
|
||||
sprite.setTint(0xffaa44); // Default orange
|
||||
}
|
||||
if (worldTile === TileType.GRASS) {
|
||||
sprite.setTint(0xff3300); // Bright red-orange for burning grass
|
||||
} else if (worldTile === TileType.DOOR_CLOSED || worldTile === TileType.DOOR_OPEN) {
|
||||
// Pulse between yellow and red for doors
|
||||
const pulse = (Math.sin(this.scene.time.now / 150) + 1) / 2;
|
||||
const r = 255;
|
||||
const g = Math.floor(200 * (1 - pulse));
|
||||
const b = 0;
|
||||
sprite.setTint((r << 16) | (g << 8) | b);
|
||||
} else {
|
||||
sprite.setAlpha(1);
|
||||
sprite.clearTint();
|
||||
sprite.setTint(0xffaa44); // Default orange
|
||||
}
|
||||
} else {
|
||||
sprite.setAlpha(1);
|
||||
sprite.clearTint();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -538,7 +546,19 @@ export class DungeonRenderer {
|
||||
this.fxRenderer.showHeal(x, y, amount);
|
||||
}
|
||||
|
||||
spawnCorpse(x: number, y: number, type: ActorType) {
|
||||
spawnCorpse(x: number, y: number, type: ActorType, targetId?: EntityId) {
|
||||
if (targetId !== undefined) {
|
||||
if (targetId === this.entityAccessor.playerId) {
|
||||
if (this.playerSprite) {
|
||||
this.playerSprite.setVisible(false);
|
||||
}
|
||||
} else {
|
||||
const sprite = this.enemySprites.get(targetId);
|
||||
if (sprite) {
|
||||
sprite.setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.fxRenderer.spawnCorpse(x, y, type);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,12 @@ vi.mock('phaser', () => {
|
||||
play: vi.fn().mockReturnThis(),
|
||||
setPosition: vi.fn().mockReturnThis(),
|
||||
setVisible: vi.fn().mockReturnThis(),
|
||||
setDisplaySize: vi.fn().mockReturnThis(),
|
||||
destroy: vi.fn(),
|
||||
frame: { name: '0' },
|
||||
setFrame: vi.fn(),
|
||||
setAlpha: vi.fn(),
|
||||
setAngle: vi.fn(),
|
||||
clearTint: vi.fn(),
|
||||
};
|
||||
|
||||
@@ -89,10 +91,12 @@ describe('DungeonRenderer', () => {
|
||||
play: vi.fn().mockReturnThis(),
|
||||
setPosition: vi.fn().mockReturnThis(),
|
||||
setVisible: vi.fn().mockReturnThis(),
|
||||
setDisplaySize: vi.fn().mockReturnThis(),
|
||||
destroy: vi.fn(),
|
||||
frame: { name: '0' },
|
||||
setFrame: vi.fn(),
|
||||
setAlpha: vi.fn(),
|
||||
setAngle: vi.fn(),
|
||||
clearTint: vi.fn(),
|
||||
})),
|
||||
circle: vi.fn().mockReturnValue({
|
||||
@@ -134,6 +138,14 @@ describe('DungeonRenderer', () => {
|
||||
setDepth: vi.fn(),
|
||||
forEachTile: vi.fn(),
|
||||
}),
|
||||
createBlankLayer: vi.fn().mockReturnValue({
|
||||
setDepth: vi.fn().mockReturnThis(),
|
||||
forEachTile: vi.fn().mockReturnThis(),
|
||||
putTileAt: vi.fn(),
|
||||
setScale: vi.fn().mockReturnThis(),
|
||||
setScrollFactor: vi.fn().mockReturnThis(),
|
||||
setVisible: vi.fn().mockReturnThis(),
|
||||
}),
|
||||
destroy: vi.fn(),
|
||||
}),
|
||||
},
|
||||
@@ -247,4 +259,43 @@ describe('DungeonRenderer', () => {
|
||||
// Should NOT tween because it's the first spawn
|
||||
expect(mockScene.tweens.add).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should hide the original sprite when spawnCorpse is called with targetId', () => {
|
||||
renderer.initializeFloor(mockWorld, ecsWorld, accessor);
|
||||
|
||||
// Add a rat
|
||||
const enemyId = 100 as EntityId;
|
||||
ecsWorld.addComponent(enemyId, "position", { x: 3, y: 1 });
|
||||
ecsWorld.addComponent(enemyId, "actorType", { type: "rat" });
|
||||
ecsWorld.addComponent(enemyId, "stats", { hp: 10, maxHp: 10 } as any);
|
||||
|
||||
(renderer as any).fovManager.visibleArray[1 * mockWorld.width + 3] = 1;
|
||||
renderer.render([]);
|
||||
|
||||
// Verify sprite was created and is visible
|
||||
const sprite = (renderer as any).enemySprites.get(enemyId);
|
||||
expect(sprite).toBeDefined();
|
||||
expect(sprite.setVisible).toHaveBeenCalledWith(true);
|
||||
|
||||
// Call spawnCorpse with targetId
|
||||
renderer.spawnCorpse(3, 1, 'rat', enemyId);
|
||||
|
||||
// Verify original sprite was hidden
|
||||
expect(sprite.setVisible).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
it('should hide the player sprite when spawnCorpse is called with playerId', () => {
|
||||
renderer.initializeFloor(mockWorld, ecsWorld, accessor);
|
||||
|
||||
// Verify player sprite was created and is visible
|
||||
const playerSprite = (renderer as any).playerSprite;
|
||||
expect(playerSprite).toBeDefined();
|
||||
playerSprite.setVisible(true); // Force visible for test
|
||||
|
||||
// Call spawnCorpse with playerId
|
||||
renderer.spawnCorpse(1, 1, 'player', accessor.playerId);
|
||||
|
||||
// Verify player sprite was hidden
|
||||
expect(playerSprite.setVisible).toHaveBeenCalledWith(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@ vi.mock('phaser', () => {
|
||||
setAlpha: vi.fn().mockReturnThis(),
|
||||
setTint: vi.fn().mockReturnThis(),
|
||||
clearTint: vi.fn().mockReturnThis(),
|
||||
setDisplaySize: vi.fn().mockReturnThis(),
|
||||
destroy: vi.fn(),
|
||||
};
|
||||
|
||||
@@ -42,6 +43,7 @@ describe('FxRenderer', () => {
|
||||
setAlpha: vi.fn().mockReturnThis(),
|
||||
setTint: vi.fn().mockReturnThis(),
|
||||
clearTint: vi.fn().mockReturnThis(),
|
||||
setDisplaySize: vi.fn().mockReturnThis(),
|
||||
destroy: vi.fn(),
|
||||
})),
|
||||
text: vi.fn(() => ({
|
||||
|
||||
Reference in New Issue
Block a user