import * as Phaser from "phaser"; export interface EntityData { x: number; y: number; direction: string; tint?: number; } /** * 精灵实体渲染器 * 用 Phaser Image 精灵替代 Graphics API 手绘 */ export class SpriteEntityRenderer { private scene: any; private textureKey: string; private defaultFacing: "up" | "down"; private sprites: Phaser.GameObjects.Image[] = []; /** * @param scene - Phaser 场景引用 * @param textureKey - 精灵纹理 key(在 Preloader 中加载的 key) * @param defaultFacing - 图片默认朝向("up" 或 "down") */ constructor(scene: any, textureKey: string, defaultFacing: "up" | "down" = "down") { this.scene = scene; this.textureKey = textureKey; this.defaultFacing = defaultFacing; } /** * 渲染所有实体(先清除旧精灵,再创建新精灵) */ renderAll(entities: EntityData[], container: Phaser.GameObjects.Container): void { this.clear(); for (const entity of entities) { const { x: cx, y: cy } = this.cellCenter(entity.x, entity.y); const angle = this.directionToAngle(entity.direction); const targetSize = this.scene.cellSize * 0.8; const sprite = this.scene.add.image(cx, cy, this.textureKey) as Phaser.GameObjects.Image; sprite.setOrigin(0.5); sprite.setRotation(angle); const scale = Math.min(targetSize / sprite.width, targetSize / sprite.height); sprite.setScale(scale); if (entity.tint !== undefined) { sprite.setTint(entity.tint); } container.add(sprite); this.sprites.push(sprite); } } /** * 清除所有管理的精灵 */ clear(): void { for (const sprite of this.sprites) { sprite.destroy(); } this.sprites = []; } /** * 创建临时精灵(用于消除动画) * 调用方负责销毁(通常通过销毁容器) */ createTempSprite( x: number, y: number, direction: string, container: Phaser.GameObjects.Container, ): Phaser.GameObjects.Image { const angle = this.directionToAngle(direction); const targetSize = this.scene.cellSize * 0.8; const sprite = this.scene.add.image(x, y, this.textureKey) as Phaser.GameObjects.Image; sprite.setOrigin(0.5); sprite.setRotation(angle); const scale = Math.min(targetSize / sprite.width, targetSize / sprite.height); sprite.setScale(scale); container.add(sprite); return sprite; } /** * 方向转旋转角度 * 根据图片默认朝向计算旋转值 */ directionToAngle(direction: string): number { if (this.defaultFacing === "down") { switch (direction) { case "down": return 0; case "up": return Math.PI; case "left": return Math.PI / 2; case "right": return -Math.PI / 2; default: return 0; } } else { // defaultFacing === "up" switch (direction) { case "up": return 0; case "down": return Math.PI; case "right": return Math.PI / 2; case "left": return -Math.PI / 2; default: return 0; } } } /** * 计算格子中心坐标 */ private cellCenter(col: number, row: number): { x: number; y: number } { return { x: col * this.scene.cellWidth + this.scene.cellWidth / 2, y: row * this.scene.cellHeight + this.scene.cellHeight / 2, }; } }