feat: create item variants
This commit is contained in:
@@ -7,6 +7,7 @@ import { ALL_TEMPLATES } from "../core/config/Items";
|
||||
import { FovManager } from "./FovManager";
|
||||
import { MinimapRenderer } from "./MinimapRenderer";
|
||||
import { FxRenderer } from "./FxRenderer";
|
||||
import { ItemSpriteFactory } from "./ItemSpriteFactory";
|
||||
|
||||
export class DungeonRenderer {
|
||||
private scene: Phaser.Scene;
|
||||
@@ -16,7 +17,7 @@ export class DungeonRenderer {
|
||||
private playerSprite?: Phaser.GameObjects.Sprite;
|
||||
private enemySprites: Map<EntityId, Phaser.GameObjects.Sprite> = new Map();
|
||||
private orbSprites: Map<EntityId, Phaser.GameObjects.Arc> = new Map();
|
||||
private itemSprites: Map<EntityId, Phaser.GameObjects.Sprite> = new Map();
|
||||
private itemSprites: Map<EntityId, Phaser.GameObjects.Container> = new Map();
|
||||
|
||||
private fovManager: FovManager;
|
||||
private minimapRenderer: MinimapRenderer;
|
||||
@@ -228,19 +229,20 @@ export class DungeonRenderer {
|
||||
if (!isVis) continue;
|
||||
|
||||
activeItemIds.add(a.id);
|
||||
let itemSprite = this.itemSprites.get(a.id);
|
||||
if (!itemSprite) {
|
||||
itemSprite = this.scene.add.sprite(0, 0, a.item.textureKey, a.item.spriteIndex);
|
||||
itemSprite.setDepth(40);
|
||||
this.itemSprites.set(a.id, itemSprite);
|
||||
let itemContainer = this.itemSprites.get(a.id);
|
||||
if (!itemContainer) {
|
||||
// Use ItemSpriteFactory to create sprite with optional glow
|
||||
itemContainer = ItemSpriteFactory.createItemSprite(this.scene, a.item, 0, 0, 1);
|
||||
itemContainer.setDepth(40);
|
||||
this.itemSprites.set(a.id, itemContainer);
|
||||
}
|
||||
const tx = a.pos.x * TILE_SIZE + TILE_SIZE / 2;
|
||||
const ty = a.pos.y * TILE_SIZE + TILE_SIZE / 2;
|
||||
itemSprite.setPosition(tx, ty);
|
||||
itemSprite.setVisible(true);
|
||||
itemContainer.setPosition(tx, ty);
|
||||
itemContainer.setVisible(true);
|
||||
|
||||
// bobbing effect?
|
||||
itemSprite.y += Math.sin(this.scene.time.now / 300) * 2;
|
||||
// bobbing effect on the container
|
||||
itemContainer.y += Math.sin(this.scene.time.now / 300) * 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
118
src/rendering/ItemSpriteFactory.ts
Normal file
118
src/rendering/ItemSpriteFactory.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import Phaser from "phaser";
|
||||
import type { Item } from "../core/types";
|
||||
import { ALL_VARIANTS, type ItemVariantId } from "../core/config/ItemVariants";
|
||||
|
||||
/**
|
||||
* Factory for creating item sprites with optional variant glow effects.
|
||||
* Centralizes item rendering logic to ensure consistent glow styling across
|
||||
* 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.
|
||||
*/
|
||||
static createItemSprite(
|
||||
scene: Phaser.Scene,
|
||||
item: Item,
|
||||
x: number,
|
||||
y: number,
|
||||
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);
|
||||
if (glowColor !== null) {
|
||||
const glow = this.createGlow(scene, item, scale, glowColor);
|
||||
container.add(glow);
|
||||
}
|
||||
}
|
||||
|
||||
// Create main item sprite
|
||||
const sprite = scene.add.sprite(0, 0, item.textureKey, item.spriteIndex);
|
||||
sprite.setScale(scale);
|
||||
container.add(sprite);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates just a sprite (no container) for simpler use cases like drag icons.
|
||||
* Does not include glow - use createItemSprite for full effect.
|
||||
*/
|
||||
static createSimpleSprite(
|
||||
scene: Phaser.Scene,
|
||||
item: Item,
|
||||
x: number,
|
||||
y: number,
|
||||
scale: number = 1
|
||||
): Phaser.GameObjects.Sprite {
|
||||
const sprite = scene.add.sprite(x, y, item.textureKey, item.spriteIndex);
|
||||
sprite.setScale(scale);
|
||||
return sprite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a soft glow effect behind the item using graphics.
|
||||
* Uses a radial gradient-like effect with multiple circles.
|
||||
*/
|
||||
private static createGlow(
|
||||
scene: Phaser.Scene,
|
||||
_item: Item,
|
||||
scale: number,
|
||||
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,
|
||||
alpha: { from: 0.7, to: 1.0 },
|
||||
scaleX: { from: 0.9, to: 1.1 },
|
||||
scaleY: { from: 0.9, to: 1.1 },
|
||||
duration: 800,
|
||||
yoyo: true,
|
||||
repeat: -1,
|
||||
ease: 'Sine.easeInOut'
|
||||
});
|
||||
|
||||
return glow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the glow color for a variant.
|
||||
*/
|
||||
private static getGlowColor(variantId: ItemVariantId): number | null {
|
||||
const variant = ALL_VARIANTS[variantId];
|
||||
return variant?.glowColor ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an item has a variant with a glow.
|
||||
*/
|
||||
static hasGlow(item: Item): boolean {
|
||||
return !!item.variant && !!ALL_VARIANTS[item.variant as ItemVariantId];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user