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.
This commit is contained in:
parent
422ddde200
commit
c97c2c4150
|
|
@ -1,19 +1,20 @@
|
||||||
import { ReactiveScene } from "boardgame-phaser";
|
import { ReactiveScene } from "boardgame-phaser";
|
||||||
import { createButton } from "@/utils/createButton";
|
import { createButton } from "@/utils/createButton";
|
||||||
import { GRID_CONFIG } from "@/config";
|
import { GRID_CONFIG } from "@/config";
|
||||||
import { createInventorySignal, moveItem } from "@/state/inventory";
|
import { createInventorySignal, type InventorySignal } from "@/state/inventory";
|
||||||
import {
|
import { createItemIn, data } from "boardgame-core/samples/slay-the-spire-like";
|
||||||
createItemIn,
|
|
||||||
data,
|
|
||||||
removeItemFromGrid,
|
|
||||||
} from "boardgame-core/samples/slay-the-spire-like";
|
|
||||||
import { createInventoryItemSpawner } from "@/gameobjects/InventoryItemSpawner";
|
import { createInventoryItemSpawner } from "@/gameobjects/InventoryItemSpawner";
|
||||||
import { SceneKey } from "./types";
|
import { SceneKey } from "./types";
|
||||||
|
import { InventorySurface } from "@/state/inventorySurfaceState";
|
||||||
|
|
||||||
export class InventoryTestScene extends ReactiveScene {
|
export class InventoryTestScene extends ReactiveScene {
|
||||||
private inventorySignal = createInventorySignal();
|
private readonly _surfaces: InventorySurface[] = [];
|
||||||
private gridOffsetX = 0;
|
private _leftInv!: InventorySignal;
|
||||||
private gridOffsetY = 0;
|
private _rightInv!: InventorySignal;
|
||||||
|
private _leftGridOffsetX = 0;
|
||||||
|
private _leftGridOffsetY = 0;
|
||||||
|
private _rightGridOffsetX = 0;
|
||||||
|
private _rightGridOffsetY = 0;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super("InventoryTestScene");
|
super("InventoryTestScene");
|
||||||
|
|
@ -23,22 +24,62 @@ export class InventoryTestScene extends ReactiveScene {
|
||||||
super.create();
|
super.create();
|
||||||
|
|
||||||
const { width, height } = this.scale;
|
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._leftInv = createInventorySignal();
|
||||||
this.gridOffsetY =
|
this._rightInv = createInventorySignal();
|
||||||
(height - invHeight * GRID_CONFIG.VIEWER_CELL_SIZE) / 2 + 40;
|
|
||||||
|
|
||||||
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.setupItemSpawner();
|
||||||
|
|
||||||
this.add
|
this.add
|
||||||
.text(
|
.text(
|
||||||
width / 2,
|
width / 2,
|
||||||
30,
|
30,
|
||||||
"Inventory Signal Test (4x6)",
|
"Inventory Signal Test (4x6 x2)",
|
||||||
GRID_CONFIG.TITLE_STYLE,
|
GRID_CONFIG.TITLE_STYLE,
|
||||||
)
|
)
|
||||||
.setOrigin(0.5);
|
.setOrigin(0.5);
|
||||||
|
|
@ -49,24 +90,28 @@ export class InventoryTestScene extends ReactiveScene {
|
||||||
.text(
|
.text(
|
||||||
width / 2,
|
width / 2,
|
||||||
height - 40,
|
height - 40,
|
||||||
"Drag items to move them",
|
"Drag items between inventories",
|
||||||
GRID_CONFIG.SUBTITLE_STYLE,
|
GRID_CONFIG.SUBTITLE_STYLE,
|
||||||
)
|
)
|
||||||
.setOrigin(0.5);
|
.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();
|
const graphics = this.add.graphics();
|
||||||
|
|
||||||
this.addEffect(() => {
|
this.addEffect(() => {
|
||||||
for (let y = 0; y < invHeight; y++) {
|
for (let y = 0; y < invHeight; y++) {
|
||||||
for (let x = 0; x < invWidth; x++) {
|
for (let x = 0; x < invWidth; x++) {
|
||||||
const px = this.gridOffsetX + x * GRID_CONFIG.VIEWER_CELL_SIZE;
|
const px = offsetX + x * GRID_CONFIG.VIEWER_CELL_SIZE;
|
||||||
const py = this.gridOffsetY + y * GRID_CONFIG.VIEWER_CELL_SIZE;
|
const py = offsetY + y * GRID_CONFIG.VIEWER_CELL_SIZE;
|
||||||
|
|
||||||
const isOccupied = this.inventorySignal.value.occupiedCells.has(
|
const isOccupied = inv.value.occupiedCells.has(`${x},${y}`);
|
||||||
`${x},${y}`,
|
|
||||||
);
|
|
||||||
graphics.fillStyle(
|
graphics.fillStyle(
|
||||||
isOccupied
|
isOccupied
|
||||||
? GRID_CONFIG.CELL_OCCUPIED_COLOR
|
? GRID_CONFIG.CELL_OCCUPIED_COLOR
|
||||||
|
|
@ -91,28 +136,7 @@ export class InventoryTestScene extends ReactiveScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupItemSpawner(): void {
|
private setupItemSpawner(): void {
|
||||||
const spawner = createInventoryItemSpawner(
|
const spawner = createInventoryItemSpawner(this, this._surfaces);
|
||||||
this,
|
|
||||||
this.inventorySignal,
|
|
||||||
this.gridOffsetX,
|
|
||||||
this.gridOffsetY,
|
|
||||||
{
|
|
||||||
onMoveItem: (
|
|
||||||
itemId: string,
|
|
||||||
newX: number,
|
|
||||||
newY: number,
|
|
||||||
newRotation: number,
|
|
||||||
) => {
|
|
||||||
return moveItem(
|
|
||||||
this.inventorySignal,
|
|
||||||
itemId,
|
|
||||||
newX,
|
|
||||||
newY,
|
|
||||||
newRotation,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
this.disposables.add(spawner);
|
this.disposables.add(spawner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,29 +155,29 @@ export class InventoryTestScene extends ReactiveScene {
|
||||||
|
|
||||||
createButton({
|
createButton({
|
||||||
scene: this,
|
scene: this,
|
||||||
label: "添加道具",
|
label: "添加道具(左)",
|
||||||
x: width - 300,
|
x: width - 350,
|
||||||
y: 40,
|
y: 40,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
this.addRandomItem();
|
this.addRandomItem(this._leftInv);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
createButton({
|
createButton({
|
||||||
scene: this,
|
scene: this,
|
||||||
label: "移除最后一个",
|
label: "添加道具(右)",
|
||||||
x: width - 150,
|
x: width - 180,
|
||||||
y: 40,
|
y: 40,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
this.removeLastItem();
|
this.addRandomItem(this._rightInv);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private addRandomItem(): void {
|
private addRandomItem(inv: InventorySignal): void {
|
||||||
const items = data.desert.getItems();
|
const items = data.desert.getItems();
|
||||||
|
|
||||||
this.inventorySignal.produce((inventory) => {
|
inv.produce((inventory) => {
|
||||||
const usedIndices = new Set<number>();
|
const usedIndices = new Set<number>();
|
||||||
|
|
||||||
for (const item of inventory.items.values()) {
|
for (const item of inventory.items.values()) {
|
||||||
|
|
@ -177,14 +201,4 @@ export class InventoryTestScene extends ReactiveScene {
|
||||||
createItemIn(inventory, id, itemData);
|
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,8 @@ export function sceneToInventory(
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
): { x: number; y: number } | null {
|
): { x: number; y: number } | null {
|
||||||
const invX = Math.round(x / surface.cellSize);
|
const invX = Math.round((x - surface.gridOffsetX) / surface.cellSize);
|
||||||
const invY = Math.round(y / surface.cellSize);
|
const invY = Math.round((y - surface.gridOffsetY) / surface.cellSize);
|
||||||
|
|
||||||
const { width, height } = surface.invSignal.peek();
|
const { width, height } = surface.invSignal.peek();
|
||||||
if (invX < 0 || invY < 0 || invX >= width || invY >= height) {
|
if (invX < 0 || invY < 0 || invX >= width || invY >= height) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue