import Phaser from 'phaser'; import { ReactiveScene } from 'boardgame-phaser'; import { parseShapeString, heroItemFighter1Data, type ParsedShape } from 'boardgame-core/samples/slay-the-spire-like'; export class ShapeViewerScene extends ReactiveScene { private readonly CELL_SIZE = 40; private readonly ITEMS_PER_ROW = 4; private currentIndex = 0; private currentRotation = 0; private currentFlipX = false; private currentFlipY = false; constructor() { super('ShapeViewerScene'); } create(): void { super.create(); this.drawShapeViewer(); this.createControls(); } private drawShapeViewer(): void { this.children.removeAll(); const { width, height } = this.scale; // Title this.add.text(width / 2, 30, 'Shape Viewer - Item Shapes', { fontSize: '24px', color: '#ffffff', fontStyle: 'bold', }).setOrigin(0.5); // Draw all shapes in a grid this.drawAllShapes(); } private drawAllShapes(): void { const { width } = this.scale; const startY = 80; const spacingX = 220; const spacingY = 140; // Show first 12 items for clarity const itemsToShow = heroItemFighter1Data.slice(0, 12); for (let i = 0; i < itemsToShow.length; i++) { const data = itemsToShow[i]; const shape = parseShapeString(data.shape); const col = i % this.ITEMS_PER_ROW; const row = Math.floor(i / this.ITEMS_PER_ROW); const x = 60 + col * spacingX; const y = startY + row * spacingY; this.drawSingleShape(x, y, data, shape); } } private drawSingleShape(startX: number, startY: number, data: any, shape: ParsedShape): void { const graphics = this.add.graphics(); // Draw shape background const shapeWidth = shape.width * this.CELL_SIZE; const shapeHeight = shape.height * this.CELL_SIZE; // Title - item name this.add.text(startX + shapeWidth / 2, startY - 20, data.name, { fontSize: '14px', color: '#ffffff', fontStyle: 'bold', }).setOrigin(0.5); // Draw shape cells for (let y = 0; y < shape.height; y++) { for (let x = 0; x < shape.width; x++) { if (shape.grid[y]?.[x]) { const px = startX + x * this.CELL_SIZE; const py = startY + y * this.CELL_SIZE; // Determine if this is the origin cell const isOrigin = x === shape.originX && y === shape.originY; const color = isOrigin ? 0x88cc44 : 0x4488cc; graphics.fillStyle(color); graphics.fillRect(px + 1, py + 1, this.CELL_SIZE - 2, this.CELL_SIZE - 2); graphics.lineStyle(2, 0xffffff); graphics.strokeRect(px, py, this.CELL_SIZE, this.CELL_SIZE); // Mark origin with 'O' if (isOrigin) { this.add.text(px + this.CELL_SIZE / 2, py + this.CELL_SIZE / 2, 'O', { fontSize: '16px', color: '#ffffff', fontStyle: 'bold', }).setOrigin(0.5); } } } } // Shape string this.add.text(startX + shapeWidth / 2, startY + shapeHeight + 10, `形状: ${data.shape}`, { fontSize: '11px', color: '#aaaaaa', }).setOrigin(0.5); // Type and cost this.add.text(startX + shapeWidth / 2, startY + shapeHeight + 28, `类型: ${data.type} | 费用: ${data.costCount} ${data.costType}`, { fontSize: '11px', color: '#cccccc', }).setOrigin(0.5); // Description this.add.text(startX + shapeWidth / 2, startY + shapeHeight + 46, data.desc, { fontSize: '10px', color: '#888888', wordWrap: { width: shapeWidth }, }).setOrigin(0.5); } private createControls(): void { const { width, height } = this.scale; // Back button this.createButton('返回菜单', 100, height - 40, () => { this.scene.start('IndexScene'); }); // Info text this.add.text(width / 2, height - 40, `Showing first 12 items | Green = Origin | Blue = Normal`, { fontSize: '14px', color: '#aaaaaa', }).setOrigin(0.5); } private createButton(label: string, x: number, y: number, onClick: () => void): void { const buttonWidth = 120; const buttonHeight = 36; const bg = this.add.rectangle(x, y, buttonWidth, buttonHeight, 0x444466) .setStrokeStyle(2, 0x7777aa) .setInteractive({ useHandCursor: true }); const text = this.add.text(x, y, label, { fontSize: '16px', color: '#ffffff', }).setOrigin(0.5); bg.on('pointerover', () => { bg.setFillStyle(0x555588); text.setScale(1.05); }); bg.on('pointerout', () => { bg.setFillStyle(0x444466); text.setScale(1); }); bg.on('pointerdown', onClick); } }