feat(sts-like-viewer): animate inventory item rotation
Introduce a tween for the item's rotation and update the hit area calculation to account for the preview rotation. The graphics are now centered within the container to support these transformations.
This commit is contained in:
parent
30e2d9ac36
commit
fe0621cedf
|
|
@ -2,6 +2,7 @@ import Phaser from "phaser";
|
||||||
import { dragDropEventEffect, DragDropEventType } from "boardgame-phaser";
|
import { dragDropEventEffect, DragDropEventType } from "boardgame-phaser";
|
||||||
import { GRID_CONFIG } from "@/config";
|
import { GRID_CONFIG } from "@/config";
|
||||||
import {
|
import {
|
||||||
|
IDENTITY_TRANSFORM,
|
||||||
ParsedShape,
|
ParsedShape,
|
||||||
Point2D,
|
Point2D,
|
||||||
Transform2D,
|
Transform2D,
|
||||||
|
|
@ -34,6 +35,10 @@ export class InventoryItemContainer extends Phaser.GameObjects.Container {
|
||||||
scene.add.existing(this);
|
scene.add.existing(this);
|
||||||
|
|
||||||
const graphics = this.scene.add.graphics();
|
const graphics = this.scene.add.graphics();
|
||||||
|
graphics.setPosition(
|
||||||
|
GRID_CONFIG.VIEWER_CELL_SIZE / 2,
|
||||||
|
GRID_CONFIG.VIEWER_CELL_SIZE / 2,
|
||||||
|
);
|
||||||
const label = this.scene.add.text(
|
const label = this.scene.add.text(
|
||||||
GRID_CONFIG.VIEWER_CELL_SIZE / 2,
|
GRID_CONFIG.VIEWER_CELL_SIZE / 2,
|
||||||
GRID_CONFIG.VIEWER_CELL_SIZE / 2,
|
GRID_CONFIG.VIEWER_CELL_SIZE / 2,
|
||||||
|
|
@ -56,14 +61,23 @@ export class InventoryItemContainer extends Phaser.GameObjects.Container {
|
||||||
disposables.addEffect(() => {
|
disposables.addEffect(() => {
|
||||||
graphics.clear();
|
graphics.clear();
|
||||||
if (!this.itemState.shape.value) return;
|
if (!this.itemState.shape.value) return;
|
||||||
this.hitArea = this.renderGraphics(
|
this.renderGraphics(
|
||||||
graphics,
|
graphics,
|
||||||
this.itemState.shape.value,
|
this.itemState.shape.value,
|
||||||
this.itemState.color.value,
|
this.itemState.color.value,
|
||||||
this.itemState.previewRotation.value,
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
disposables.addEffect(() => {
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: graphics,
|
||||||
|
rotation: -(this.itemState.previewRotation.value * Math.PI) / 180,
|
||||||
|
duration: 150,
|
||||||
|
ease: "Power2",
|
||||||
|
});
|
||||||
|
this.hitArea = this.updateHitArea(this.itemState.previewRotation.value);
|
||||||
|
});
|
||||||
|
|
||||||
disposables.addEffect(() => {
|
disposables.addEffect(() => {
|
||||||
if (!this.itemState.transform.value) return;
|
if (!this.itemState.transform.value) return;
|
||||||
this.snapBack(this.itemState.transform.value);
|
this.snapBack(this.itemState.transform.value);
|
||||||
|
|
@ -71,6 +85,25 @@ export class InventoryItemContainer extends Phaser.GameObjects.Container {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateHitArea(value: number): Point2D[] {
|
||||||
|
const shape = this.itemState.shape.value;
|
||||||
|
if (!shape) return [];
|
||||||
|
|
||||||
|
const rotation = value;
|
||||||
|
const cells = transformShape(shape, {
|
||||||
|
rotation,
|
||||||
|
offset: { x: 0, y: 0 },
|
||||||
|
flipX: false,
|
||||||
|
flipY: false,
|
||||||
|
});
|
||||||
|
const cellSize = GRID_CONFIG.VIEWER_CELL_SIZE;
|
||||||
|
|
||||||
|
return cells.map((cell) => ({
|
||||||
|
x: (cell.x - cells[0].x) * cellSize,
|
||||||
|
y: (cell.y - cells[0].y) * cellSize,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
setItem(item: GameItem): void {
|
setItem(item: GameItem): void {
|
||||||
this.itemState.setItem(item);
|
this.itemState.setItem(item);
|
||||||
}
|
}
|
||||||
|
|
@ -79,16 +112,8 @@ export class InventoryItemContainer extends Phaser.GameObjects.Container {
|
||||||
graphics: Phaser.GameObjects.Graphics,
|
graphics: Phaser.GameObjects.Graphics,
|
||||||
shape: ParsedShape,
|
shape: ParsedShape,
|
||||||
itemColor: number,
|
itemColor: number,
|
||||||
rotation: number,
|
|
||||||
) {
|
) {
|
||||||
const transform: Transform2D = {
|
const cells = transformShape(shape, IDENTITY_TRANSFORM);
|
||||||
offset: { x: 0, y: 0 },
|
|
||||||
rotation,
|
|
||||||
flipX: false,
|
|
||||||
flipY: false,
|
|
||||||
};
|
|
||||||
const cells = transformShape(shape, transform);
|
|
||||||
const cellRects: { x: number; y: number }[] = [];
|
|
||||||
|
|
||||||
for (const cell of cells) {
|
for (const cell of cells) {
|
||||||
const localX = (cell.x - cells[0].x) * GRID_CONFIG.VIEWER_CELL_SIZE;
|
const localX = (cell.x - cells[0].x) * GRID_CONFIG.VIEWER_CELL_SIZE;
|
||||||
|
|
@ -96,16 +121,12 @@ export class InventoryItemContainer extends Phaser.GameObjects.Container {
|
||||||
|
|
||||||
graphics.fillStyle(itemColor);
|
graphics.fillStyle(itemColor);
|
||||||
graphics.fillRect(
|
graphics.fillRect(
|
||||||
localX + 2,
|
localX + 2 - GRID_CONFIG.VIEWER_CELL_SIZE / 2,
|
||||||
localY + 2,
|
localY + 2 - GRID_CONFIG.VIEWER_CELL_SIZE / 2,
|
||||||
GRID_CONFIG.VIEWER_CELL_SIZE - 4,
|
GRID_CONFIG.VIEWER_CELL_SIZE - 4,
|
||||||
GRID_CONFIG.VIEWER_CELL_SIZE - 4,
|
GRID_CONFIG.VIEWER_CELL_SIZE - 4,
|
||||||
);
|
);
|
||||||
|
|
||||||
cellRects.push({ x: localX, y: localY });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cellRects;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupInteractive() {
|
private setupInteractive() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue