400 lines
11 KiB
TypeScript
400 lines
11 KiB
TypeScript
/**
|
||
* PinballManager - Pinball模块主控制器
|
||
* 负责整个Pinball模块的生命周期管理和模式切换
|
||
*/
|
||
|
||
import { _decorator, Camera, Component, director, Director, game, Game, Node, Scene } from 'cc';
|
||
import { EventBus } from './Core/EventBus';
|
||
import { GameState, PinballConfig } from './Core/GameData';
|
||
import { StandaloneMode } from './GameModes/StandaloneMode';
|
||
|
||
const { ccclass, property } = _decorator;
|
||
|
||
export enum PinballMode {
|
||
STANDALONE = 'standalone',
|
||
CLIENT_MULTIPLAYER = 'client-multiplayer',
|
||
SERVER_MULTIPLAYER = 'server-multiplayer'
|
||
}
|
||
|
||
@ccclass('PinballManager')
|
||
export class PinballManager extends Component {
|
||
|
||
@property({
|
||
type: Node,
|
||
tooltip: "主相机节点,用于渲染游戏画面"
|
||
})
|
||
cameraNode: Node = null;
|
||
|
||
@property({
|
||
type: Node,
|
||
tooltip: "渲染容器节点,所有游戏对象将在此节点下渲染"
|
||
})
|
||
renderContainer: Node = null;
|
||
|
||
@property({
|
||
type: Node,
|
||
tooltip: "UI容器节点,用于显示游戏UI界面"
|
||
})
|
||
uiContainer: Node = null;
|
||
|
||
@property({
|
||
tooltip: "启动时的默认游戏模式"
|
||
})
|
||
defaultMode: PinballMode = PinballMode.STANDALONE;
|
||
|
||
@property({
|
||
tooltip: "是否在启动时自动开始游戏"
|
||
})
|
||
autoStart: boolean = true;
|
||
|
||
@property({
|
||
tooltip: "调试模式,启用详细日志"
|
||
})
|
||
debugMode: boolean = true;
|
||
|
||
// 核心系统
|
||
private eventBus: EventBus = null;
|
||
private currentMode: PinballMode = null;
|
||
private currentGameMode: Component = null;
|
||
private mainCamera: Camera = null;
|
||
|
||
// 游戏状态
|
||
private isInitialized: boolean = false;
|
||
private isPaused: boolean = false;
|
||
private gameConfig: PinballConfig = null;
|
||
|
||
/**
|
||
* 启动 PinballManager
|
||
* 必须在配置应用后调用
|
||
*/
|
||
async Start(): Promise<boolean> {
|
||
this.log('[PinballManager] Start 开始');
|
||
|
||
try {
|
||
// 初始化事件总线
|
||
this.eventBus = EventBus.getInstance();
|
||
|
||
// 验证必需的节点
|
||
if (!this.validateRequiredNodes()) {
|
||
console.error('[PinballManager] 必需节点验证失败');
|
||
return false;
|
||
}
|
||
|
||
// 获取主相机
|
||
this.initializeCamera();
|
||
|
||
// 创建默认配置
|
||
this.createDefaultConfig();
|
||
|
||
// 注册全局事件监听器
|
||
this.registerGlobalEvents();
|
||
|
||
// 初始化完成
|
||
this.isInitialized = true;
|
||
this.log('[PinballManager] 初始化完成');
|
||
|
||
this.log('[PinballManager] Start 完成');
|
||
return true;
|
||
} catch (error) {
|
||
console.error('[PinballManager] Start 过程中发生错误:', error);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 停止 PinballManager
|
||
*/
|
||
Stop(): void {
|
||
this.log('[PinballManager] Stop 开始');
|
||
this.cleanup();
|
||
this.isInitialized = false;
|
||
this.log('[PinballManager] Stop 完成');
|
||
}
|
||
|
||
// 保留 onDestroy 作为安全清理
|
||
onDestroy() {
|
||
this.Stop();
|
||
}
|
||
|
||
/**
|
||
* 验证必需的节点
|
||
*/
|
||
private validateRequiredNodes(): boolean {
|
||
if (!this.cameraNode) {
|
||
console.error('[PinballManager] cameraNode 未设置');
|
||
return false;
|
||
}
|
||
|
||
if (!this.renderContainer) {
|
||
console.error('[PinballManager] renderContainer 未设置');
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 初始化相机
|
||
*/
|
||
private initializeCamera(): void {
|
||
this.mainCamera = this.cameraNode.getComponent(Camera);
|
||
if (!this.mainCamera) {
|
||
console.error('[PinballManager] 主相机组件未找到');
|
||
return;
|
||
}
|
||
|
||
this.log('主相机初始化完成');
|
||
}
|
||
|
||
/**
|
||
* 创建默认配置
|
||
*/
|
||
private createDefaultConfig(): void {
|
||
this.gameConfig = {
|
||
mode: this.defaultMode,
|
||
physicsSettings: {
|
||
gravity: { x: 0, y: -9.81 },
|
||
timeStep: 1 / 60
|
||
},
|
||
renderSettings: {
|
||
enableEffects: true,
|
||
maxParticles: 500
|
||
},
|
||
wasmPath: 'assets/wasm/pinball_physics.wasm'
|
||
};
|
||
|
||
this.log('默认配置创建完成', this.gameConfig);
|
||
}
|
||
|
||
/**
|
||
* 注册全局事件监听器
|
||
*/
|
||
private registerGlobalEvents(): void {
|
||
// 监听场景切换事件 - Cocos Creator 3.x 中使用静态常量
|
||
director.on(Director.EVENT_BEFORE_SCENE_LAUNCH, this.onSceneChange, this);
|
||
|
||
// 监听游戏暂停/恢复 - Cocos Creator 3.x 中使用game事件
|
||
game.on(Game.EVENT_HIDE, this.onGamePause, this);
|
||
game.on(Game.EVENT_SHOW, this.onGameResume, this);
|
||
|
||
this.log('全局事件监听器注册完成');
|
||
}
|
||
|
||
/**
|
||
* 启动游戏
|
||
*/
|
||
public async startGame(mode: PinballMode): Promise<boolean> {
|
||
if (!this.isInitialized) {
|
||
console.error('[PinballManager] 尚未初始化');
|
||
return false;
|
||
}
|
||
|
||
if (this.currentGameMode) {
|
||
await this.stopCurrentGame();
|
||
}
|
||
|
||
this.log(`开始启动游戏模式: ${mode}`);
|
||
|
||
try {
|
||
switch (mode) {
|
||
case PinballMode.STANDALONE:
|
||
await this.startStandaloneMode();
|
||
break;
|
||
|
||
case PinballMode.CLIENT_MULTIPLAYER:
|
||
console.warn('[PinballManager] Client Multiplayer 模式尚未实现');
|
||
return false;
|
||
|
||
case PinballMode.SERVER_MULTIPLAYER:
|
||
console.warn('[PinballManager] Server Multiplayer 模式尚未实现');
|
||
return false;
|
||
|
||
default:
|
||
console.error(`[PinballManager] 未知游戏模式: ${mode}`);
|
||
return false;
|
||
}
|
||
|
||
this.currentMode = mode;
|
||
this.gameConfig.mode = mode;
|
||
|
||
this.log(`游戏模式 ${mode} 启动成功`);
|
||
|
||
// 发送游戏开始事件
|
||
this.eventBus.emit('game.started', { mode });
|
||
|
||
return true;
|
||
|
||
} catch (error) {
|
||
console.error(`[PinballManager] 启动游戏模式 ${mode} 失败:`, error);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 启动Standalone模式
|
||
*/
|
||
private async startStandaloneMode(): Promise<void> {
|
||
// 添加StandaloneMode组件
|
||
const standaloneMode = this.node.addComponent(StandaloneMode);
|
||
|
||
// 设置所需的引用
|
||
standaloneMode.gameCamera = this.mainCamera;
|
||
standaloneMode.renderNode = this.renderContainer;
|
||
standaloneMode.boundsNode = this.renderContainer; // 简化设置
|
||
|
||
// StandaloneMode 会在 onLoad 中自动初始化
|
||
this.currentGameMode = standaloneMode;
|
||
|
||
this.log('Standalone模式启动完成');
|
||
}
|
||
|
||
/**
|
||
* 停止当前游戏模式
|
||
*/
|
||
public async stopCurrentGame(): Promise<void> {
|
||
if (!this.currentGameMode) {
|
||
return;
|
||
}
|
||
|
||
this.log(`停止当前游戏模式: ${this.currentMode}`);
|
||
|
||
// 销毁当前游戏模式组件
|
||
this.currentGameMode.destroy();
|
||
this.currentGameMode = null;
|
||
this.currentMode = null;
|
||
|
||
// 发送游戏停止事件
|
||
this.eventBus.emit('game.stopped', {});
|
||
|
||
this.log('当前游戏模式已停止');
|
||
}
|
||
|
||
/**
|
||
* 暂停游戏
|
||
*/
|
||
public pauseGame(): void {
|
||
if (this.isPaused) {
|
||
return;
|
||
}
|
||
|
||
this.isPaused = true;
|
||
this.eventBus.emit('game.paused', {});
|
||
this.log('游戏已暂停');
|
||
}
|
||
|
||
/**
|
||
* 恢复游戏
|
||
*/
|
||
public resumeGame(): void {
|
||
if (!this.isPaused) {
|
||
return;
|
||
}
|
||
|
||
this.isPaused = false;
|
||
this.eventBus.emit('game.resumed', {});
|
||
this.log('游戏已恢复');
|
||
}
|
||
|
||
/**
|
||
* 重启当前游戏
|
||
*/
|
||
public async restartGame(): Promise<boolean> {
|
||
const currentMode = this.currentMode;
|
||
|
||
if (currentMode) {
|
||
await this.stopCurrentGame();
|
||
return await this.startGame(currentMode);
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 切换游戏模式
|
||
*/
|
||
public async switchMode(newMode: PinballMode): Promise<boolean> {
|
||
if (this.currentMode === newMode) {
|
||
this.log(`已经是 ${newMode} 模式`);
|
||
return true;
|
||
}
|
||
|
||
return await this.startGame(newMode);
|
||
}
|
||
|
||
/**
|
||
* 场景切换事件处理
|
||
*/
|
||
private onSceneChange(scene: Scene): void {
|
||
this.log('场景切换事件');
|
||
// 可以在此处理场景切换时的清理工作
|
||
}
|
||
|
||
/**
|
||
* 游戏暂停事件处理
|
||
*/
|
||
private onGamePause(): void {
|
||
this.pauseGame();
|
||
}
|
||
|
||
/**
|
||
* 游戏恢复事件处理
|
||
*/
|
||
private onGameResume(): void {
|
||
this.resumeGame();
|
||
}
|
||
|
||
/**
|
||
* 清理资源
|
||
*/
|
||
private cleanup(): void {
|
||
// 清理全局事件监听器
|
||
director.off(Director.EVENT_BEFORE_SCENE_LAUNCH, this.onSceneChange, this);
|
||
game.off(Game.EVENT_HIDE, this.onGamePause, this);
|
||
game.off(Game.EVENT_SHOW, this.onGameResume, this);
|
||
|
||
// 停止当前游戏
|
||
if (this.currentGameMode) {
|
||
this.stopCurrentGame();
|
||
}
|
||
|
||
this.log('PinballManager 资源清理完成');
|
||
}
|
||
|
||
/**
|
||
* 获取当前游戏状态
|
||
*/
|
||
public getGameState(): GameState | null {
|
||
if (this.currentGameMode && this.currentGameMode instanceof StandaloneMode) {
|
||
return this.currentGameMode.getGameStats() as any;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 获取游戏配置
|
||
*/
|
||
public getConfig(): PinballConfig {
|
||
return this.gameConfig;
|
||
}
|
||
|
||
/**
|
||
* 更新游戏配置
|
||
*/
|
||
public updateConfig(newConfig: Partial<PinballConfig>): void {
|
||
this.gameConfig = { ...this.gameConfig, ...newConfig };
|
||
this.log('游戏配置已更新', this.gameConfig);
|
||
}
|
||
|
||
/**
|
||
* 调试日志输出
|
||
*/
|
||
private log(message: string, data?: any): void {
|
||
if (this.debugMode) {
|
||
if (data) {
|
||
console.log(`[PinballManager] ${message}`, data);
|
||
} else {
|
||
console.log(`[PinballManager] ${message}`);
|
||
}
|
||
}
|
||
}
|
||
} |