diff --git a/packages/sts-like-viewer/src/ui/App.tsx b/packages/sts-like-viewer/src/ui/App.tsx index 959f3c1..10fde21 100644 --- a/packages/sts-like-viewer/src/ui/App.tsx +++ b/packages/sts-like-viewer/src/ui/App.tsx @@ -1,13 +1,13 @@ -import { h } from 'preact'; -import { PhaserGame, PhaserScene } from 'boardgame-phaser'; -import { useMemo } from 'preact/hooks'; -import { IndexScene } from '@/scenes/IndexScene'; -import { MapViewerScene } from '@/scenes/MapViewerScene'; -import { GridViewerScene } from '@/scenes/GridViewerScene'; -import { ShapeViewerScene } from '@/scenes/ShapeViewerScene'; -import { GameFlowScene } from '@/scenes/GameFlowScene'; -import { PlaceholderEncounterScene } from '@/scenes/PlaceholderEncounterScene'; -import { createGameState } from '@/state/gameState'; +import { h } from "preact"; +import { PhaserGame, PhaserScene } from "boardgame-phaser"; +import { useMemo } from "preact/hooks"; +import { IndexScene } from "@/scenes/IndexScene"; +import { MapViewerScene } from "@/scenes/MapViewerScene"; +import { GridViewerScene } from "@/scenes/GridViewerScene"; +import { ShapeViewerScene } from "@/scenes/ShapeViewerScene"; +import { GameFlowScene } from "@/scenes/GameFlowScene"; +import { PlaceholderEncounterScene } from "@/scenes/PlaceholderEncounterScene"; +import { createGameState } from "@/state/gameState"; // 全局游戏状态单例 const gameState = createGameState(); @@ -18,18 +18,36 @@ export default function App() { const gridViewerScene = useMemo(() => new GridViewerScene(), []); const shapeViewerScene = useMemo(() => new ShapeViewerScene(), []); const gameFlowScene = useMemo(() => new GameFlowScene(gameState), []); - const placeholderEncounterScene = useMemo(() => new PlaceholderEncounterScene(gameState), []); + const placeholderEncounterScene = useMemo( + () => new PlaceholderEncounterScene(gameState), + [], + ); return (
- - - - - - - + + + + + + +
diff --git a/packages/sts-like-viewer/src/widgets/DragController.ts b/packages/sts-like-viewer/src/widgets/DragController.ts index 4a81b0e..f91ae31 100644 --- a/packages/sts-like-viewer/src/widgets/DragController.ts +++ b/packages/sts-like-viewer/src/widgets/DragController.ts @@ -4,19 +4,19 @@ import { type GameItemMeta, type GridInventory, validatePlacement, - placeItem, transformShape, } from "boardgame-core/samples/slay-the-spire-like"; +import { dragDropEventEffect, DragDropEventType } from "boardgame-phaser"; +import { DisposableBag } from "boardgame-phaser"; -export interface DragState { +export interface DragSession { itemId: string; itemShape: InventoryItem["shape"]; itemTransform: InventoryItem["transform"]; itemMeta: InventoryItem["meta"]; ghostContainer: Phaser.GameObjects.Container; previewGraphics: Phaser.GameObjects.Graphics; - dragOffsetX: number; - dragOffsetY: number; + disposables: DisposableBag; } export interface DragControllerOptions { @@ -28,21 +28,20 @@ export interface DragControllerOptions { gridY: number; getInventory: () => GridInventory; getItemColor: (itemId: string) => number; - getItemCells: ( - item: InventoryItem, - ) => { x: number; y: number }[]; onPlaceItem: (item: InventoryItem) => void; onCreateLostItem: ( itemId: string, shape: InventoryItem["shape"], transform: InventoryItem["transform"], meta: InventoryItem["meta"], + x: number, + y: number, ) => void; } /** - * Manages drag-and-drop state and logic for inventory items. - * Handles ghost visuals, placement preview, rotation, and validation. + * Event-driven drag controller using dragDropEventEffect from boardgame-phaser. + * Manages ghost visuals, placement preview, rotation, and validation. */ export class DragController { private scene: Phaser.Scene; @@ -53,18 +52,17 @@ export class DragController { private gridY: number; private getInventory: () => GridInventory; private getItemColor: (itemId: string) => number; - private getItemCells: ( - item: InventoryItem, - ) => { x: number; y: number }[]; private onPlaceItem: (item: InventoryItem) => void; private onCreateLostItem: ( itemId: string, shape: InventoryItem["shape"], transform: InventoryItem["transform"], meta: InventoryItem["meta"], + x: number, + y: number, ) => void; - private dragState: DragState | null = null; + private activeSession: DragSession | null = null; constructor(options: DragControllerOptions) { this.scene = options.scene; @@ -75,66 +73,44 @@ export class DragController { this.gridY = options.gridY; this.getInventory = options.getInventory; this.getItemColor = options.getItemColor; - this.getItemCells = options.getItemCells; this.onPlaceItem = options.onPlaceItem; this.onCreateLostItem = options.onCreateLostItem; } /** - * Start dragging an item from the inventory. + * Start a drag session for an inventory item. + * Uses dragDropEventEffect for pointer tracking and event emission. */ - startDrag(itemId: string, pointer: Phaser.Input.Pointer): void { - const inventory = this.getInventory(); - const item = inventory.items.get(itemId); - if (!item) return; - + startDrag( + itemId: string, + item: InventoryItem, + itemContainer: Phaser.GameObjects.Container, + ): () => void { const cells = this.getItemCells(item); const firstCell = cells[0]; - const itemWorldX = + const worldX = this.container.x + this.gridX + firstCell.x * (this.cellSize + this.gridGap); - const itemWorldY = + const worldY = 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.getItemColor(itemId); - - for (let y = 0; y < item.shape.height; y++) { - for (let x = 0; x < item.shape.width; x++) { - if (item.shape.grid[y]?.[x]) { - ghostGraphics.fillStyle(color, 0.7); - ghostGraphics.fillRect( - x * (this.cellSize + this.gridGap), - y * (this.cellSize + this.gridGap), - this.cellSize - 2, - this.cellSize - 2, - ); - ghostGraphics.lineStyle(2, 0xffffff); - ghostGraphics.strokeRect( - x * (this.cellSize + this.gridGap), - y * (this.cellSize + this.gridGap), - this.cellSize, - this.cellSize, - ); - } - } - } - ghostContainer.add(ghostGraphics); + const ghostContainer = this.createGhostContainer( + worldX, + worldY, + item.shape, + item.transform, + this.getItemColor(itemId), + ); const previewGraphics = this.scene.add .graphics() .setDepth(999) .setAlpha(0.5); - this.dragState = { + const disposables = new DisposableBag(); + const session: DragSession = { itemId, itemShape: item.shape, itemTransform: { @@ -144,26 +120,160 @@ export class DragController { itemMeta: item.meta, ghostContainer, previewGraphics, - dragOffsetX, - dragOffsetY, + disposables, + }; + + this.activeSession = session; + + // Set up drag-drop event handling via framework utility + const disposeDrag = dragDropEventEffect( + itemContainer as Phaser.GameObjects.GameObject, + disposables, + ); + + itemContainer.on("dragstart", () => { + ghostContainer.setVisible(true); + }); + + itemContainer.on("dragmove", () => { + this.handleDragMove(session); + }); + + itemContainer.on("dragend", () => { + this.handleDragEnd(session); + disposeDrag(); + this.activeSession = null; + }); + + return () => { + disposeDrag(); + this.destroySession(session); + this.activeSession = null; }; } /** - * Start dragging a lost item (item that was dropped outside valid placement). + * Start a drag session for a lost item. */ startLostItemDrag( itemId: string, shape: InventoryItem["shape"], transform: InventoryItem["transform"], meta: InventoryItem["meta"], - pointer: Phaser.Input.Pointer, - ): void { - const ghostContainer = this.scene.add - .container(pointer.x, pointer.y) - .setDepth(1000); + lostContainer: Phaser.GameObjects.Container, + ): () => void { + const pointer = this.scene.input.activePointer; + const ghostContainer = this.createGhostContainer( + pointer.x, + pointer.y, + shape, + transform, + this.getItemColor(itemId), + ); + const previewGraphics = this.scene.add + .graphics() + .setDepth(999) + .setAlpha(0.5); + + const disposables = new DisposableBag(); + const session: DragSession = { + itemId, + itemShape: shape, + itemTransform: { ...transform, offset: { ...transform.offset } }, + itemMeta: meta, + ghostContainer, + previewGraphics, + disposables, + }; + + this.activeSession = session; + + const disposeDrag = dragDropEventEffect( + lostContainer as Phaser.GameObjects.GameObject, + disposables, + ); + + lostContainer.on("dragstart", () => { + ghostContainer.setVisible(true); + }); + + lostContainer.on("dragmove", () => { + this.handleDragMove(session); + }); + + lostContainer.on("dragend", () => { + this.handleDragEnd(session); + disposeDrag(); + this.activeSession = null; + }); + + return () => { + disposeDrag(); + this.destroySession(session); + this.activeSession = null; + }; + } + + /** + * Rotate the currently dragged item by 90 degrees. + */ + rotateDraggedItem(): void { + if (!this.activeSession) return; + + const currentRotation = + (this.activeSession.itemTransform.rotation + 90) % 360; + this.activeSession.itemTransform = { + ...this.activeSession.itemTransform, + rotation: currentRotation, + }; + + this.updateGhostVisuals(this.activeSession); + } + + /** + * Check if currently dragging. + */ + isDragging(): boolean { + return this.activeSession !== null; + } + + /** + * Get the ID of the item being dragged, or null. + */ + getDraggedItemId(): string | null { + return this.activeSession?.itemId ?? null; + } + + /** + * Get the current position of the dragged ghost container. + */ + getDraggedItemPosition(): { x: number; y: number } { + if (!this.activeSession) return { x: 0, y: 0 }; + return { + x: this.activeSession.ghostContainer.x, + y: this.activeSession.ghostContainer.y, + }; + } + + /** + * Clean up active session and destroy all visuals. + */ + destroy(): void { + if (this.activeSession) { + this.destroySession(this.activeSession); + this.activeSession = null; + } + } + + private createGhostContainer( + x: number, + y: number, + shape: InventoryItem["shape"], + transform: InventoryItem["transform"], + color: number, + ): Phaser.GameObjects.Container { + const ghostContainer = this.scene.add.container(x, y).setDepth(1000); const ghostGraphics = this.scene.add.graphics(); - const color = this.getItemColor(itemId); const cells = transformShape(shape, transform); for (const cell of cells) { @@ -184,52 +294,15 @@ export class DragController { } ghostContainer.add(ghostGraphics); - const previewGraphics = this.scene.add - .graphics() - .setDepth(999) - .setAlpha(0.5); - - this.dragState = { - itemId, - itemShape: shape, - itemTransform: { ...transform, offset: { ...transform.offset } }, - itemMeta: meta, - ghostContainer, - previewGraphics, - dragOffsetX: 0, - dragOffsetY: 0, - }; + return ghostContainer; } - /** - * Rotate the currently dragged item by 90 degrees. - */ - rotateDraggedItem(): void { - if (!this.dragState) return; - - const currentRotation = (this.dragState.itemTransform.rotation + 90) % 360; - this.dragState.itemTransform = { - ...this.dragState.itemTransform, - rotation: currentRotation, - }; - - this.updateGhostVisuals(); - } - - /** - * Update ghost visuals to reflect current drag state (after rotation). - */ - private updateGhostVisuals(): void { - if (!this.dragState) return; - - this.dragState.ghostContainer.removeAll(true); + private updateGhostVisuals(session: DragSession): void { + session.ghostContainer.removeAll(true); const ghostGraphics = this.scene.add.graphics(); - const color = this.getItemColor(this.dragState.itemId); + const color = this.getItemColor(session.itemId); - const cells = transformShape( - this.dragState.itemShape, - this.dragState.itemTransform, - ); + const cells = transformShape(session.itemShape, session.itemTransform); for (const cell of cells) { ghostGraphics.fillStyle(color, 0.7); ghostGraphics.fillRect( @@ -246,68 +319,58 @@ export class DragController { this.cellSize, ); } - this.dragState.ghostContainer.add(ghostGraphics); + session.ghostContainer.add(ghostGraphics); } - /** - * Handle pointer movement during drag: update ghost position and placement preview. - */ - onPointerMove(pointer: Phaser.Input.Pointer): void { - if (!this.dragState) return; + private handleDragMove(session: DragSession): void { + const pointer = this.scene.input.activePointer; + session.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 - this.dragState.dragOffsetX, - pointer.y - this.dragState.dragOffsetY, - ); - this.dragState.previewGraphics.clear(); + const gridCell = this.getWorldGridCell(pointer.x, pointer.y); + session.previewGraphics.clear(); if (gridCell) { const inventory = this.getInventory(); const testTransform = { - ...this.dragState.itemTransform, + ...session.itemTransform, offset: { x: gridCell.x, y: gridCell.y }, }; const validation = validatePlacement( inventory, - this.dragState.itemShape, + session.itemShape, testTransform, ); - const cells = transformShape(this.dragState.itemShape, testTransform); + const cells = transformShape(session.itemShape, testTransform); for (const cell of cells) { const px = this.gridX + cell.x * (this.cellSize + this.gridGap); const py = this.gridY + cell.y * (this.cellSize + this.gridGap); if (validation.valid) { - this.dragState.previewGraphics.fillStyle(0x33ff33, 0.3); - this.dragState.previewGraphics.fillRect( + session.previewGraphics.fillStyle(0x33ff33, 0.3); + session.previewGraphics.fillRect( px, py, this.cellSize, this.cellSize, ); - this.dragState.previewGraphics.lineStyle(2, 0x33ff33); - this.dragState.previewGraphics.strokeRect( + session.previewGraphics.lineStyle(2, 0x33ff33); + session.previewGraphics.strokeRect( px, py, this.cellSize, this.cellSize, ); } else { - this.dragState.previewGraphics.fillStyle(0xff3333, 0.3); - this.dragState.previewGraphics.fillRect( + session.previewGraphics.fillStyle(0xff3333, 0.3); + session.previewGraphics.fillRect( px, py, this.cellSize, this.cellSize, ); - this.dragState.previewGraphics.lineStyle(2, 0xff3333); - this.dragState.previewGraphics.strokeRect( + session.previewGraphics.lineStyle(2, 0xff3333); + session.previewGraphics.strokeRect( px, py, this.cellSize, @@ -318,63 +381,56 @@ export class DragController { } } - /** - * Handle pointer release: validate placement and either place item or create lost item. - */ - onPointerUp(pointer: Phaser.Input.Pointer): void { - if (!this.dragState) return; - - const gridCell = this.getWorldGridCell( - pointer.x - this.dragState.dragOffsetX, - pointer.y - this.dragState.dragOffsetY, - ); + private handleDragEnd(session: DragSession): void { + const pointer = this.scene.input.activePointer; + const gridCell = this.getWorldGridCell(pointer.x, pointer.y); const inventory = this.getInventory(); - this.dragState.ghostContainer.destroy(); - this.dragState.previewGraphics.destroy(); + session.ghostContainer.destroy(); + session.previewGraphics.destroy(); + session.disposables.dispose(); if (gridCell) { const testTransform = { - ...this.dragState.itemTransform, + ...session.itemTransform, offset: { x: gridCell.x, y: gridCell.y }, }; const validation = validatePlacement( inventory, - this.dragState.itemShape, + session.itemShape, testTransform, ); if (validation.valid) { const item: InventoryItem = { - id: this.dragState.itemId, - shape: this.dragState.itemShape, + id: session.itemId, + shape: session.itemShape, transform: testTransform, - meta: this.dragState.itemMeta, + meta: session.itemMeta, }; this.onPlaceItem(item); } else { this.onCreateLostItem( - this.dragState.itemId, - this.dragState.itemShape, - this.dragState.itemTransform, - this.dragState.itemMeta, + session.itemId, + session.itemShape, + session.itemTransform, + session.itemMeta, + session.ghostContainer.x, + session.ghostContainer.y, ); } } else { this.onCreateLostItem( - this.dragState.itemId, - this.dragState.itemShape, - this.dragState.itemTransform, - this.dragState.itemMeta, + session.itemId, + session.itemShape, + session.itemTransform, + session.itemMeta, + session.ghostContainer.x, + session.ghostContainer.y, ); } - - this.dragState = null; } - /** - * Convert world coordinates to grid cell coordinates. - */ private getWorldGridCell( worldX: number, worldY: number, @@ -398,36 +454,24 @@ export class DragController { return { x: cellX, y: cellY }; } - /** - * Check if an item is currently being dragged. - */ - isDragging(): boolean { - return this.dragState !== null; - } - - /** - * Get the ID of the item being dragged, or null. - */ - getDraggedItemId(): string | null { - return this.dragState?.itemId ?? null; - } - - getDraggedItemPosition(): { x: number; y: number } { - if (!this.dragState) return { x: 0, y: 0 }; - return { - x: this.dragState.ghostContainer.x, - y: this.dragState.ghostContainer.y, - }; - } - - /** - * Clean up drag state and visuals. - */ - destroy(): void { - if (this.dragState) { - this.dragState.ghostContainer.destroy(); - this.dragState.previewGraphics.destroy(); - this.dragState = null; + private getItemCells( + item: InventoryItem, + ): { x: number; y: number }[] { + const cells: { x: number; y: number }[] = []; + const { offset } = item.transform; + for (let y = 0; y < item.shape.height; y++) { + for (let x = 0; x < item.shape.width; x++) { + if (item.shape.grid[y]?.[x]) { + cells.push({ x: x + offset.x, y: y + offset.y }); + } + } } + return cells; + } + + private destroySession(session: DragSession): void { + session.disposables.dispose(); + session.ghostContainer.destroy(); + session.previewGraphics.destroy(); } } diff --git a/packages/sts-like-viewer/src/widgets/InventoryWidget.ts b/packages/sts-like-viewer/src/widgets/InventoryWidget.ts index cd15da6..b0428a1 100644 --- a/packages/sts-like-viewer/src/widgets/InventoryWidget.ts +++ b/packages/sts-like-viewer/src/widgets/InventoryWidget.ts @@ -25,6 +25,7 @@ export interface InventoryWidgetOptions { /** * Thin orchestrator for the inventory grid widget. * Delegates rendering, drag logic, and lost-item management to focused modules. + * Uses event-driven drag via dragDropEventEffect from boardgame-phaser. */ export class InventoryWidget { private scene: Phaser.Scene; @@ -40,9 +41,7 @@ export class InventoryWidget { private dragController: DragController; private lostItemManager: LostItemManager; - private pointerMoveHandler!: (pointer: Phaser.Input.Pointer) => void; - private pointerUpHandler!: (pointer: Phaser.Input.Pointer) => void; - private pointerDownHandler!: (pointer: Phaser.Input.Pointer) => void; + private rightClickHandler!: (pointer: Phaser.Input.Pointer) => void; constructor(options: InventoryWidgetOptions) { this.scene = options.scene; @@ -52,14 +51,9 @@ export class InventoryWidget { this.isLocked = options.isLocked ?? false; const inventory = this.gameState.value.inventory; - const gridW = - inventory.width * this.cellSize + (inventory.width - 1) * this.gridGap; - const gridH = - inventory.height * this.cellSize + (inventory.height - 1) * this.gridGap; this.container = this.scene.add.container(options.x, options.y); - // Initialize sub-modules this.renderer = new ItemRenderer({ scene: this.scene, container: this.container, @@ -78,10 +72,9 @@ export class InventoryWidget { gridY: this.gridY, getInventory: () => this.getInventory(), getItemColor: (id) => this.renderer.getItemColor(id), - getItemCells: (item) => this.renderer.getItemCells(item), onPlaceItem: (item) => this.handlePlaceItem(item), - onCreateLostItem: (id, shape, transform, meta) => - this.handleCreateLostItem(id, shape, transform, meta), + onCreateLostItem: (id, shape, transform, meta, x, y) => + this.handleCreateLostItem(id, shape, transform, meta, x, y), }); this.lostItemManager = new LostItemManager({ @@ -89,13 +82,13 @@ export class InventoryWidget { cellSize: this.cellSize, gridGap: this.gridGap, getItemColor: (id) => this.renderer.getItemColor(id), - onLostItemDragStart: (id, pointer) => + onLostItemDragStart: (id, lostContainer) => this.dragController.startLostItemDrag( id, this.getLostItemShape(id), this.getLostItemTransform(id), this.getLostItemMeta(id), - pointer, + lostContainer, ), isDragging: () => this.dragController.isDragging(), }); @@ -117,13 +110,14 @@ export class InventoryWidget { for (const [itemId, item] of inventory.items) { if (this.renderer.hasItem(itemId)) continue; const visuals = this.renderer.createItemVisuals(itemId, item); - this.setupItemInteraction(itemId, visuals); + this.setupItemInteraction(itemId, visuals, item); } } private setupItemInteraction( itemId: string, visuals: ReturnType, + item: InventoryItem, ): void { visuals.container.on("pointerdown", (pointer: Phaser.Input.Pointer) => { if (this.isLocked) return; @@ -133,30 +127,20 @@ export class InventoryWidget { removeItemFromGrid(state.inventory, itemId); }); this.renderer.removeItemVisuals(itemId); - this.dragController.startDrag(itemId, pointer); + this.dragController.startDrag(itemId, item, visuals.container); } }); } private setupInput(): void { - this.pointerDownHandler = (pointer: Phaser.Input.Pointer) => { + this.rightClickHandler = (pointer: Phaser.Input.Pointer) => { if (!this.dragController.isDragging()) return; if (pointer.button === 1) { this.dragController.rotateDraggedItem(); } }; - this.pointerMoveHandler = (pointer: Phaser.Input.Pointer) => { - this.dragController.onPointerMove(pointer); - }; - - this.pointerUpHandler = (pointer: Phaser.Input.Pointer) => { - this.dragController.onPointerUp(pointer); - }; - - this.scene.input.on("pointermove", this.pointerMoveHandler); - this.scene.input.on("pointerup", this.pointerUpHandler); - this.scene.input.on("pointerdown", this.pointerDownHandler); + this.scene.input.on("pointerdown", this.rightClickHandler); } private handlePlaceItem(item: InventoryItem): void { @@ -167,7 +151,7 @@ export class InventoryWidget { const placedItem = inventory.items.get(item.id); if (placedItem) { const visuals = this.renderer.createItemVisuals(item.id, placedItem); - this.setupItemInteraction(item.id, visuals); + this.setupItemInteraction(item.id, visuals, placedItem); } } @@ -176,15 +160,10 @@ export class InventoryWidget { shape: InventoryItem["shape"], transform: InventoryItem["transform"], meta: InventoryItem["meta"], + x: number, + y: number, ): void { - this.lostItemManager.createLostItem( - itemId, - shape, - transform, - meta, - this.dragController.getDraggedItemPosition().x, - this.dragController.getDraggedItemPosition().y, - ); + this.lostItemManager.createLostItem(itemId, shape, transform, meta, x, y); } private getLostItemShape(itemId: string) { @@ -214,13 +193,6 @@ export class InventoryWidget { public refresh(): void { const inventory = this.getInventory(); - // Remove visuals for items no longer in inventory - for (const [itemId] of inventory.items.entries()) { - // We need a way to track which items have visuals - // For now, clear and redraw - } - - // Simple approach: destroy all and redraw this.renderer.destroy(); this.renderer = new ItemRenderer({ scene: this.scene, @@ -235,9 +207,7 @@ export class InventoryWidget { } public destroy(): void { - this.scene.input.off("pointermove", this.pointerMoveHandler); - this.scene.input.off("pointerup", this.pointerUpHandler); - this.scene.input.off("pointerdown", this.pointerDownHandler); + this.scene.input.off("pointerdown", this.rightClickHandler); this.dragController.destroy(); this.lostItemManager.destroy(); diff --git a/packages/sts-like-viewer/src/widgets/LostItemManager.ts b/packages/sts-like-viewer/src/widgets/LostItemManager.ts index e085e13..23f202f 100644 --- a/packages/sts-like-viewer/src/widgets/LostItemManager.ts +++ b/packages/sts-like-viewer/src/widgets/LostItemManager.ts @@ -17,7 +17,10 @@ export interface LostItemManagerOptions { cellSize: number; gridGap: number; getItemColor: (itemId: string) => number; - onLostItemDragStart: (itemId: string, pointer: Phaser.Input.Pointer) => void; + onLostItemDragStart: ( + itemId: string, + container: Phaser.GameObjects.Container, + ) => void; isDragging: () => boolean; } @@ -32,7 +35,7 @@ export class LostItemManager { private getItemColor: (itemId: string) => number; private onLostItemDragStart: ( itemId: string, - pointer: Phaser.Input.Pointer, + container: Phaser.GameObjects.Container, ) => void; private isDragging: () => boolean; @@ -48,37 +51,35 @@ export class LostItemManager { } /** - * Create a visual representation of a lost item. + * Create a visual representation of a lost item at the given position. */ createLostItem( itemId: string, shape: InventoryItem["shape"], transform: InventoryItem["transform"], meta: InventoryItem["meta"], - positionX: number, - positionY: number, + x: number, + y: number, ): void { - const container = this.scene.add - .container(positionX, positionY) - .setDepth(500); + const container = this.scene.add.container(x, y).setDepth(500); const graphics = this.scene.add.graphics(); const color = this.getItemColor(itemId); - for (let y = 0; y < shape.height; y++) { - for (let x = 0; x < shape.width; x++) { - if (shape.grid[y]?.[x]) { + 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( - x * (this.cellSize + this.gridGap), - y * (this.cellSize + this.gridGap), + gx * (this.cellSize + this.gridGap), + gy * (this.cellSize + this.gridGap), this.cellSize - 2, this.cellSize - 2, ); graphics.lineStyle(2, 0xff4444); graphics.strokeRect( - x * (this.cellSize + this.gridGap), - y * (this.cellSize + this.gridGap), + gx * (this.cellSize + this.gridGap), + gy * (this.cellSize + this.gridGap), this.cellSize, this.cellSize, ); @@ -108,7 +109,7 @@ export class LostItemManager { container.on("pointerdown", (pointer: Phaser.Input.Pointer) => { if (this.isDragging()) return; if (pointer.button === 0) { - this.onLostItemDragStart(itemId, pointer); + this.onLostItemDragStart(itemId, container); } }); diff --git a/packages/sts-like-viewer/tsconfig.json b/packages/sts-like-viewer/tsconfig.json index d7f3323..9974bb0 100644 --- a/packages/sts-like-viewer/tsconfig.json +++ b/packages/sts-like-viewer/tsconfig.json @@ -3,14 +3,15 @@ "compilerOptions": { "baseUrl": ".", "paths": { - "@/*": ["src/*"] + "@/*": ["src/*"], + "boardgame-phaser": ["../framework/src/index.ts"], }, "jsx": "react-jsx", "jsxImportSource": "preact", "noEmit": true, "declaration": false, "declarationMap": false, - "sourceMap": false + "sourceMap": false, }, - "include": ["src/**/*"] + "include": ["src/**/*"], }