refactor: improve inventory item interaction and state
- Decouple hit area calculation from the rendering effect in `InventoryItemContainer`. - Implement a dedicated `hitArea` property to track cell rectangles. - Update `setupInteractive` to use the container itself as the hit area with a custom callback. - Move drag-and-drop logic into a dedicated `setupDnDEffect` method. - Add `addPreviewRotation` to `InventoryItemState` for cleaner rotation updates. - Normalize `previewRotation` to stay within 0-360 degrees.
This commit is contained in:
parent
c9f573ef86
commit
30e2d9ac36
|
|
@ -2,15 +2,14 @@ import Phaser from "phaser";
|
|||
import { dragDropEventEffect, DragDropEventType } from "boardgame-phaser";
|
||||
import { GRID_CONFIG } from "@/config";
|
||||
import {
|
||||
IDENTITY_TRANSFORM,
|
||||
ParsedShape,
|
||||
Point2D,
|
||||
Transform2D,
|
||||
transformShape,
|
||||
type GameItem,
|
||||
} from "boardgame-core/samples/slay-the-spire-like";
|
||||
import { DisposableBag } from "../../../framework/dist";
|
||||
import { InventoryItemState } from "@/state/InventoryItemState";
|
||||
import { effect } from "@preact/signals-core";
|
||||
|
||||
export interface InventoryItemContainerCallbacks {
|
||||
onMoveItem: (
|
||||
|
|
@ -23,6 +22,7 @@ export interface InventoryItemContainerCallbacks {
|
|||
|
||||
export class InventoryItemContainer extends Phaser.GameObjects.Container {
|
||||
private itemState: InventoryItemState;
|
||||
private hitArea: Point2D[] = [];
|
||||
|
||||
constructor(
|
||||
scene: Phaser.Scene,
|
||||
|
|
@ -41,6 +41,7 @@ export class InventoryItemContainer extends Phaser.GameObjects.Container {
|
|||
GRID_CONFIG.ITEM_NAME_STYLE,
|
||||
);
|
||||
this.add([graphics, label]);
|
||||
this.setupInteractive();
|
||||
|
||||
this.itemState = new InventoryItemState();
|
||||
|
||||
|
|
@ -50,20 +51,18 @@ export class InventoryItemContainer extends Phaser.GameObjects.Container {
|
|||
label.setText(this.itemState.name.value);
|
||||
});
|
||||
|
||||
disposables.add(
|
||||
effect(() => {
|
||||
disposables.add(this.setupDnDEffect());
|
||||
|
||||
disposables.addEffect(() => {
|
||||
graphics.clear();
|
||||
if (!this.itemState.shape.value) return;
|
||||
const cellRects = this.renderGraphics(
|
||||
this.hitArea = this.renderGraphics(
|
||||
graphics,
|
||||
this.itemState.shape.value,
|
||||
this.itemState.color.value,
|
||||
this.itemState.previewRotation.value,
|
||||
);
|
||||
|
||||
return this.setupInteractive(cellRects);
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
disposables.addEffect(() => {
|
||||
if (!this.itemState.transform.value) return;
|
||||
|
|
@ -81,7 +80,7 @@ export class InventoryItemContainer extends Phaser.GameObjects.Container {
|
|||
shape: ParsedShape,
|
||||
itemColor: number,
|
||||
rotation: number,
|
||||
): { x: number; y: number }[] {
|
||||
) {
|
||||
const transform: Transform2D = {
|
||||
offset: { x: 0, y: 0 },
|
||||
rotation,
|
||||
|
|
@ -109,17 +108,17 @@ export class InventoryItemContainer extends Phaser.GameObjects.Container {
|
|||
return cellRects;
|
||||
}
|
||||
|
||||
private setupInteractive(cellRects: { x: number; y: number }[]) {
|
||||
private setupInteractive() {
|
||||
this.setScrollFactor(0);
|
||||
const cellSize = GRID_CONFIG.VIEWER_CELL_SIZE;
|
||||
this.setInteractive({
|
||||
hitArea: cellRects,
|
||||
hitArea: this,
|
||||
hitAreaCallback: (
|
||||
hitArea: { x: number; y: number }[],
|
||||
hitArea: InventoryItemContainer,
|
||||
x: number,
|
||||
y: number,
|
||||
) =>
|
||||
hitArea.some(
|
||||
hitArea.hitArea.some(
|
||||
(cell) =>
|
||||
x >= cell.x &&
|
||||
x < cell.x + cellSize &&
|
||||
|
|
@ -128,11 +127,12 @@ export class InventoryItemContainer extends Phaser.GameObjects.Container {
|
|||
),
|
||||
useHandCursor: true,
|
||||
} as Phaser.Types.Input.InputConfiguration);
|
||||
}
|
||||
|
||||
private setupDnDEffect() {
|
||||
let startX = 0;
|
||||
let startY = 0;
|
||||
return dragDropEventEffect(this, (event) => {
|
||||
console.log(event.type);
|
||||
if (event.type === DragDropEventType.DOWN) {
|
||||
startX = this.x;
|
||||
startY = this.y;
|
||||
|
|
@ -141,8 +141,7 @@ export class InventoryItemContainer extends Phaser.GameObjects.Container {
|
|||
this.x = startX + event.deltaX;
|
||||
this.y = startY + event.deltaY;
|
||||
} else if (event.type === DragDropEventType.ALTBUTTON) {
|
||||
const current = this.itemState.previewRotation.peek();
|
||||
this.itemState.setPreviewRotation(current + 90);
|
||||
this.itemState.addPreviewRotation(90);
|
||||
} else if (event.type === DragDropEventType.UP) {
|
||||
this.setAlpha(1);
|
||||
const finalRotation = this.itemState.previewRotation.peek();
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export class InventoryItemState {
|
|||
|
||||
this.previewRotation = computed(() => {
|
||||
const base = this._item.value?.transform?.rotation ?? 0;
|
||||
return base + this._previewRotation.value;
|
||||
return (base + this._previewRotation.value) % 360;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -50,6 +50,10 @@ export class InventoryItemState {
|
|||
this._previewRotation.value = rotation;
|
||||
}
|
||||
|
||||
addPreviewRotation(rotation: number): void {
|
||||
this._previewRotation.value += rotation;
|
||||
}
|
||||
|
||||
private computeColor(itemId: string): number {
|
||||
const hash = itemId.split("").reduce((acc, c) => acc + c.charCodeAt(0), 0);
|
||||
return ITEM_COLORS[hash % ITEM_COLORS.length];
|
||||
|
|
|
|||
Loading…
Reference in New Issue