Files
shooter-demo/client-cocos/assets/scripts/App/ClientRunner.ts
2025-11-28 18:10:10 +08:00

219 lines
6.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}