Files
shooter-demo/client-cocos/assets/scripts/App/ClientRunner.ts

219 lines
6.5 KiB
TypeScript
Raw Normal View History

2025-11-28 18:10:10 +08:00
import { _decorator, Component, Enum, Node } from 'cc';
import { PinballBootConfig, PinballBootMode, PinballBootResult, PinballBootstrap } from '../Modules/Pinball/Boot';
import { PinballManager } from '../Modules/Pinball/PinballManager';
const { ccclass, property } = _decorator;
// 定义模式枚举
export enum RunMode {
STANDALONE = 0,
CLIENT_MULTIPLAYER = 1,
SERVER_MULTIPLAYER = 2
}
// 将枚举注册到Cocos Creator
Enum(RunMode);
// RunMode 到字符串的映射
const RunModeStrings = {
[RunMode.STANDALONE]: 'standalone',
[RunMode.CLIENT_MULTIPLAYER]: 'client-multiplayer',
[RunMode.SERVER_MULTIPLAYER]: 'server-multiplayer'
} as const;
// RunMode 到 PinballBootMode 的映射
const RunModeToPinballBootMode = {
[RunMode.STANDALONE]: PinballBootMode.STANDALONE,
[RunMode.CLIENT_MULTIPLAYER]: PinballBootMode.CLIENT_MULTIPLAYER,
[RunMode.SERVER_MULTIPLAYER]: PinballBootMode.SERVER_MULTIPLAYER
} as const;
@ccclass('ClientRunner')
export class ClientRunner extends Component {
@property({
type: Enum(RunMode),
displayName: "运行模式",
tooltip: '选择运行模式:单机/客户端多人/服务器多人'
})
public mode: RunMode = RunMode.STANDALONE;
@property({
type: Node,
displayName: "主相机节点",
tooltip: '主相机节点,用于渲染游戏画面'
})
public cameraNode: Node = null;
@property({
type: Node,
displayName: "渲染容器",
tooltip: '渲染容器节点,所有游戏对象将在此节点下渲染'
})
public renderContainer: Node = null;
@property({
type: Node,
displayName: "UI容器",
tooltip: 'UI容器节点用于显示游戏UI界面'
})
public uiContainer: Node = null;
private pinballManager: PinballManager = null;
private bootResult: PinballBootResult = null;
async start() {
console.log(`[ClientRunner] 开始启动,运行模式: ${this.getModeString()}`);
// 使用 Bootstrap 启动游戏
await this.bootWithBootstrap();
}
/**
* 使 Bootstrap
*/
private async bootWithBootstrap(): Promise<void> {
try {
// 创建启动配置
const config = this.createBootConfig();
// 使用 Bootstrap 启动
const bootstrap = PinballBootstrap.getInstance();
this.bootResult = await bootstrap.boot(this, config);
if (this.bootResult.success) {
this.pinballManager = this.bootResult.pinballManager;
console.log(`[ClientRunner] 使用 Bootstrap 启动成功: ${this.bootResult.mode}`);
} else {
console.error(`[ClientRunner] Bootstrap 启动失败: ${this.bootResult.error}`);
this.handleBootFailure(this.bootResult);
}
} catch (error) {
console.error('[ClientRunner] Bootstrap 启动异常:', error);
}
}
/**
*
*/
private createBootConfig(): PinballBootConfig {
// 将 RunMode 转换为 PinballBootMode
const bootMode = this.convertRunModeToPinballBootMode(this.mode);
// 使用默认配置并设置节点引用
const config = PinballBootstrap.createDefaultConfig(bootMode);
config.cameraNode = this.cameraNode;
config.renderContainer = this.renderContainer;
config.uiContainer = this.uiContainer;
// 根据模式添加特定配置
if (bootMode === PinballBootMode.CLIENT_MULTIPLAYER ||
bootMode === PinballBootMode.SERVER_MULTIPLAYER) {
config.multiplayerConfig = {
serverAddress: 'localhost:3000', // 默认服务器地址
playerName: 'Player1',
roomId: 'default'
};
}
return config;
}
/**
* RunMode PinballBootMode
*/
private convertRunModeToPinballBootMode(runMode: RunMode): PinballBootMode {
return RunModeToPinballBootMode[runMode] ?? PinballBootMode.STANDALONE;
}
/**
*
*/
private handleBootFailure(result: PinballBootResult): void {
console.error(`[ClientRunner] 启动失败 - 模式: ${result.mode}, 错误: ${result.error}`);
// 可以在这里添加错误恢复逻辑,比如回退到 Standalone 模式
if (result.mode !== PinballBootMode.STANDALONE) {
console.log('[ClientRunner] 尝试回退到 Standalone 模式...');
setTimeout(async () => {
this.mode = RunMode.STANDALONE;
await this.bootWithBootstrap();
}, 1000);
}
}
update(deltaTime: number) {
}
onDestroy() {
// 清理 PinballManager
if (this.pinballManager) {
this.pinballManager = null;
}
}
/**
* PinballManager
*/
public getPinballManager(): PinballManager | null {
return this.pinballManager;
}
/**
*
*/
public async restart(): Promise<void> {
console.log('[ClientRunner] 重启游戏...');
if (this.pinballManager) {
await this.pinballManager.restartGame();
} else {
// 如果没有 PinballManager重新执行启动流程
await this.bootWithBootstrap();
}
}
/**
*
*/
public async switchMode(newMode: RunMode): Promise<void> {
console.log(`[ClientRunner] 切换模式从 ${this.getModeString()}${this.getModeStringForMode(newMode)}`);
// 停止当前游戏
if (this.pinballManager) {
await this.pinballManager.stopCurrentGame();
}
// 设置新模式
this.mode = newMode;
// 重新启动
await this.bootWithBootstrap();
}
/**
*
*/
public getBootResult(): PinballBootResult | null {
return this.bootResult;
}
/**
*
*/
private getModeStringForMode(mode: RunMode): string {
return RunModeStrings[mode] ?? 'standalone';
}
/**
*
* @returns
*/
public getModeString(): string {
return this.getModeStringForMode(this.mode);
}
}