import Phaser from 'phaser'; import type { BoopState, BoopPart } from '@/game'; import { GameHostScene, spawnEffect, type Spawner } from 'boardgame-phaser'; import { BOARD_OFFSET, CELL_SIZE } from './BoardRenderer'; class BoopPartSpawner implements Spawner { constructor(public readonly scene: GameHostScene) {} *getData() { for (const part of Object.values(this.scene.state.pieces)) { if(part.regionId === 'board') yield part; } } getKey(part: BoopPart): string { return part.id; } onUpdate(part: BoopPart, obj: Phaser.GameObjects.Container): void { const [row, col] = part.position; const x = BOARD_OFFSET.x + col * CELL_SIZE + CELL_SIZE / 2; const y = BOARD_OFFSET.y + row * CELL_SIZE + CELL_SIZE / 2; this.scene.tweens.add({ targets: obj, x: x, y: y, duration: 200, ease: 'Power2', }); } onSpawn(part: BoopPart) { const [row, col] = part.position; const x = BOARD_OFFSET.x + col * CELL_SIZE + CELL_SIZE / 2; const y = BOARD_OFFSET.y + row * CELL_SIZE + CELL_SIZE / 2; const container = this.scene.add.container(x, y); const isCat = part.type === 'cat'; const baseColor = part.player === 'white' ? 0xffffff : 0x333333; const strokeColor = part.player === 'white' ? 0x000000 : 0xffffff; const circle = this.scene.add.circle(0, 0, CELL_SIZE * 0.4, baseColor) .setStrokeStyle(3, strokeColor); const text = isCat ? '🐱' : '🐾'; const textObj = this.scene.add.text(0, 0, text, { fontSize: `${isCat ? 40 : 32}px`, fontFamily: 'Arial', }).setOrigin(0.5); container.add([circle, textObj]); container.setScale(0); this.scene.addTweenInterruption(this.scene.tweens.add({ targets: container, scale: 1, duration: 200, ease: 'Back.easeOut', })); return container; } onDespawn(obj: Phaser.GameObjects.Container) { this.scene.tweens.add({ targets: obj, alpha: 0, scale: 0.5, duration: 200, ease: 'Back.easeIn', onComplete: () => obj.destroy(), }); } } export function createPieceSpawner(scene: GameHostScene) { return spawnEffect(new BoopPartSpawner(scene)); }