feat(sts-viewer): add spawn/despawn tweens and async interruptions
Add visual tweens for Buff and Card game objects. Update spawners to use `GameHostScene` and `addInterruption` to ensure animations complete before the next state change occurs.
This commit is contained in:
parent
c29b9a43b3
commit
dfbdaa3499
|
|
@ -129,4 +129,24 @@ export class Buff extends Phaser.GameObjects.Container {
|
|||
this.tooltipContainer.destroy(fromScene);
|
||||
super.destroy(fromScene);
|
||||
}
|
||||
|
||||
playSpawnTween() {
|
||||
this.setScale(0);
|
||||
this.scene.tweens.add({
|
||||
targets: this,
|
||||
scale: 1,
|
||||
duration: 200,
|
||||
ease: "Back.Out",
|
||||
});
|
||||
}
|
||||
|
||||
playDespawnTween() {
|
||||
this.scene.tweens.add({
|
||||
targets: this,
|
||||
scale: 0,
|
||||
duration: 200,
|
||||
ease: "Back.In",
|
||||
onComplete: () => this.destroy(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
import { GameHostScene } from "boardgame-phaser";
|
||||
import { BuffData, Buff } from "./Buff";
|
||||
import { SpawnerCallback } from "boardgame-phaser";
|
||||
import { CombatState } from "boardgame-core/samples/slay-the-spire-like";
|
||||
|
||||
export type BuffDataWithIndex = BuffData & { x: number };
|
||||
export class BuffSpawner implements SpawnerCallback<BuffDataWithIndex, Buff> {
|
||||
constructor(
|
||||
public scene: Phaser.Scene,
|
||||
public scene: GameHostScene<CombatState>,
|
||||
public buffContainer: Phaser.GameObjects.Container,
|
||||
) {}
|
||||
getKey(t: BuffDataWithIndex) {
|
||||
|
|
@ -13,10 +15,13 @@ export class BuffSpawner implements SpawnerCallback<BuffDataWithIndex, Buff> {
|
|||
onSpawn(t: BuffDataWithIndex) {
|
||||
const buff = new Buff(this.scene, t.x, 0, t);
|
||||
this.buffContainer.add(buff);
|
||||
buff.playSpawnTween();
|
||||
this.scene.addInterruption(new Promise((r) => setTimeout(r, 50)));
|
||||
return buff;
|
||||
}
|
||||
onDespawn(obj: Buff) {
|
||||
obj.destroy();
|
||||
this.scene.addInterruption(new Promise((r) => setTimeout(r, 50)));
|
||||
obj.playDespawnTween();
|
||||
}
|
||||
onUpdate(t: BuffDataWithIndex, obj: Buff) {
|
||||
obj.setPosition(t.x, 0);
|
||||
|
|
|
|||
|
|
@ -165,10 +165,10 @@ export class CardContainer extends Phaser.GameObjects.Container {
|
|||
return this._selected;
|
||||
}
|
||||
|
||||
playSpawnTween(delay = 0): void {
|
||||
playSpawnTween(delay = 0) {
|
||||
this.setAlpha(0);
|
||||
this.setScale(0.5);
|
||||
this.scene.tweens.add({
|
||||
return this.scene.tweens.add({
|
||||
targets: this,
|
||||
alpha: 1,
|
||||
scale: 1,
|
||||
|
|
@ -178,8 +178,8 @@ export class CardContainer extends Phaser.GameObjects.Container {
|
|||
});
|
||||
}
|
||||
|
||||
playDespawnTween(onComplete?: () => void): void {
|
||||
this.scene.tweens.add({
|
||||
playDespawnTween(onComplete?: () => void) {
|
||||
return this.scene.tweens.add({
|
||||
targets: this,
|
||||
alpha: 0,
|
||||
scale: 0.5,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import type {
|
|||
GameCard,
|
||||
} from "boardgame-core/samples/slay-the-spire-like";
|
||||
import { CardContainer } from "./CardContainer";
|
||||
import { GameHostScene } from "boardgame-phaser";
|
||||
|
||||
export interface CardSpawnData {
|
||||
cardId: string;
|
||||
|
|
@ -17,7 +18,7 @@ const HAND_MARGIN = 100;
|
|||
|
||||
export class CardSpawner implements Spawner<CardSpawnData, CardContainer> {
|
||||
constructor(
|
||||
private scene: Phaser.Scene,
|
||||
private scene: GameHostScene<CombatState>,
|
||||
private getState: () => CombatState,
|
||||
private onCardClick: (cardId: string) => void,
|
||||
) {}
|
||||
|
|
@ -47,6 +48,7 @@ export class CardSpawner implements Spawner<CardSpawnData, CardContainer> {
|
|||
});
|
||||
|
||||
container.playSpawnTween(data.index * 40);
|
||||
this.scene.addInterruption(new Promise((r) => setTimeout(r, 40)));
|
||||
return container;
|
||||
}
|
||||
|
||||
|
|
@ -63,8 +65,9 @@ export class CardSpawner implements Spawner<CardSpawnData, CardContainer> {
|
|||
}
|
||||
}
|
||||
|
||||
onDespawn(obj: CardContainer): void {
|
||||
onDespawn(obj: CardContainer, data: CardSpawnData): void {
|
||||
obj.playDespawnTween(() => obj.destroy());
|
||||
this.scene.addInterruption(new Promise((r) => setTimeout(r, 40)));
|
||||
}
|
||||
|
||||
private getCardPosition(
|
||||
|
|
@ -104,7 +107,7 @@ export class CardSpawner implements Spawner<CardSpawnData, CardContainer> {
|
|||
}
|
||||
|
||||
export function createCardSpawner(
|
||||
scene: Phaser.Scene,
|
||||
scene: GameHostScene<CombatState>,
|
||||
getState: () => CombatState,
|
||||
onCardClick: (cardId: string) => void,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
import Phaser from "phaser";
|
||||
import type {
|
||||
CombatEntity,
|
||||
CombatState,
|
||||
EffectTable,
|
||||
EnemyEntity,
|
||||
} from "boardgame-core/samples/slay-the-spire-like";
|
||||
import { BuffData } from "./Buff";
|
||||
import { createSpawnUpdate } from "boardgame-phaser";
|
||||
import { BuffDataWithIndex, BuffSpawner } from "./BuffSpawner";
|
||||
import { GameHostScene } from "boardgame-phaser";
|
||||
|
||||
export type CombatUnitData = {
|
||||
key: string;
|
||||
|
|
@ -30,15 +32,22 @@ export class CombatUnitContainer extends Phaser.GameObjects.Container {
|
|||
private hpText!: Phaser.GameObjects.Text;
|
||||
private buffContainer!: Phaser.GameObjects.Container;
|
||||
private intentText!: Phaser.GameObjects.Text | null;
|
||||
private hostScene: GameHostScene<CombatState>;
|
||||
private updateBuffs!: (buffs: Iterable<BuffData & { x: number }>) => void;
|
||||
|
||||
private currentEntity!: CombatEntity;
|
||||
private currentName: string;
|
||||
private currentIsPlayer: boolean;
|
||||
|
||||
constructor(scene: Phaser.Scene, x: number, y: number, data: CombatUnitData) {
|
||||
constructor(
|
||||
scene: GameHostScene<CombatState>,
|
||||
x: number,
|
||||
y: number,
|
||||
data: CombatUnitData,
|
||||
) {
|
||||
super(scene, x, y);
|
||||
scene.add.existing(this);
|
||||
this.hostScene = scene;
|
||||
|
||||
this.currentEntity = data.entity;
|
||||
this.currentName = data.name;
|
||||
|
|
@ -92,7 +101,7 @@ export class CombatUnitContainer extends Phaser.GameObjects.Container {
|
|||
|
||||
this.buffContainer = this.scene.add.container(0, CONTAINER_HEIGHT / 2 - 40);
|
||||
this.updateBuffs = createSpawnUpdate(
|
||||
new BuffSpawner(this.scene, this.buffContainer),
|
||||
new BuffSpawner(this.hostScene, this.buffContainer),
|
||||
);
|
||||
|
||||
if (!this.currentIsPlayer) {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
import Phaser from "phaser";
|
||||
import type { Spawner } from "boardgame-phaser";
|
||||
import { spawnEffect } from "boardgame-phaser";
|
||||
import type { CombatState, CombatEntity, EnemyEntity } from "boardgame-core/samples/slay-the-spire-like";
|
||||
import { CombatUnitContainer, type CombatUnitData } from "./CombatUnitContainer";
|
||||
import type { CombatState } from "boardgame-core/samples/slay-the-spire-like";
|
||||
import {
|
||||
CombatUnitContainer,
|
||||
type CombatUnitData,
|
||||
} from "./CombatUnitContainer";
|
||||
import { GameHostScene } from "boardgame-phaser";
|
||||
|
||||
export class CombatUnitSpawner implements Spawner<CombatUnitData, CombatUnitContainer> {
|
||||
constructor(private scene: Phaser.Scene) {}
|
||||
export class CombatUnitSpawner implements Spawner<
|
||||
CombatUnitData,
|
||||
CombatUnitContainer
|
||||
> {
|
||||
constructor(private scene: GameHostScene<CombatState>) {}
|
||||
|
||||
*getData(): Iterable<CombatUnitData> {
|
||||
const combat = this.getCombatState();
|
||||
|
|
@ -70,6 +76,6 @@ export class CombatUnitSpawner implements Spawner<CombatUnitData, CombatUnitCont
|
|||
}
|
||||
}
|
||||
|
||||
export function createCombatUnitSpawner(scene: Phaser.Scene) {
|
||||
export function createCombatUnitSpawner(scene: GameHostScene<CombatState>) {
|
||||
return spawnEffect(new CombatUnitSpawner(scene));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue