import { _decorator, Camera, Component, Node } from 'cc'; import { EventBus } from '../Core/EventBus'; import { PhysicsBodyData, Vector2 } from '../Core/GameData'; import { IPhysicsEngine } from '../Core/IPhysicsEngine'; import { IRenderer } from '../Core/IRenderer'; import { InputManager } from '../Input/InputManager'; import { MouseInputEvent, TouchInputEvent } from '../Input/InputTypes'; import { WasmPhysicsEngine } from '../Physics/WasmPhysicsEngine'; import { PinballRenderer } from '../Renderer/PinballRenderer'; const { ccclass, property } = _decorator; /** * Standalone模式 - 单机弹珠物理游戏模式 * 整合物理引擎、渲染器和输入管理器,提供完整的单机游戏体验 */ @ccclass('StandaloneMode') export class StandaloneMode extends Component { @property(Camera) gameCamera: Camera = null; @property(Node) renderNode: Node = null; @property({ type: Node, tooltip: "用于显示游戏边界的节点" }) boundsNode: Node = null; // 核心系统 private physicsEngine: IPhysicsEngine = null; private renderer: IRenderer = null; private inputManager: InputManager = null; private eventBus: EventBus = null; // 游戏配置 @property({ tooltip: "游戏世界宽度" }) worldWidth: number = 800; @property({ tooltip: "游戏世界高度" }) worldHeight: number = 600; @property({ tooltip: "重力加速度" }) gravity: number = -9.81; @property({ tooltip: "弹珠默认半径" }) ballRadius: number = 10; @property({ tooltip: "弹珠默认密度" }) ballDensity: number = 1.0; @property({ tooltip: "弹珠默认弹性系数" }) ballRestitution: number = 0.8; // 游戏状态 private isInitialized: boolean = false; private ballCount: number = 0; private activeBalls: Map = new Map(); async onLoad() { // 初始化事件总线 this.eventBus = EventBus.getInstance(); // 初始化物理引擎 await this.initializePhysics(); // 初始化渲染器 this.initializeRenderer(); // 初始化输入管理器 this.initializeInput(); // 注册事件监听 this.registerEventHandlers(); console.log('[StandaloneMode] 初始化完成'); } onEnable() { if (this.isInitialized) { this.startGameLoop(); } } onDisable() { this.stopGameLoop(); } onDestroy() { this.cleanup(); } /** * 初始化物理引擎 */ private async initializePhysics(): Promise { this.physicsEngine = new WasmPhysicsEngine(); await this.physicsEngine.initialize({ gravity: { x: 0, y: this.gravity }, timeStep: 1 / 60, maxBodies: 1000 }); // 创建物理世界 await this.physicsEngine.createWorld({ x: 0, y: this.gravity }); // 创建世界边界 this.createWorldBounds(); console.log('[StandaloneMode] 物理引擎初始化完成'); } /** * 初始化渲染器 */ private initializeRenderer(): void { if (!this.renderNode) { console.error('[StandaloneMode] renderNode 未设置'); return; } this.renderer = this.renderNode.getComponent(PinballRenderer); if (!this.renderer) { this.renderer = this.renderNode.addComponent(PinballRenderer); } // 设置渲染器参数 if (this.gameCamera) { this.renderer.setCamera(this.gameCamera); } this.renderer.setWorldBounds(this.worldWidth, this.worldHeight); console.log('[StandaloneMode] 渲染器初始化完成'); } /** * 初始化输入管理器 */ private initializeInput(): void { this.inputManager = this.getComponent(InputManager); if (!this.inputManager) { this.inputManager = this.addComponent(InputManager); } // 设置输入管理器参数 if (this.gameCamera) { this.inputManager.setCamera(this.gameCamera); } console.log('[StandaloneMode] 输入管理器初始化完成'); } /** * 注册事件处理器 */ private registerEventHandlers(): void { // 监听输入事件 this.eventBus.on('input.mouse.click', (event: MouseInputEvent) => this.onMouseClick(event)); this.eventBus.on('input.touch.start', (event: TouchInputEvent) => this.onTouchStart(event)); // 监听物理事件 this.eventBus.on('physics.collision', (collisionData: any) => this.onPhysicsCollision(collisionData)); console.log('[StandaloneMode] 事件处理器注册完成'); this.isInitialized = true; } /** * 创建世界边界 */ private createWorldBounds(): void { const halfWidth = this.worldWidth / 2; const halfHeight = this.worldHeight / 2; const wallThickness = 10; // 创建四面墙壁 const walls = [ // 底部墙 { x: 0, y: -halfHeight - wallThickness / 2, width: this.worldWidth + wallThickness, height: wallThickness }, // 顶部墙 { x: 0, y: halfHeight + wallThickness / 2, width: this.worldWidth + wallThickness, height: wallThickness }, // 左侧墙 { x: -halfWidth - wallThickness / 2, y: 0, width: wallThickness, height: this.worldHeight + wallThickness }, // 右侧墙 { x: halfWidth + wallThickness / 2, y: 0, width: wallThickness, height: this.worldHeight + wallThickness } ]; for (const wall of walls) { this.physicsEngine.createBox({ position: { x: wall.x, y: wall.y }, size: { x: wall.width, y: wall.height }, isStatic: true, restitution: 0.8, friction: 0.3 }); } console.log('[StandaloneMode] 世界边界创建完成'); } /** * 鼠标点击事件处理 */ private onMouseClick(event: MouseInputEvent): void { this.createBallAtPosition(event.position); } /** * 触摸开始事件处理 */ private onTouchStart(event: TouchInputEvent): void { this.createBallAtPosition(event.position); } /** * 在指定位置创建弹珠 */ private createBallAtPosition(position: Vector2): void { const ballId = this.physicsEngine.createCircle({ position: position, radius: this.ballRadius, isStatic: false, density: this.ballDensity, restitution: this.ballRestitution, friction: 0.3 }); // 创建球体数据 const ballData: PhysicsBodyData = { id: ballId, position: position, rotation: 0, velocity: { x: 0, y: 0 }, angularVelocity: 0, bodyType: 'circle', radius: this.ballRadius, isStatic: false }; this.activeBalls.set(ballId, ballData); this.ballCount++; // 通知渲染器 this.eventBus.emit('ball.created', { id: ballId, position: position, radius: this.ballRadius }); console.log(`[StandaloneMode] 创建弹珠 #${ballId} 在位置 (${position.x}, ${position.y})`); } /** * 物理碰撞事件处理 */ private onPhysicsCollision(collisionData: any): void { // 播放碰撞音效或效果 console.log('[StandaloneMode] 物理碰撞:', collisionData); } /** * 开始游戏循环 */ private startGameLoop(): void { // 在update中已经自动运行物理和渲染循环 console.log('[StandaloneMode] 游戏循环已开始'); } /** * 停止游戏循环 */ private stopGameLoop(): void { console.log('[StandaloneMode] 游戏循环已停止'); } /** * 游戏更新循环 */ update(deltaTime: number) { if (!this.isInitialized || !this.physicsEngine) { return; } // 步进物理引擎 this.physicsEngine.step(deltaTime); // 更新所有活动球体的状态 for (const [ballId, ballData] of this.activeBalls) { const updatedData = this.physicsEngine.getBodyData(ballId); if (updatedData) { // 更新本地数据 ballData.position = updatedData.position; ballData.rotation = updatedData.rotation; ballData.velocity = updatedData.velocity; ballData.angularVelocity = updatedData.angularVelocity; // 发送更新事件给渲染器 this.eventBus.emit('ball.updated', { id: ballId, position: ballData.position, rotation: ballData.rotation }); } } } /** * 清理资源 */ private cleanup(): void { // 清理事件监听器 this.eventBus.off('input.mouse.click', this.onMouseClick); this.eventBus.off('input.touch.start', this.onTouchStart); this.eventBus.off('physics.collision', this.onPhysicsCollision); // 清理物理引擎 if (this.physicsEngine) { this.physicsEngine.cleanup(); this.physicsEngine = null; } // 清理数据 this.activeBalls.clear(); this.ballCount = 0; this.isInitialized = false; console.log('[StandaloneMode] 资源清理完成'); } /** * 获取游戏统计信息 */ public getGameStats() { return { ballCount: this.ballCount, activeBalls: this.activeBalls.size, worldSize: { width: this.worldWidth, height: this.worldHeight }, isInitialized: this.isInitialized }; } /** * 重置游戏 */ public resetGame(): void { // 移除所有球体 for (const ballId of this.activeBalls.keys()) { this.physicsEngine.removeBody(ballId); this.eventBus.emit('ball.removed', { id: ballId }); } this.activeBalls.clear(); this.ballCount = 0; console.log('[StandaloneMode] 游戏重置完成'); } }