From 0ecef16a4a568fc46c7adf1388f58c711e2b3b7f Mon Sep 17 00:00:00 2001 From: hypercross Date: Fri, 17 Apr 2026 19:45:34 +0800 Subject: [PATCH] fix: inventory interaction --- .../src/widgets/InventoryWidget.ts | 85 +++++++++++++++++-- 1 file changed, 77 insertions(+), 8 deletions(-) diff --git a/packages/sts-like-viewer/src/widgets/InventoryWidget.ts b/packages/sts-like-viewer/src/widgets/InventoryWidget.ts index d268b91..962745e 100644 --- a/packages/sts-like-viewer/src/widgets/InventoryWidget.ts +++ b/packages/sts-like-viewer/src/widgets/InventoryWidget.ts @@ -33,11 +33,16 @@ interface DragState { itemMeta: InventoryItem['meta']; ghostContainer: Phaser.GameObjects.Container; previewGraphics: Phaser.GameObjects.Graphics; + dragOffsetX: number; + dragOffsetY: number; } interface LostItem { id: string; container: Phaser.GameObjects.Container; + shape: InventoryItem['shape']; + transform: InventoryItem['transform']; + meta: InventoryItem['meta']; } export class InventoryWidget { @@ -76,13 +81,13 @@ export class InventoryWidget { this.container = this.scene.add.container(options.x, options.y); + this.pointerMoveHandler = this.onPointerMove.bind(this); + this.pointerUpHandler = this.onPointerUp.bind(this); + this.drawGridBackground(inventory.width, inventory.height, gridW, gridH); this.drawItems(); this.setupInput(); - this.pointerMoveHandler = this.onPointerMove.bind(this); - this.pointerUpHandler = this.onPointerUp.bind(this); - this.scene.events.once('shutdown', () => this.destroy()); } @@ -205,7 +210,14 @@ export class InventoryWidget { }); this.removeItemVisuals(itemId); - const ghostContainer = this.scene.add.container(pointer.x, pointer.y).setDepth(1000); + const cells = this.getItemCells(item); + const firstCell = cells[0]; + const itemWorldX = this.container.x + this.gridX + firstCell.x * (this.cellSize + this.gridGap); + const itemWorldY = this.container.y + this.gridY + firstCell.y * (this.cellSize + this.gridGap); + const dragOffsetX = pointer.x - itemWorldX; + const dragOffsetY = pointer.y - itemWorldY; + + const ghostContainer = this.scene.add.container(itemWorldX, itemWorldY).setDepth(1000); const ghostGraphics = this.scene.add.graphics(); const color = this.colorMap.get(itemId) ?? 0x888888; @@ -230,6 +242,42 @@ export class InventoryWidget { itemMeta: item.meta, ghostContainer, previewGraphics, + dragOffsetX, + dragOffsetY, + }; + } + + private startLostItemDrag(itemId: string, pointer: Phaser.Input.Pointer): void { + const lost = this.lostItems.get(itemId); + if (!lost) return; + + lost.container.destroy(); + this.lostItems.delete(itemId); + + const ghostContainer = this.scene.add.container(pointer.x, pointer.y).setDepth(1000); + const ghostGraphics = this.scene.add.graphics(); + const color = this.colorMap.get(itemId) ?? 0x888888; + + const cells = transformShape(lost.shape, lost.transform); + for (const cell of cells) { + ghostGraphics.fillStyle(color, 0.7); + ghostGraphics.fillRect(cell.x * (this.cellSize + this.gridGap), cell.y * (this.cellSize + this.gridGap), this.cellSize - 2, this.cellSize - 2); + ghostGraphics.lineStyle(2, 0xffffff); + ghostGraphics.strokeRect(cell.x * (this.cellSize + this.gridGap), cell.y * (this.cellSize + this.gridGap), this.cellSize, this.cellSize); + } + ghostContainer.add(ghostGraphics); + + const previewGraphics = this.scene.add.graphics().setDepth(999).setAlpha(0.5); + + this.dragState = { + itemId, + itemShape: lost.shape, + itemTransform: { ...lost.transform, offset: { ...lost.transform.offset } }, + itemMeta: lost.meta, + ghostContainer, + previewGraphics, + dragOffsetX: 0, + dragOffsetY: 0, }; } @@ -265,9 +313,9 @@ export class InventoryWidget { private onPointerMove(pointer: Phaser.Input.Pointer): void { if (!this.dragState) return; - this.dragState.ghostContainer.setPosition(pointer.x, pointer.y); + this.dragState.ghostContainer.setPosition(pointer.x - this.dragState.dragOffsetX, pointer.y - this.dragState.dragOffsetY); - const gridCell = this.getWorldGridCell(pointer.x, pointer.y); + const gridCell = this.getWorldGridCell(pointer.x - this.dragState.dragOffsetX, pointer.y - this.dragState.dragOffsetY); this.dragState.previewGraphics.clear(); if (gridCell) { @@ -298,7 +346,7 @@ export class InventoryWidget { private onPointerUp(pointer: Phaser.Input.Pointer): void { if (!this.dragState) return; - const gridCell = this.getWorldGridCell(pointer.x, pointer.y); + const gridCell = this.getWorldGridCell(pointer.x - this.dragState.dragOffsetX, pointer.y - this.dragState.dragOffsetY); const inventory = this.getInventory(); this.dragState.ghostContainer.destroy(); @@ -345,6 +393,10 @@ export class InventoryWidget { const cellX = Math.floor(localX / (this.cellSize + this.gridGap)); const cellY = Math.floor(localY / (this.cellSize + this.gridGap)); + if (cellX < 0 || cellY < 0 || cellX >= this.getInventory().width || cellY >= this.getInventory().height) { + return null; + } + return { x: cellX, y: cellY }; } @@ -376,7 +428,24 @@ export class InventoryWidget { }).setOrigin(0.5); container.add(text); - this.lostItems.set(this.dragState.itemId, { id: this.dragState.itemId, container }); + 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) => { + if (this.isLocked) return; + if (this.dragState) return; + if (pointer.button === 0) { + this.startLostItemDrag(this.dragState!.itemId, pointer); + } + }); + + this.lostItems.set(this.dragState.itemId, { + id: this.dragState.itemId, + container, + shape: this.dragState.itemShape, + transform: { ...this.dragState.itemTransform }, + meta: this.dragState.itemMeta, + }); } private removeItemVisuals(itemId: string): void {