boardgame-phaser/packages/framework/src/ui/PhaserBridge.tsx

76 lines
2.2 KiB
TypeScript

import Phaser from 'phaser';
import { signal, useSignal, useSignalEffect, type Signal } from '@preact/signals';
import { createContext, h } from 'preact';
import { useContext } from 'preact/hooks';
import {ReadonlySignal} from "@preact/signals-core";
export const phaserContext = createContext<ReadonlySignal<Phaser.Game | undefined>>(signal(undefined));
export const defaultPhaserConfig: Phaser.Types.Core.GameConfig = {
type: Phaser.AUTO,
width: 560,
height: 560,
parent: 'phaser-container',
backgroundColor: '#f9fafb',
scene: [],
};
export interface PhaserGameProps {
config?: Partial<Phaser.Types.Core.GameConfig>;
children?: any;
}
export function PhaserGame(props: PhaserGameProps) {
const gameSignal = useSignal<Phaser.Game>();
useSignalEffect(() => {
const config: Phaser.Types.Core.GameConfig = {
...defaultPhaserConfig,
...props.config,
};
const phaserGame = new Phaser.Game(config);
gameSignal.value = phaserGame;
return () => {
gameSignal.value = undefined;
phaserGame.destroy(true);
};
});
return (
<div id="phaser-container" className="w-full h-full">
<phaserContext.Provider value={gameSignal}>
{props.children}
</phaserContext.Provider>
</div>
);
}
export interface PhaserSceneProps {
sceneKey: string;
scene: Phaser.Scene;
autoStart: boolean;
data?: object;
children?: any;
}
export const phaserSceneContext = createContext<ReadonlySignal<Phaser.Scene | undefined>>(signal(undefined));
export function PhaserScene(props: PhaserSceneProps) {
const context = useContext(phaserContext);
const sceneSignal = useSignal<Phaser.Scene>();
useSignalEffect(() => {
const game = context.value;
if (!game) return;
game.scene.add(props.sceneKey, props.scene, props.autoStart, props.data);
sceneSignal.value = game.scene.getScene(props.sceneKey);
return () => {
sceneSignal.value = undefined;
game.scene.remove(props.sceneKey);
};
});
return <phaserSceneContext.Provider value={sceneSignal}>{props.children}</phaserSceneContext.Provider>;
}