feat(sts-viewer): add CombatTestScene and unit visuals
Implement a new combat test scene to visualize Slay the Spire-like combat states. This includes: - `CombatUnitContainer`: A Phaser container for displaying unit HP, name, buffs, and enemy intents. - `CombatUnitSpawner`: A spawner to manage the lifecycle of combat units based on the combat state. - `
This commit is contained in:
parent
9637312b7c
commit
3f2ba84a06
|
|
@ -0,0 +1,228 @@
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import type { CombatEntity, EffectTable, EnemyEntity } from "boardgame-core/samples/slay-the-spire-like";
|
||||||
|
|
||||||
|
export type CombatUnitData = {
|
||||||
|
key: string;
|
||||||
|
entity: CombatEntity;
|
||||||
|
name: string;
|
||||||
|
isPlayer: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CONTAINER_WIDTH = 200;
|
||||||
|
const CONTAINER_HEIGHT = 260;
|
||||||
|
const HP_BAR_WIDTH = 160;
|
||||||
|
const HP_BAR_HEIGHT = 16;
|
||||||
|
const BUFF_ICON_SIZE = 28;
|
||||||
|
const BUFF_ICON_GAP = 6;
|
||||||
|
|
||||||
|
export class CombatUnitContainer extends Phaser.GameObjects.Container {
|
||||||
|
private bg!: Phaser.GameObjects.Rectangle;
|
||||||
|
private nameText!: Phaser.GameObjects.Text;
|
||||||
|
private hpBarBg!: Phaser.GameObjects.Rectangle;
|
||||||
|
private hpBarFill!: Phaser.GameObjects.Rectangle;
|
||||||
|
private hpText!: Phaser.GameObjects.Text;
|
||||||
|
private buffContainer!: Phaser.GameObjects.Container;
|
||||||
|
private intentText!: Phaser.GameObjects.Text | null;
|
||||||
|
|
||||||
|
private currentEntity!: CombatEntity;
|
||||||
|
private currentName: string;
|
||||||
|
private currentIsPlayer: boolean;
|
||||||
|
|
||||||
|
constructor(scene: Phaser.Scene, x: number, y: number, data: CombatUnitData) {
|
||||||
|
super(scene, x, y);
|
||||||
|
scene.add.existing(this);
|
||||||
|
|
||||||
|
this.currentEntity = data.entity;
|
||||||
|
this.currentName = data.name;
|
||||||
|
this.currentIsPlayer = data.isPlayer;
|
||||||
|
|
||||||
|
this.createVisuals();
|
||||||
|
this.updateFromData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private createVisuals(): void {
|
||||||
|
const bgColor = this.currentIsPlayer ? 0x224466 : 0x662222;
|
||||||
|
const borderColor = this.currentIsPlayer ? 0x44aaff : 0xff4444;
|
||||||
|
|
||||||
|
this.bg = this.scene.add
|
||||||
|
.rectangle(0, 0, CONTAINER_WIDTH, CONTAINER_HEIGHT, bgColor)
|
||||||
|
.setStrokeStyle(3, borderColor);
|
||||||
|
|
||||||
|
this.nameText = this.scene.add
|
||||||
|
.text(0, -CONTAINER_HEIGHT / 2 + 24, this.currentName, {
|
||||||
|
fontSize: "18px",
|
||||||
|
color: "#ffffff",
|
||||||
|
fontStyle: "bold",
|
||||||
|
})
|
||||||
|
.setOrigin(0.5);
|
||||||
|
|
||||||
|
this.hpBarBg = this.scene.add
|
||||||
|
.rectangle(0, -CONTAINER_HEIGHT / 2 + 60, HP_BAR_WIDTH, HP_BAR_HEIGHT, 0x333333);
|
||||||
|
|
||||||
|
this.hpBarFill = this.scene.add
|
||||||
|
.rectangle(-HP_BAR_WIDTH / 2, -CONTAINER_HEIGHT / 2 + 60, HP_BAR_WIDTH, HP_BAR_HEIGHT, 0x22c55e)
|
||||||
|
.setOrigin(0, 0.5);
|
||||||
|
|
||||||
|
this.hpText = this.scene.add
|
||||||
|
.text(0, -CONTAINER_HEIGHT / 2 + 60, "", {
|
||||||
|
fontSize: "12px",
|
||||||
|
color: "#ffffff",
|
||||||
|
fontStyle: "bold",
|
||||||
|
})
|
||||||
|
.setOrigin(0.5);
|
||||||
|
|
||||||
|
this.buffContainer = this.scene.add.container(0, CONTAINER_HEIGHT / 2 - 40);
|
||||||
|
|
||||||
|
if (!this.currentIsPlayer) {
|
||||||
|
this.intentText = this.scene.add
|
||||||
|
.text(0, -CONTAINER_HEIGHT / 2 + 86, "", {
|
||||||
|
fontSize: "12px",
|
||||||
|
color: "#ffcc88",
|
||||||
|
})
|
||||||
|
.setOrigin(0.5);
|
||||||
|
} else {
|
||||||
|
this.intentText = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.add([
|
||||||
|
this.bg,
|
||||||
|
this.nameText,
|
||||||
|
this.hpBarBg,
|
||||||
|
this.hpBarFill,
|
||||||
|
this.hpText,
|
||||||
|
this.buffContainer,
|
||||||
|
...(this.intentText ? [this.intentText] : []),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFromData(data: CombatUnitData): void {
|
||||||
|
this.currentEntity = data.entity;
|
||||||
|
this.currentName = data.name;
|
||||||
|
|
||||||
|
this.nameText.setText(this.currentName);
|
||||||
|
|
||||||
|
const hpPercent = this.currentEntity.maxHp > 0
|
||||||
|
? this.currentEntity.hp / this.currentEntity.maxHp
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
const fillWidth = Math.max(0, HP_BAR_WIDTH * hpPercent);
|
||||||
|
this.hpBarFill.setDisplaySize(fillWidth, HP_BAR_HEIGHT);
|
||||||
|
|
||||||
|
const hpColor = hpPercent > 0.5 ? 0x22c55e : hpPercent > 0.25 ? 0xf59e0b : 0xef4444;
|
||||||
|
this.hpBarFill.setFillStyle(hpColor);
|
||||||
|
|
||||||
|
this.hpText.setText(`${this.currentEntity.hp} / ${this.currentEntity.maxHp} HP`);
|
||||||
|
|
||||||
|
this.renderBuffs(this.currentEntity.effects);
|
||||||
|
|
||||||
|
if (!this.currentIsPlayer && this.intentText) {
|
||||||
|
const enemyEntity = data.entity as EnemyEntity;
|
||||||
|
const intent = enemyEntity.currentIntent;
|
||||||
|
const intentName = intent?.id ?? "unknown";
|
||||||
|
this.intentText.setText(`Intent: ${intentName}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderBuffs(effects: EffectTable): void {
|
||||||
|
this.buffContainer.removeAll(true);
|
||||||
|
|
||||||
|
const entries = Object.entries(effects);
|
||||||
|
const totalWidth = entries.length * BUFF_ICON_SIZE + (entries.length - 1) * BUFF_ICON_GAP;
|
||||||
|
const startX = -totalWidth / 2 + BUFF_ICON_SIZE / 2;
|
||||||
|
|
||||||
|
entries.forEach(([key, entry], index) => {
|
||||||
|
const x = startX + index * (BUFF_ICON_SIZE + BUFF_ICON_GAP);
|
||||||
|
const stacks = entry.stacks;
|
||||||
|
|
||||||
|
const isPositive = this.isPositiveEffect(key);
|
||||||
|
const iconColor = isPositive ? 0x44aa44 : 0xaa4444;
|
||||||
|
|
||||||
|
const bg = this.scene.add
|
||||||
|
.rectangle(x, 0, BUFF_ICON_SIZE, BUFF_ICON_SIZE, iconColor)
|
||||||
|
.setStrokeStyle(1, 0xffffff);
|
||||||
|
|
||||||
|
const text = this.scene.add
|
||||||
|
.text(x, 0, `${stacks}`, {
|
||||||
|
fontSize: "12px",
|
||||||
|
color: "#ffffff",
|
||||||
|
fontStyle: "bold",
|
||||||
|
})
|
||||||
|
.setOrigin(0.5);
|
||||||
|
|
||||||
|
this.buffContainer.add([bg, text]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private isPositiveEffect(effectId: string): boolean {
|
||||||
|
const positive = new Set([
|
||||||
|
"block",
|
||||||
|
"strength",
|
||||||
|
"dexterity",
|
||||||
|
"regen",
|
||||||
|
"armor",
|
||||||
|
"barrier",
|
||||||
|
"momentum",
|
||||||
|
]);
|
||||||
|
return positive.has(effectId.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
playSpawnEffect(): void {
|
||||||
|
this.setScale(0);
|
||||||
|
this.setAlpha(0);
|
||||||
|
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: this,
|
||||||
|
scale: 1,
|
||||||
|
alpha: 1,
|
||||||
|
duration: 400,
|
||||||
|
ease: "Back.easeOut",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
playDamageEffect(): void {
|
||||||
|
const flash = this.scene.add
|
||||||
|
.rectangle(this.x, this.y, CONTAINER_WIDTH, CONTAINER_HEIGHT, 0xff0000, 0.4)
|
||||||
|
.setDepth(200);
|
||||||
|
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: this,
|
||||||
|
x: this.x + 8,
|
||||||
|
duration: 60,
|
||||||
|
yoyo: true,
|
||||||
|
repeat: 3,
|
||||||
|
onComplete: () => {
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: flash,
|
||||||
|
alpha: 0,
|
||||||
|
duration: 200,
|
||||||
|
onComplete: () => flash.destroy(),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
playHealEffect(): void {
|
||||||
|
const healText = this.scene.add
|
||||||
|
.text(this.x, this.y - 40, "+HP", {
|
||||||
|
fontSize: "20px",
|
||||||
|
color: "#22c55e",
|
||||||
|
fontStyle: "bold",
|
||||||
|
})
|
||||||
|
.setOrigin(0.5)
|
||||||
|
.setDepth(200);
|
||||||
|
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: healText,
|
||||||
|
y: this.y - 80,
|
||||||
|
alpha: 0,
|
||||||
|
duration: 800,
|
||||||
|
ease: "Power2",
|
||||||
|
onComplete: () => healText.destroy(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy(fromScene?: boolean): void {
|
||||||
|
this.buffContainer.removeAll(true);
|
||||||
|
super.destroy(fromScene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
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";
|
||||||
|
|
||||||
|
export class CombatUnitSpawner implements Spawner<CombatUnitData, CombatUnitContainer> {
|
||||||
|
constructor(private scene: Phaser.Scene) {}
|
||||||
|
|
||||||
|
*getData(): Iterable<CombatUnitData> {
|
||||||
|
const combat = this.getCombatState();
|
||||||
|
if (!combat) return;
|
||||||
|
|
||||||
|
yield {
|
||||||
|
key: "player",
|
||||||
|
entity: combat.player,
|
||||||
|
name: "Player",
|
||||||
|
isPlayer: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let i = 0; i < combat.enemies.length; i++) {
|
||||||
|
const enemy = combat.enemies[i];
|
||||||
|
yield {
|
||||||
|
key: `enemy-${i}`,
|
||||||
|
entity: enemy,
|
||||||
|
name: enemy.enemy.name,
|
||||||
|
isPlayer: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getKey(t: CombatUnitData): string {
|
||||||
|
return t.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSpawn(t: CombatUnitData): CombatUnitContainer | null {
|
||||||
|
const { width, height } = this.scene.scale;
|
||||||
|
const combat = this.getCombatState();
|
||||||
|
if (!combat) return null;
|
||||||
|
|
||||||
|
const totalUnits = 1 + combat.enemies.length;
|
||||||
|
const spacing = 220;
|
||||||
|
const totalWidth = (totalUnits - 1) * spacing;
|
||||||
|
const startX = width / 2 - totalWidth / 2;
|
||||||
|
|
||||||
|
let x = startX;
|
||||||
|
if (t.key.startsWith("enemy-")) {
|
||||||
|
const index = parseInt(t.key.replace("enemy-", ""), 10);
|
||||||
|
x = startX + (index + 1) * spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
const y = height / 2;
|
||||||
|
|
||||||
|
const container = new CombatUnitContainer(this.scene, x, y, t);
|
||||||
|
container.playSpawnEffect();
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpdate(t: CombatUnitData, obj: CombatUnitContainer): void {
|
||||||
|
obj.updateFromData(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDespawn(obj: CombatUnitContainer): void {
|
||||||
|
obj.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCombatState(): CombatState | null {
|
||||||
|
const registry = this.scene.registry;
|
||||||
|
return (registry.get("combatState") as CombatState | undefined) ?? null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createCombatUnitSpawner(scene: Phaser.Scene) {
|
||||||
|
return spawnEffect(new CombatUnitSpawner(scene));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,183 @@
|
||||||
|
import { ReactiveScene } from "boardgame-phaser";
|
||||||
|
import { spawnEffect, type Spawner } from "boardgame-phaser";
|
||||||
|
import { mutableSignal } from "boardgame-core";
|
||||||
|
import { type CombatState } from "boardgame-core/samples/slay-the-spire-like";
|
||||||
|
import { createCombatState } from "@/state/combatState";
|
||||||
|
import { createButton } from "@/utils/createButton";
|
||||||
|
import { SceneKey } from "./types";
|
||||||
|
import {
|
||||||
|
CombatUnitContainer,
|
||||||
|
type CombatUnitData,
|
||||||
|
} from "@/gameobjects/CombatUnitContainer";
|
||||||
|
|
||||||
|
export class CombatTestScene extends ReactiveScene {
|
||||||
|
private combatSignal = mutableSignal<CombatState | null>(null);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super("CombatTestScene");
|
||||||
|
}
|
||||||
|
|
||||||
|
create(): void {
|
||||||
|
super.create();
|
||||||
|
const { width, height } = this.scale;
|
||||||
|
|
||||||
|
const module = createCombatState();
|
||||||
|
this.combatSignal.value = module.createInitialState();
|
||||||
|
|
||||||
|
this.add
|
||||||
|
.text(width / 2, 30, "Combat State Test", {
|
||||||
|
fontSize: "24px",
|
||||||
|
color: "#ffffff",
|
||||||
|
fontStyle: "bold",
|
||||||
|
})
|
||||||
|
.setOrigin(0.5);
|
||||||
|
|
||||||
|
this.add
|
||||||
|
.text(width / 2, 60, "Player & Enemies with Buffs / HP", {
|
||||||
|
fontSize: "14px",
|
||||||
|
color: "#aaaaaa",
|
||||||
|
})
|
||||||
|
.setOrigin(0.5);
|
||||||
|
|
||||||
|
const unitSpawner: Spawner<CombatUnitData, CombatUnitContainer> = {
|
||||||
|
getData: () => this.generateUnitData(),
|
||||||
|
getKey: (t) => t.key,
|
||||||
|
onSpawn: (t) => this.spawnUnit(t, width, height),
|
||||||
|
onUpdate: (t, obj) => obj.updateFromData(t),
|
||||||
|
onDespawn: (obj) => obj.destroy(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const disposeSpawner = spawnEffect(unitSpawner);
|
||||||
|
this.disposables.add(disposeSpawner);
|
||||||
|
|
||||||
|
this.createControls(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateUnitData(): CombatUnitData[] {
|
||||||
|
const combat = this.combatSignal.value;
|
||||||
|
if (!combat) return [];
|
||||||
|
|
||||||
|
const units: CombatUnitData[] = [
|
||||||
|
{
|
||||||
|
key: "player",
|
||||||
|
entity: combat.player,
|
||||||
|
name: "Player",
|
||||||
|
isPlayer: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
combat.enemies.forEach((enemy, i) => {
|
||||||
|
units.push({
|
||||||
|
key: `enemy-${i}`,
|
||||||
|
entity: enemy,
|
||||||
|
name: enemy.enemy.name,
|
||||||
|
isPlayer: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return units;
|
||||||
|
}
|
||||||
|
|
||||||
|
private spawnUnit(
|
||||||
|
t: CombatUnitData,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
): CombatUnitContainer | null {
|
||||||
|
const combat = this.combatSignal.value;
|
||||||
|
if (!combat) return null;
|
||||||
|
|
||||||
|
const totalUnits = 1 + combat.enemies.length;
|
||||||
|
const spacing = 220;
|
||||||
|
const totalWidth = (totalUnits - 1) * spacing;
|
||||||
|
const startX = width / 2 - totalWidth / 2;
|
||||||
|
|
||||||
|
let x = startX;
|
||||||
|
if (t.key.startsWith("enemy-")) {
|
||||||
|
const index = parseInt(t.key.replace("enemy-", ""), 10);
|
||||||
|
x = startX + (index + 1) * spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
const container = new CombatUnitContainer(this, x, height / 2, t);
|
||||||
|
container.playSpawnEffect();
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createControls(width: number, height: number): void {
|
||||||
|
createButton({
|
||||||
|
scene: this,
|
||||||
|
label: "返回菜单",
|
||||||
|
x: 100,
|
||||||
|
y: 40,
|
||||||
|
onClick: async () => {
|
||||||
|
await this.sceneController.launch(SceneKey.IndexScene);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
createButton({
|
||||||
|
scene: this,
|
||||||
|
label: "Damage Player",
|
||||||
|
x: width - 520,
|
||||||
|
y: height - 40,
|
||||||
|
onClick: () => {
|
||||||
|
this.combatSignal.produce((draft) => {
|
||||||
|
if (!draft) return;
|
||||||
|
draft.player.hp = Math.max(0, draft.player.hp - 5);
|
||||||
|
if (draft.player.hp <= 0) draft.player.isAlive = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
createButton({
|
||||||
|
scene: this,
|
||||||
|
label: "Damage Enemy",
|
||||||
|
x: width - 380,
|
||||||
|
y: height - 40,
|
||||||
|
onClick: () => {
|
||||||
|
this.combatSignal.produce((draft) => {
|
||||||
|
if (!draft) return;
|
||||||
|
const enemy = draft.enemies[0];
|
||||||
|
if (enemy) {
|
||||||
|
enemy.hp = Math.max(0, enemy.hp - 5);
|
||||||
|
if (enemy.hp <= 0) enemy.isAlive = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
createButton({
|
||||||
|
scene: this,
|
||||||
|
label: "Heal Player",
|
||||||
|
x: width - 240,
|
||||||
|
y: height - 40,
|
||||||
|
onClick: () => {
|
||||||
|
this.combatSignal.produce((draft) => {
|
||||||
|
if (!draft) return;
|
||||||
|
draft.player.hp = Math.min(draft.player.maxHp, draft.player.hp + 5);
|
||||||
|
if (draft.player.hp > 0) draft.player.isAlive = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
createButton({
|
||||||
|
scene: this,
|
||||||
|
label: "Add Buff",
|
||||||
|
x: width - 100,
|
||||||
|
y: height - 40,
|
||||||
|
onClick: () => {
|
||||||
|
this.combatSignal.produce((draft) => {
|
||||||
|
if (!draft) return;
|
||||||
|
const current = draft.player.effects["strength"];
|
||||||
|
draft.player.effects["strength"] = {
|
||||||
|
data: {
|
||||||
|
id: "strength",
|
||||||
|
name: "Strength",
|
||||||
|
description: "Deal +1 damage per stack",
|
||||||
|
lifecycle: "temporary",
|
||||||
|
},
|
||||||
|
stacks: (current?.stacks ?? 0) + 1,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -38,21 +38,22 @@ export class IndexScene extends ReactiveScene {
|
||||||
scene: SceneKey;
|
scene: SceneKey;
|
||||||
y: number;
|
y: number;
|
||||||
}[] = [
|
}[] = [
|
||||||
{ label: "Map Viewer", scene: SceneKey.MapViewerScene, y: centerY },
|
{ label: "Combat Test", scene: SceneKey.CombatTestScene, y: centerY },
|
||||||
|
{ label: "Map Viewer", scene: SceneKey.MapViewerScene, y: centerY + 70 },
|
||||||
{
|
{
|
||||||
label: "Grid Inventory Viewer",
|
label: "Grid Inventory Viewer",
|
||||||
scene: SceneKey.GridViewerScene,
|
scene: SceneKey.GridViewerScene,
|
||||||
y: centerY + 70,
|
y: centerY + 140,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Shape Viewer",
|
label: "Shape Viewer",
|
||||||
scene: SceneKey.ShapeViewerScene,
|
scene: SceneKey.ShapeViewerScene,
|
||||||
y: centerY + 140,
|
y: centerY + 210,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Inventory Test",
|
label: "Inventory Test",
|
||||||
scene: SceneKey.InventoryTestScene,
|
scene: SceneKey.InventoryTestScene,
|
||||||
y: centerY + 210,
|
y: centerY + 280,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
export enum SceneKey {
|
export enum SceneKey {
|
||||||
|
CombatTestScene = "CombatTestScene",
|
||||||
GridViewerScene = "GridViewerScene",
|
GridViewerScene = "GridViewerScene",
|
||||||
IndexScene = "IndexScene",
|
IndexScene = "IndexScene",
|
||||||
InventoryTestScene = "InventoryTestScene",
|
InventoryTestScene = "InventoryTestScene",
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { GridViewerScene } from "@/scenes/GridViewerScene";
|
||||||
import { ShapeViewerScene } from "@/scenes/ShapeViewerScene";
|
import { ShapeViewerScene } from "@/scenes/ShapeViewerScene";
|
||||||
import { GAME_CONFIG } from "@/config";
|
import { GAME_CONFIG } from "@/config";
|
||||||
import { InventoryTestScene } from "@/scenes/InventoryTestScene";
|
import { InventoryTestScene } from "@/scenes/InventoryTestScene";
|
||||||
|
import { CombatTestScene } from "@/scenes/CombatTestScene";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
|
|
@ -12,6 +13,7 @@ export default function App() {
|
||||||
<div className="flex-1 flex relative justify-center items-center">
|
<div className="flex-1 flex relative justify-center items-center">
|
||||||
<PhaserGame initialScene="IndexScene" config={GAME_CONFIG}>
|
<PhaserGame initialScene="IndexScene" config={GAME_CONFIG}>
|
||||||
<PhaserScene scene={IndexScene} />
|
<PhaserScene scene={IndexScene} />
|
||||||
|
<PhaserScene scene={CombatTestScene} />
|
||||||
<PhaserScene scene={InventoryTestScene} />
|
<PhaserScene scene={InventoryTestScene} />
|
||||||
<PhaserScene scene={MapViewerScene} />
|
<PhaserScene scene={MapViewerScene} />
|
||||||
<PhaserScene scene={GridViewerScene} />
|
<PhaserScene scene={GridViewerScene} />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue