feat: scene manager and transitions
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import Phaser from 'phaser';
|
||||
import { ReactiveScene, type ReactiveScenePhaserData } from './ReactiveScene';
|
||||
|
||||
export interface FadeSceneData {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理淡入淡出到黑色的过渡场景
|
||||
*/
|
||||
export class FadeScene extends ReactiveScene<FadeSceneData> {
|
||||
private overlay!: Phaser.GameObjects.Rectangle;
|
||||
private isFading = false;
|
||||
|
||||
constructor() {
|
||||
super(FADE_SCENE_KEY);
|
||||
}
|
||||
|
||||
create(): void {
|
||||
super.create();
|
||||
|
||||
// 创建黑色遮罩层,覆盖整个游戏区域
|
||||
const game = this.game;
|
||||
this.overlay = this.add.rectangle(
|
||||
0,
|
||||
0,
|
||||
game.scale.width,
|
||||
game.scale.height,
|
||||
0x000000,
|
||||
1
|
||||
).setOrigin(0)
|
||||
.setAlpha(1)
|
||||
.setDepth(999999)
|
||||
.setInteractive({ useHandCursor: false });
|
||||
|
||||
// 防止遮罩阻挡输入
|
||||
this.overlay.disableInteractive();
|
||||
}
|
||||
|
||||
/**
|
||||
* 淡入(从黑色到透明)
|
||||
* @param duration 动画时长(毫秒)
|
||||
*/
|
||||
fadeIn(duration = 300): Promise<void> {
|
||||
return this.fadeTo(0, duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* 淡出(从透明到黑色)
|
||||
* @param duration 动画时长(毫秒)
|
||||
*/
|
||||
fadeOut(duration = 300): Promise<void> {
|
||||
return this.fadeTo(1, duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* 淡入淡出到指定透明度
|
||||
*/
|
||||
private fadeTo(targetAlpha: number, duration: number): Promise<void> {
|
||||
if (this.isFading) {
|
||||
console.warn('FadeScene: 正在进行过渡动画');
|
||||
}
|
||||
|
||||
this.isFading = true;
|
||||
this.overlay.setAlpha(targetAlpha === 1 ? 0 : 1);
|
||||
|
||||
return new Promise<void>((resolve) => {
|
||||
this.tweens.add({
|
||||
targets: this.overlay,
|
||||
alpha: targetAlpha,
|
||||
duration,
|
||||
ease: 'Linear',
|
||||
onComplete: () => {
|
||||
this.isFading = false;
|
||||
resolve();
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 导出常量供 PhaserGame 使用
|
||||
export const FADE_SCENE_KEY = '__fade__';
|
||||
@@ -1,15 +1,19 @@
|
||||
import Phaser from 'phaser';
|
||||
import { effect } from '@preact/signals-core';
|
||||
import { effect, type ReadonlySignal } from '@preact/signals-core';
|
||||
import { DisposableBag, type IDisposable } from '../utils';
|
||||
|
||||
type CleanupFn = void | (() => void);
|
||||
|
||||
export interface PhaserGameContext {
|
||||
game: Phaser.Game;
|
||||
// 前向声明,避免循环导入
|
||||
export interface SceneController {
|
||||
launch(sceneKey: string, data?: Record<string, unknown>): Promise<void>;
|
||||
currentScene: ReadonlySignal<string | null>;
|
||||
isTransitioning: ReadonlySignal<boolean>;
|
||||
}
|
||||
|
||||
export interface ReactiveScenePhaserData {
|
||||
phaserGame: PhaserGameContext;
|
||||
phaserGame: ReadonlySignal<{ game: Phaser.Game }>;
|
||||
sceneController: SceneController;
|
||||
}
|
||||
|
||||
export interface ReactiveSceneOptions<TData extends Record<string, unknown> = {}> {
|
||||
@@ -18,7 +22,7 @@ export interface ReactiveSceneOptions<TData extends Record<string, unknown> = {}
|
||||
|
||||
/**
|
||||
* 通用的响应式 Scene 基类
|
||||
* @typeparam TData - 通过 init(data) 接收的数据类型(必须包含 phaserGame)
|
||||
* @typeparam TData - 通过 init(data) 接收的数据类型(必须包含 phaserGame 和 sceneController)
|
||||
*/
|
||||
export abstract class ReactiveScene<TData extends Record<string, unknown> = {}>
|
||||
extends Phaser.Scene
|
||||
@@ -38,10 +42,17 @@ export abstract class ReactiveScene<TData extends Record<string, unknown> = {}>
|
||||
/**
|
||||
* 获取 Phaser game 实例的响应式信号
|
||||
*/
|
||||
public get phaserGame(): PhaserGameContext {
|
||||
public get phaserGame(): ReadonlySignal<{ game: Phaser.Game }> {
|
||||
return this._initData.phaserGame;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取场景控制器
|
||||
*/
|
||||
public get sceneController(): SceneController {
|
||||
return this._initData.sceneController;
|
||||
}
|
||||
|
||||
constructor(key?: string) {
|
||||
super(key);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
export { ReactiveScene } from './ReactiveScene';
|
||||
export type { ReactiveSceneOptions, ReactiveScenePhaserData } from './ReactiveScene';
|
||||
export type { ReactiveSceneOptions, ReactiveScenePhaserData, SceneController } from './ReactiveScene';
|
||||
|
||||
export { FadeScene, FADE_SCENE_KEY } from './FadeScene';
|
||||
export type { FadeSceneData } from './FadeScene';
|
||||
|
||||
export { GameHostScene } from './GameHostScene';
|
||||
export type { GameHostSceneOptions } from './GameHostScene';
|
||||
|
||||
Reference in New Issue
Block a user