Character sprite switching - directionality - added dragon head

This commit is contained in:
2026-01-31 10:58:12 +11:00
parent 58b3726d21
commit b18e2d08ba
17 changed files with 163 additions and 85 deletions

View File

@@ -4,7 +4,7 @@ import { TileType } from "../core/terrain";
import { TILE_SIZE } from "../core/constants";
import { idx, isWall } from "../engine/world/world-logic";
import { GAME_CONFIG } from "../core/config/GameConfig";
import { ALL_TEMPLATES } from "../core/config/Items";
import { FovManager } from "./FovManager";
import { MinimapRenderer } from "./MinimapRenderer";
import { FxRenderer } from "./FxRenderer";
@@ -88,9 +88,10 @@ export class DungeonRenderer {
// Ensure player sprite exists
if (!this.playerSprite) {
this.playerSprite = this.scene.add.sprite(0, 0, "warrior", 0);
this.playerSprite = this.scene.add.sprite(0, 0, "PriestessSouth");
this.playerSprite.setDepth(100);
this.playerSprite.play('warrior-idle');
this.playerSprite.setDisplaySize(TILE_SIZE, TILE_SIZE); // Ensure it fits in 1 tile
// No animation for simple sprites for now
}
this.minimapRenderer.positionMinimap();
@@ -288,6 +289,18 @@ export class DungeonRenderer {
const ty = a.pos.y * TILE_SIZE + TILE_SIZE / 2;
if (this.playerSprite.x !== tx || this.playerSprite.y !== ty) {
// Determine direction
const dx = tx - this.playerSprite.x;
const dy = ty - this.playerSprite.y;
if (Math.abs(dy) > Math.abs(dx)) {
if (dy < 0) this.playerSprite.setTexture("PriestessNorth");
else this.playerSprite.setTexture("PriestessSouth");
} else if (Math.abs(dx) > 0) {
if (dx > 0) this.playerSprite.setTexture("PriestessEast");
else this.playerSprite.setTexture("PriestessWest");
}
this.scene.tweens.add({
targets: this.playerSprite,
x: tx,
@@ -465,7 +478,7 @@ export class DungeonRenderer {
this.fxRenderer.showFloatingText(x, y, message, color);
}
showProjectile(from: Vec2, to: Vec2, itemId: string, onComplete: () => void) {
showProjectile(from: Vec2, to: Vec2, texture: string, frame: number, onComplete: () => void) {
// World coords
const startX = from.x * TILE_SIZE + TILE_SIZE / 2;
const startY = from.y * TILE_SIZE + TILE_SIZE / 2;
@@ -473,15 +486,22 @@ export class DungeonRenderer {
const endY = to.y * TILE_SIZE + TILE_SIZE / 2;
// Create sprite
// Look up sprite index from config
const itemConfig = ALL_TEMPLATES[itemId as keyof typeof ALL_TEMPLATES];
const texture = itemConfig?.textureKey ?? "items";
const frame = itemConfig?.spriteIndex ?? 0;
const isStandalone = frame === undefined || frame === 0;
const sprite = isStandalone
? this.scene.add.sprite(startX, startY, texture)
: this.scene.add.sprite(startX, startY, texture, frame);
// Scale for standalone 24x24 image should be 1.0 (or matching world scale)
// Other sprites are 16x16.
if (isStandalone) {
sprite.setDisplaySize(16, 16);
} else {
sprite.setScale(1.0);
}
// Use 'items' spritesheet
const sprite = this.scene.add.sprite(startX, startY, texture, frame);
sprite.setDepth(2000);
// Rotate?
const angle = Phaser.Math.Angle.Between(startX, startY, endX, endY);
sprite.setRotation(angle + Math.PI / 4); // Adjust for sprite orientation (diagonal usually)

View File

@@ -47,11 +47,11 @@ export class FxRenderer {
let textStr = amount.toString();
let color = "#ff3333";
let fontSize = "16px";
if (isCrit) {
textStr += "!";
color = "#ffff00";
fontSize = "22px";
textStr += "!";
color = "#ffff00";
fontSize = "22px";
}
const text = this.scene.add.text(screenX, screenY, textStr, {
@@ -63,19 +63,19 @@ export class FxRenderer {
}).setOrigin(0.5, 1).setDepth(200);
if (isBlock) {
const blockText = this.scene.add.text(screenX + 10, screenY - 10, "Blocked", {
fontSize: "10px",
color: "#888888",
fontStyle: "bold"
}).setOrigin(0, 1).setDepth(200);
this.scene.tweens.add({
targets: blockText,
y: screenY - 34,
alpha: 0,
duration: 800,
onComplete: () => blockText.destroy()
});
const blockText = this.scene.add.text(screenX + 10, screenY - 10, "Blocked", {
fontSize: "10px",
color: "#888888",
fontStyle: "bold"
}).setOrigin(0, 1).setDepth(200);
this.scene.tweens.add({
targets: blockText,
y: screenY - 34,
alpha: 0,
duration: 800,
onComplete: () => blockText.destroy()
});
}
this.scene.tweens.add({
@@ -132,7 +132,7 @@ export class FxRenderer {
}
spawnCorpse(x: number, y: number, type: ActorType) {
const textureKey = type === "player" ? "warrior" : type;
const textureKey = type === "player" ? "PriestessSouth" : type;
const corpse = this.scene.add.sprite(
x * TILE_SIZE + TILE_SIZE / 2,
@@ -141,7 +141,23 @@ export class FxRenderer {
0
);
corpse.setDepth(50);
corpse.play(`${textureKey}-die`);
// Use display size for Priestess sprites to match 1 tile
if (textureKey.startsWith("Priestess")) {
corpse.setDisplaySize(TILE_SIZE, TILE_SIZE);
} else {
corpse.setScale(1.0); // Reset to standard scale for spritesheet assets
}
// Only play animation if it's not a priestess sprite
if (!textureKey.startsWith("Priestess")) {
corpse.play(`${textureKey}-die`);
} else {
// Maybe rotate or fade for visual interest since there's no animation
corpse.setAngle(90);
}
this.corpseSprites.push({ sprite: corpse, x, y });
}

View File

@@ -8,7 +8,7 @@ import { ALL_VARIANTS, type ItemVariantId } from "../core/config/ItemVariants";
* inventory, quick slots, and world drops.
*/
export class ItemSpriteFactory {
/**
* Creates an item sprite with optional glow effect for variants.
* Returns a container with the glow (if applicable) and main sprite.
@@ -21,7 +21,7 @@ export class ItemSpriteFactory {
scale: number = 1
): Phaser.GameObjects.Container {
const container = scene.add.container(x, y);
// Create glow effect if item has a variant
if (item.variant) {
const glowColor = this.getGlowColor(item.variant as ItemVariantId);
@@ -30,21 +30,32 @@ export class ItemSpriteFactory {
container.add(glow);
}
}
// Create main item sprite
const sprite = scene.add.sprite(0, 0, item.textureKey, item.spriteIndex);
sprite.setScale(scale);
// Standalone images don't use frame indices
const isStandalone = item.spriteIndex === undefined || item.spriteIndex === 0;
const sprite = isStandalone
? scene.add.sprite(0, 0, item.textureKey)
: scene.add.sprite(0, 0, item.textureKey, item.spriteIndex);
if (isStandalone) {
sprite.setDisplaySize(16 * scale, 16 * scale);
} else {
sprite.setScale(scale);
}
container.add(sprite);
// Add upgrade level badge if item has been upgraded
if (item.upgradeLevel && item.upgradeLevel > 0) {
const badge = this.createUpgradeBadge(scene, item.upgradeLevel, scale);
container.add(badge);
}
return container;
}
/**
* Creates just a sprite (no container) for simpler use cases like drag icons.
* Does not include glow - use createItemSprite for full effect.
@@ -56,11 +67,21 @@ export class ItemSpriteFactory {
y: number,
scale: number = 1
): Phaser.GameObjects.Sprite {
const sprite = scene.add.sprite(x, y, item.textureKey, item.spriteIndex);
sprite.setScale(scale);
const isStandalone = item.spriteIndex === undefined || item.spriteIndex === 0;
const sprite = isStandalone
? scene.add.sprite(x, y, item.textureKey)
: scene.add.sprite(x, y, item.textureKey, item.spriteIndex);
if (isStandalone) {
sprite.setDisplaySize(16 * scale, 16 * scale);
} else {
sprite.setScale(scale);
}
return sprite;
}
/**
* Creates a soft glow effect behind the item using graphics.
* Uses a radial gradient-like effect with multiple circles.
@@ -72,26 +93,26 @@ export class ItemSpriteFactory {
color: number
): Phaser.GameObjects.Graphics {
const glow = scene.add.graphics();
// Base size for the glow (16x16 sprite scaled)
const baseSize = 16 * scale;
const glowRadius = baseSize * 0.8;
// Extract RGB from hex color
const r = (color >> 16) & 0xff;
const g = (color >> 8) & 0xff;
const b = color & 0xff;
// Draw multiple circles with decreasing alpha for soft glow effect
const layers = 5;
for (let i = layers; i >= 1; i--) {
const layerRadius = glowRadius * (i / layers) * 1.2;
const layerAlpha = 0.15 * (1 - (i - 1) / layers);
glow.fillStyle(Phaser.Display.Color.GetColor(r, g, b), layerAlpha);
glow.fillCircle(0, 0, layerRadius);
}
// Add pulsing animation to the glow
scene.tweens.add({
targets: glow,
@@ -103,10 +124,10 @@ export class ItemSpriteFactory {
repeat: -1,
ease: 'Sine.easeInOut'
});
return glow;
}
/**
* Gets the glow color for a variant.
*/
@@ -114,7 +135,7 @@ export class ItemSpriteFactory {
const variant = ALL_VARIANTS[variantId];
return variant?.glowColor ?? null;
}
/**
* Creates a badge displaying the upgrade level (e.g., "+1").
*/
@@ -125,7 +146,7 @@ export class ItemSpriteFactory {
): Phaser.GameObjects.Text {
// Position at top-right corner, slightly inset
const offset = 5 * scale;
// Level text with strong outline for readability without background
const text = scene.add.text(offset, -offset, `+${level}`, {
fontSize: `${9 * scale}px`,
@@ -136,7 +157,7 @@ export class ItemSpriteFactory {
strokeThickness: 3
});
text.setOrigin(0.5);
return text;
}