2026-04-12 16:26:52 +08:00
|
|
|
|
import Phaser from 'phaser';
|
2026-04-12 16:52:53 +08:00
|
|
|
|
import { effect, type ReadonlySignal } from '@preact/signals-core';
|
2026-04-12 16:26:52 +08:00
|
|
|
|
import { DisposableBag, type IDisposable } from '../utils';
|
|
|
|
|
|
|
|
|
|
|
|
type CleanupFn = void | (() => void);
|
|
|
|
|
|
|
2026-04-12 16:52:53 +08:00
|
|
|
|
// 前向声明,避免循环导入
|
|
|
|
|
|
export interface SceneController {
|
|
|
|
|
|
launch(sceneKey: string, data?: Record<string, unknown>): Promise<void>;
|
|
|
|
|
|
currentScene: ReadonlySignal<string | null>;
|
|
|
|
|
|
isTransitioning: ReadonlySignal<boolean>;
|
2026-04-12 16:26:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface ReactiveScenePhaserData {
|
2026-04-12 16:52:53 +08:00
|
|
|
|
phaserGame: ReadonlySignal<{ game: Phaser.Game }>;
|
|
|
|
|
|
sceneController: SceneController;
|
2026-04-12 16:26:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface ReactiveSceneOptions<TData extends Record<string, unknown> = {}> {
|
|
|
|
|
|
key?: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 通用的响应式 Scene 基类
|
2026-04-12 16:52:53 +08:00
|
|
|
|
* @typeparam TData - 通过 init(data) 接收的数据类型(必须包含 phaserGame 和 sceneController)
|
2026-04-12 16:26:52 +08:00
|
|
|
|
*/
|
|
|
|
|
|
export abstract class ReactiveScene<TData extends Record<string, unknown> = {}>
|
|
|
|
|
|
extends Phaser.Scene
|
|
|
|
|
|
implements IDisposable
|
|
|
|
|
|
{
|
|
|
|
|
|
protected disposables = new DisposableBag();
|
|
|
|
|
|
private _initData!: TData & ReactiveScenePhaserData;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取通过 init() 注入的数据
|
|
|
|
|
|
* 在 create() 阶段保证可用
|
|
|
|
|
|
*/
|
|
|
|
|
|
public get initData(): TData & ReactiveScenePhaserData {
|
|
|
|
|
|
return this._initData;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取 Phaser game 实例的响应式信号
|
|
|
|
|
|
*/
|
2026-04-12 16:52:53 +08:00
|
|
|
|
public get phaserGame(): ReadonlySignal<{ game: Phaser.Game }> {
|
2026-04-12 16:26:52 +08:00
|
|
|
|
return this._initData.phaserGame;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-12 16:52:53 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 获取场景控制器
|
|
|
|
|
|
*/
|
|
|
|
|
|
public get sceneController(): SceneController {
|
|
|
|
|
|
return this._initData.sceneController;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-12 16:26:52 +08:00
|
|
|
|
constructor(key?: string) {
|
|
|
|
|
|
super(key);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
init(data: TData & ReactiveScenePhaserData): void {
|
|
|
|
|
|
this._initData = data;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
create(): void {
|
|
|
|
|
|
this.events.on('shutdown', this.dispose, this);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
dispose(): void {
|
|
|
|
|
|
this.disposables.dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public addDisposable(disposable: IDisposable): void {
|
|
|
|
|
|
this.disposables.add(disposable);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 注册响应式监听(场景关闭时自动清理) */
|
|
|
|
|
|
public addEffect(fn: () => CleanupFn): void {
|
|
|
|
|
|
this.disposables.add(effect(fn));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|