From c97c2c41506aaa46c79ca6d2024a5553568d6ed3 Mon Sep 17 00:00:00 2001 From: hypercross Date: Tue, 21 Apr 2026 16:48:45 +0800 Subject: [PATCH] feat(sts-viewer): support multiple inventory surfaces Refactor `InventoryTestScene` to support multiple inventory signals simultaneously. This introduces `InventorySurface` to manage positioning and signal mapping for multiple grids, allowing for testing item movement between different inventory areas. --- .../src/scenes/InventoryTestScene.ts | 142 ++++++++++-------- .../src/state/inventorySurfaceState.ts | 4 +- 2 files changed, 80 insertions(+), 66 deletions(-) diff --git a/packages/sts-like-viewer/src/scenes/InventoryTestScene.ts b/packages/sts-like-viewer/src/scenes/InventoryTestScene.ts index 16819de..851adf9 100644 --- a/packages/sts-like-viewer/src/scenes/InventoryTestScene.ts +++ b/packages/sts-like-viewer/src/scenes/InventoryTestScene.ts @@ -1,19 +1,20 @@ import { ReactiveScene } from "boardgame-phaser"; import { createButton } from "@/utils/createButton"; import { GRID_CONFIG } from "@/config"; -import { createInventorySignal, moveItem } from "@/state/inventory"; -import { - createItemIn, - data, - removeItemFromGrid, -} from "boardgame-core/samples/slay-the-spire-like"; +import { createInventorySignal, type InventorySignal } from "@/state/inventory"; +import { createItemIn, data } from "boardgame-core/samples/slay-the-spire-like"; import { createInventoryItemSpawner } from "@/gameobjects/InventoryItemSpawner"; import { SceneKey } from "./types"; +import { InventorySurface } from "@/state/inventorySurfaceState"; export class InventoryTestScene extends ReactiveScene { - private inventorySignal = createInventorySignal(); - private gridOffsetX = 0; - private gridOffsetY = 0; + private readonly _surfaces: InventorySurface[] = []; + private _leftInv!: InventorySignal; + private _rightInv!: InventorySignal; + private _leftGridOffsetX = 0; + private _leftGridOffsetY = 0; + private _rightGridOffsetX = 0; + private _rightGridOffsetY = 0; constructor() { super("InventoryTestScene"); @@ -23,22 +24,62 @@ export class InventoryTestScene extends ReactiveScene { super.create(); const { width, height } = this.scale; - const inventory = this.inventorySignal.value; - const invWidth = inventory.width; - const invHeight = inventory.height; - this.gridOffsetX = (width - invWidth * GRID_CONFIG.VIEWER_CELL_SIZE) / 2; - this.gridOffsetY = - (height - invHeight * GRID_CONFIG.VIEWER_CELL_SIZE) / 2 + 40; + this._leftInv = createInventorySignal(); + this._rightInv = createInventorySignal(); - this.drawGrid(invWidth, invHeight); + const invWidth = 4; + const invHeight = 6; + const cellSize = GRID_CONFIG.VIEWER_CELL_SIZE; + const gap = 80; + + this._leftGridOffsetX = + (width / 2 - gap / 2) / 2 - (invWidth * cellSize) / 2; + this._leftGridOffsetY = (height - invHeight * cellSize) / 2 + 40; + + this._rightGridOffsetX = + width / 2 + + gap / 2 + + (width / 2 - gap / 2) / 2 - + (invWidth * cellSize) / 2; + this._rightGridOffsetY = (height - invHeight * cellSize) / 2 + 40; + + this._surfaces.push( + { + invSignal: this._leftInv, + gridOffsetX: this._leftGridOffsetX, + gridOffsetY: this._leftGridOffsetY, + cellSize, + }, + { + invSignal: this._rightInv, + gridOffsetX: this._rightGridOffsetX, + gridOffsetY: this._rightGridOffsetY, + cellSize, + }, + ); + + this.drawGrid( + this._leftInv, + invWidth, + invHeight, + this._leftGridOffsetX, + this._leftGridOffsetY, + ); + this.drawGrid( + this._rightInv, + invWidth, + invHeight, + this._rightGridOffsetX, + this._rightGridOffsetY, + ); this.setupItemSpawner(); this.add .text( width / 2, 30, - "Inventory Signal Test (4x6)", + "Inventory Signal Test (4x6 x2)", GRID_CONFIG.TITLE_STYLE, ) .setOrigin(0.5); @@ -49,24 +90,28 @@ export class InventoryTestScene extends ReactiveScene { .text( width / 2, height - 40, - "Drag items to move them", + "Drag items between inventories", GRID_CONFIG.SUBTITLE_STYLE, ) .setOrigin(0.5); } - private drawGrid(invWidth: number, invHeight: number): void { + private drawGrid( + inv: InventorySignal, + invWidth: number, + invHeight: number, + offsetX: number, + offsetY: number, + ): void { const graphics = this.add.graphics(); this.addEffect(() => { for (let y = 0; y < invHeight; y++) { for (let x = 0; x < invWidth; x++) { - const px = this.gridOffsetX + x * GRID_CONFIG.VIEWER_CELL_SIZE; - const py = this.gridOffsetY + y * GRID_CONFIG.VIEWER_CELL_SIZE; + const px = offsetX + x * GRID_CONFIG.VIEWER_CELL_SIZE; + const py = offsetY + y * GRID_CONFIG.VIEWER_CELL_SIZE; - const isOccupied = this.inventorySignal.value.occupiedCells.has( - `${x},${y}`, - ); + const isOccupied = inv.value.occupiedCells.has(`${x},${y}`); graphics.fillStyle( isOccupied ? GRID_CONFIG.CELL_OCCUPIED_COLOR @@ -91,28 +136,7 @@ export class InventoryTestScene extends ReactiveScene { } private setupItemSpawner(): void { - const spawner = createInventoryItemSpawner( - this, - this.inventorySignal, - this.gridOffsetX, - this.gridOffsetY, - { - onMoveItem: ( - itemId: string, - newX: number, - newY: number, - newRotation: number, - ) => { - return moveItem( - this.inventorySignal, - itemId, - newX, - newY, - newRotation, - ); - }, - }, - ); + const spawner = createInventoryItemSpawner(this, this._surfaces); this.disposables.add(spawner); } @@ -131,29 +155,29 @@ export class InventoryTestScene extends ReactiveScene { createButton({ scene: this, - label: "添加道具", - x: width - 300, + label: "添加道具(左)", + x: width - 350, y: 40, onClick: () => { - this.addRandomItem(); + this.addRandomItem(this._leftInv); }, }); createButton({ scene: this, - label: "移除最后一个", - x: width - 150, + label: "添加道具(右)", + x: width - 180, y: 40, onClick: () => { - this.removeLastItem(); + this.addRandomItem(this._rightInv); }, }); } - private addRandomItem(): void { + private addRandomItem(inv: InventorySignal): void { const items = data.desert.getItems(); - this.inventorySignal.produce((inventory) => { + inv.produce((inventory) => { const usedIndices = new Set(); for (const item of inventory.items.values()) { @@ -177,14 +201,4 @@ export class InventoryTestScene extends ReactiveScene { createItemIn(inventory, id, itemData); }); } - - private removeLastItem(): void { - this.inventorySignal.produce((inventory) => { - const ids = [...inventory.items.keys()]; - const last = ids.length > 0 ? ids[ids.length - 1] : null; - console.log({ last }); - if (!last) return; - removeItemFromGrid(inventory, last); - }); - } } diff --git a/packages/sts-like-viewer/src/state/inventorySurfaceState.ts b/packages/sts-like-viewer/src/state/inventorySurfaceState.ts index 47ac3fc..91f6941 100644 --- a/packages/sts-like-viewer/src/state/inventorySurfaceState.ts +++ b/packages/sts-like-viewer/src/state/inventorySurfaceState.ts @@ -45,8 +45,8 @@ export function sceneToInventory( x: number, y: number, ): { x: number; y: number } | null { - const invX = Math.round(x / surface.cellSize); - const invY = Math.round(y / surface.cellSize); + const invX = Math.round((x - surface.gridOffsetX) / surface.cellSize); + const invY = Math.round((y - surface.gridOffsetY) / surface.cellSize); const { width, height } = surface.invSignal.peek(); if (invX < 0 || invY < 0 || invX >= width || invY >= height) {