refactor: remove unused state and widget files in sts-like-viewer
This commit is contained in:
parent
033a8e4a40
commit
85bc4f5400
|
|
@ -1,34 +0,0 @@
|
||||||
import { MutableSignal, mutableSignal, createRNG } from 'boardgame-core';
|
|
||||||
import { createRunState, generatePointCrawlMap, data, type RunState, type ItemData } from 'boardgame-core/samples/slay-the-spire-like';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 全局游戏运行状态 Signal
|
|
||||||
*
|
|
||||||
* 在 App.tsx 中创建为单例,所有场景共享。
|
|
||||||
* 遭遇场景通过读取此 signal 的当前遭遇状态来构建 UI。
|
|
||||||
*/
|
|
||||||
export function createGameState(seed?: number): MutableSignal<RunState> {
|
|
||||||
const actualSeed = seed ?? Date.now();
|
|
||||||
const rng = createRNG(actualSeed);
|
|
||||||
const encounters = data.desert.encounters;
|
|
||||||
const map = generatePointCrawlMap(rng, encounters);
|
|
||||||
const starterItems: ItemData[] = data.desert.items.slice(0, 3);
|
|
||||||
return mutableSignal<RunState>(createRunState(map, starterItems));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取当前遭遇数据(computed getter) */
|
|
||||||
export function currentEncounter(
|
|
||||||
gameState: MutableSignal<RunState>
|
|
||||||
): { nodeId: string; encounter: { name: string; description: string; type: string } } | null {
|
|
||||||
const state = gameState.value;
|
|
||||||
const node = state.map.nodes.get(state.currentNodeId);
|
|
||||||
if (!node || !node.encounter) return null;
|
|
||||||
return {
|
|
||||||
nodeId: node.id,
|
|
||||||
encounter: {
|
|
||||||
type: node.type,
|
|
||||||
name: node.encounter.name,
|
|
||||||
description: node.encounter.description,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
import Phaser from "phaser";
|
|
||||||
|
|
||||||
export interface GridBackgroundRendererOptions {
|
|
||||||
scene: Phaser.Scene;
|
|
||||||
parentContainer: Phaser.GameObjects.Container;
|
|
||||||
cellSize: number;
|
|
||||||
gridGap: number;
|
|
||||||
gridX: number;
|
|
||||||
gridY: number;
|
|
||||||
/** Background fill color for each cell */
|
|
||||||
cellBgColor?: number;
|
|
||||||
/** Border/stroke color for each cell */
|
|
||||||
cellBorderColor?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the static grid background (empty cells with borders).
|
|
||||||
* Separated from item rendering so it can be drawn once and left alone.
|
|
||||||
*/
|
|
||||||
export class GridBackgroundRenderer {
|
|
||||||
private scene: Phaser.Scene;
|
|
||||||
private parentContainer: Phaser.GameObjects.Container;
|
|
||||||
private cellSize: number;
|
|
||||||
private gridGap: number;
|
|
||||||
private gridX: number;
|
|
||||||
private gridY: number;
|
|
||||||
private cellBgColor: number;
|
|
||||||
private cellBorderColor: number;
|
|
||||||
|
|
||||||
private graphics!: Phaser.GameObjects.Graphics;
|
|
||||||
|
|
||||||
constructor(options: GridBackgroundRendererOptions) {
|
|
||||||
this.scene = options.scene;
|
|
||||||
this.parentContainer = options.parentContainer;
|
|
||||||
this.cellSize = options.cellSize;
|
|
||||||
this.gridGap = options.gridGap;
|
|
||||||
this.gridX = options.gridX;
|
|
||||||
this.gridY = options.gridY;
|
|
||||||
this.cellBgColor = options.cellBgColor ?? 0x1a1a2e;
|
|
||||||
this.cellBorderColor = options.cellBorderColor ?? 0x444477;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw the grid background for the given dimensions.
|
|
||||||
* Should be called once during initialization.
|
|
||||||
*/
|
|
||||||
draw(width: number, height: number): void {
|
|
||||||
this.graphics = this.scene.add.graphics();
|
|
||||||
|
|
||||||
for (let y = 0; y < height; y++) {
|
|
||||||
for (let x = 0; x < width; x++) {
|
|
||||||
const px = this.gridX + x * (this.cellSize + this.gridGap);
|
|
||||||
const py = this.gridY + y * (this.cellSize + this.gridGap);
|
|
||||||
|
|
||||||
this.graphics.fillStyle(this.cellBgColor);
|
|
||||||
this.graphics.fillRect(px, py, this.cellSize, this.cellSize);
|
|
||||||
this.graphics.lineStyle(2, this.cellBorderColor);
|
|
||||||
this.graphics.strokeRect(px, py, this.cellSize, this.cellSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.parentContainer.add(this.graphics);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy the graphics object.
|
|
||||||
*/
|
|
||||||
destroy(): void {
|
|
||||||
this.graphics?.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,157 +0,0 @@
|
||||||
import Phaser from "phaser";
|
|
||||||
import {
|
|
||||||
type InventoryItem,
|
|
||||||
type GameItemMeta,
|
|
||||||
} from "boardgame-core/samples/slay-the-spire-like";
|
|
||||||
|
|
||||||
export interface LostItem {
|
|
||||||
id: string;
|
|
||||||
container: Phaser.GameObjects.Container;
|
|
||||||
shape: InventoryItem<GameItemMeta>["shape"];
|
|
||||||
transform: InventoryItem<GameItemMeta>["transform"];
|
|
||||||
meta: InventoryItem<GameItemMeta>["meta"];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LostItemManagerOptions {
|
|
||||||
scene: Phaser.Scene;
|
|
||||||
cellSize: number;
|
|
||||||
gridGap: number;
|
|
||||||
getItemColor: (itemId: string) => number;
|
|
||||||
onLostItemDragStart: (
|
|
||||||
itemId: string,
|
|
||||||
container: Phaser.GameObjects.Container,
|
|
||||||
) => void;
|
|
||||||
isDragging: () => boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages "lost" items — items that were dropped outside valid grid placement.
|
|
||||||
* Renders them as semi-transparent red-bordered containers that can be re-dragged.
|
|
||||||
*/
|
|
||||||
export class LostItemManager {
|
|
||||||
private scene: Phaser.Scene;
|
|
||||||
private cellSize: number;
|
|
||||||
private gridGap: number;
|
|
||||||
private getItemColor: (itemId: string) => number;
|
|
||||||
private onLostItemDragStart: (
|
|
||||||
itemId: string,
|
|
||||||
container: Phaser.GameObjects.Container,
|
|
||||||
) => void;
|
|
||||||
private isDragging: () => boolean;
|
|
||||||
|
|
||||||
private lostItems = new Map<string, LostItem>();
|
|
||||||
|
|
||||||
constructor(options: LostItemManagerOptions) {
|
|
||||||
this.scene = options.scene;
|
|
||||||
this.cellSize = options.cellSize;
|
|
||||||
this.gridGap = options.gridGap;
|
|
||||||
this.getItemColor = options.getItemColor;
|
|
||||||
this.onLostItemDragStart = options.onLostItemDragStart;
|
|
||||||
this.isDragging = options.isDragging;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a visual representation of a lost item at the given position.
|
|
||||||
*/
|
|
||||||
createLostItem(
|
|
||||||
itemId: string,
|
|
||||||
shape: InventoryItem<GameItemMeta>["shape"],
|
|
||||||
transform: InventoryItem<GameItemMeta>["transform"],
|
|
||||||
meta: InventoryItem<GameItemMeta>["meta"],
|
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
): void {
|
|
||||||
const container = this.scene.add.container(x, y).setDepth(500);
|
|
||||||
|
|
||||||
const graphics = this.scene.add.graphics();
|
|
||||||
const color = this.getItemColor(itemId);
|
|
||||||
|
|
||||||
for (let gy = 0; gy < shape.height; gy++) {
|
|
||||||
for (let gx = 0; gx < shape.width; gx++) {
|
|
||||||
if (shape.grid[gy]?.[gx]) {
|
|
||||||
graphics.fillStyle(color, 0.5);
|
|
||||||
graphics.fillRect(
|
|
||||||
gx * (this.cellSize + this.gridGap),
|
|
||||||
gy * (this.cellSize + this.gridGap),
|
|
||||||
this.cellSize - 2,
|
|
||||||
this.cellSize - 2,
|
|
||||||
);
|
|
||||||
graphics.lineStyle(2, 0xff4444);
|
|
||||||
graphics.strokeRect(
|
|
||||||
gx * (this.cellSize + this.gridGap),
|
|
||||||
gy * (this.cellSize + this.gridGap),
|
|
||||||
this.cellSize,
|
|
||||||
this.cellSize,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
container.add(graphics);
|
|
||||||
|
|
||||||
const name = meta?.itemData.name ?? itemId;
|
|
||||||
const text = this.scene.add
|
|
||||||
.text(0, -20, `${name} (lost)`, {
|
|
||||||
fontSize: "12px",
|
|
||||||
color: "#ff4444",
|
|
||||||
fontStyle: "italic",
|
|
||||||
})
|
|
||||||
.setOrigin(0.5);
|
|
||||||
container.add(text);
|
|
||||||
|
|
||||||
const hitRect = new Phaser.Geom.Rectangle(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
this.cellSize,
|
|
||||||
this.cellSize,
|
|
||||||
);
|
|
||||||
container.setInteractive(hitRect, Phaser.Geom.Rectangle.Contains);
|
|
||||||
|
|
||||||
container.on("pointerdown", (pointer: Phaser.Input.Pointer) => {
|
|
||||||
// Guard against stale events firing on destroyed containers
|
|
||||||
if (!container.scene || !container.active) return;
|
|
||||||
if (this.isDragging()) return;
|
|
||||||
if (pointer.button === 0) {
|
|
||||||
this.onLostItemDragStart(itemId, container);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.lostItems.set(itemId, {
|
|
||||||
id: itemId,
|
|
||||||
container,
|
|
||||||
shape,
|
|
||||||
transform: { ...transform },
|
|
||||||
meta,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all lost item IDs.
|
|
||||||
*/
|
|
||||||
getLostItemIds(): string[] {
|
|
||||||
return Array.from(this.lostItems.keys());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a lost item by ID, or undefined if not found.
|
|
||||||
*/
|
|
||||||
getLostItem(itemId: string): LostItem | undefined {
|
|
||||||
return this.lostItems.get(itemId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy and clear all lost items.
|
|
||||||
*/
|
|
||||||
clear(): void {
|
|
||||||
for (const lost of this.lostItems.values()) {
|
|
||||||
lost.container.destroy();
|
|
||||||
}
|
|
||||||
this.lostItems.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy all managed visuals.
|
|
||||||
*/
|
|
||||||
destroy(): void {
|
|
||||||
this.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue