/** * Pinball 渲染器实现 * 负责渲染物理对象、粒子效果等 */ import { _decorator, Camera, Color, Component, Graphics, Node, Prefab, Sprite, tween, Vec3 } from 'cc'; import { PhysicsBodyData, Vector2 } from '../Core/GameData'; import { IRenderer, ParticleEffect, RenderObject } from '../Core/IRenderer'; const { ccclass, property } = _decorator; @ccclass export class PinballRenderer extends Component implements IRenderer { @property(Node) private renderContainer: Node = null!; @property(Prefab) private ballPrefab: Prefab = null!; private renderObjects: Map = new Map(); private particlePool: Node[] = []; private camera: Camera = null!; /** * 设置相机 */ setCamera(camera: Camera): void { this.camera = camera; console.log('Camera set for PinballRenderer'); } /** * 设置世界边界 */ setWorldBounds(width: number, height: number): void { console.log(`World bounds set to ${width} x ${height}`); // 可以在此处设置渲染边界或背景 } /** * 初始化渲染器 */ async initialize(parentNode: any): Promise { console.log('Initializing PinballRenderer...'); // 设置渲染容器 if (parentNode) { this.renderContainer = parentNode; } else { this.renderContainer = this.node; } // 获取相机 - 在 Cocos Creator 3.x 中需要通过场景查找 const cameraNode = this.renderContainer.scene?.getChildByName('Main Camera'); if (cameraNode) { this.camera = cameraNode.getComponent(Camera); } if (!this.camera) { console.warn('Main camera not found, creating default camera'); const cameraNode = new Node('PinballCamera'); this.camera = cameraNode.addComponent(Camera); this.renderContainer.addChild(cameraNode); } // 创建默认球体预制件(如果没有提供) if (!this.ballPrefab) { await this.createDefaultBallPrefab(); } console.log('PinballRenderer initialized successfully'); } /** * 创建默认的球体预制件 */ private async createDefaultBallPrefab(): Promise { // 创建一个简单的圆形节点作为默认球体 const ballNode = new Node('DefaultBall'); // 添加 Sprite 组件 const sprite = ballNode.addComponent(Sprite); // 创建圆形材质 const graphics = ballNode.addComponent(Graphics); graphics.fillColor = Color.WHITE; graphics.circle(0, 0, 25); // 半径 25 像素 graphics.fill(); console.log('Created default ball prefab'); } /** * 渲染物理体 */ renderBodies(bodies: PhysicsBodyData[]): void { // 清理不存在的渲染对象 const currentBodyIds = new Set(bodies.map(body => body.id.toString())); for (const [id, node] of this.renderObjects) { if (!currentBodyIds.has(id)) { this.removeRenderObject(id); } } // 更新或创建渲染对象 for (const body of bodies) { const bodyIdStr = body.id.toString(); let renderNode = this.renderObjects.get(bodyIdStr); if (!renderNode) { // 创建新的渲染对象 const renderObject = this.createRenderObject(body); renderNode = this.createRenderNode(renderObject); this.renderObjects.set(bodyIdStr, renderNode); this.renderContainer.addChild(renderNode); } // 更新位置 renderNode.setPosition(body.position.x * 100, body.position.y * 100); // 放大显示 } } /** * 创建渲染对象数据 */ createRenderObject(body: PhysicsBodyData): RenderObject { return { id: body.id.toString(), position: body.position, radius: body.radius, color: body.isStatic ? { r: 128, g: 128, b: 128, a: 255 } : // 静态物体:灰色 { r: 255, g: 100, b: 100, a: 255 }, // 动态物体:红色 layer: 0 }; } /** * 创建渲染节点 */ private createRenderNode(renderObject: RenderObject): Node { const node = new Node(`Ball_${renderObject.id}`); // 添加 Graphics 组件用于绘制圆形 const graphics = node.addComponent(Graphics); graphics.fillColor = new Color( renderObject.color.r, renderObject.color.g, renderObject.color.b, renderObject.color.a ); const radius = Math.max(renderObject.radius * 100, 10); // 最小半径 10 像素 graphics.circle(0, 0, radius); graphics.fill(); // 添加边框 graphics.strokeColor = Color.BLACK; graphics.lineWidth = 2; graphics.circle(0, 0, radius); graphics.stroke(); return node; } /** * 更新渲染对象 */ updateRenderObject(renderObject: RenderObject, body: PhysicsBodyData): void { const node = this.renderObjects.get(renderObject.id); if (node) { // 更新位置 node.setPosition(body.position.x * 100, body.position.y * 100); // 可以在此添加更多属性的更新,如颜色、大小等 } } /** * 移除渲染对象 */ removeRenderObject(bodyId: string): void { const node = this.renderObjects.get(bodyId); if (node) { node.removeFromParent(); this.renderObjects.delete(bodyId); console.log(`Removed render object ${bodyId}`); } } /** * 播放粒子效果 */ playParticleEffect(effect: ParticleEffect): void { // 创建简单的粒子效果节点 const particleNode = this.getParticleNode(); particleNode.setPosition(effect.position.x * 100, effect.position.y * 100); // 使用 Cocos Creator 3.x 的 tween 系统 tween(particleNode) .parallel( tween().to(effect.lifetime, { opacity: 0 }), tween().by(effect.lifetime, { position: new Vec3(effect.velocity.x * 50, effect.velocity.y * 50, 0) }) ) .call(() => { this.recycleParticleNode(particleNode); }) .start(); this.renderContainer.addChild(particleNode); } /** * 获取粒子节点(对象池) */ private getParticleNode(): Node { if (this.particlePool.length > 0) { return this.particlePool.pop()!; } const node = new Node('Particle'); const graphics = node.addComponent(Graphics); graphics.fillColor = Color.YELLOW; graphics.circle(0, 0, 3); graphics.fill(); return node; } /** * 回收粒子节点 */ private recycleParticleNode(node: Node): void { node.removeFromParent(); // 重置透明度 - 在 Cocos Creator 3.x 中通过 UIOpacity 组件 const uiOpacity = node.getComponent('cc.UIOpacity') as any; if (uiOpacity) { uiOpacity.opacity = 255; } node.setPosition(0, 0, 0); // 重置位置 this.particlePool.push(node); } /** * 清除所有渲染对象 */ clear(): void { for (const [id, node] of this.renderObjects) { node.removeFromParent(); } this.renderObjects.clear(); // 清理粒子池 for (const particle of this.particlePool) { particle.removeFromParent(); } this.particlePool = []; console.log('Cleared all render objects'); } /** * 设置相机位置 */ setCameraPosition(position: Vector2): void { if (this.camera) { this.camera.node.setPosition(position.x * 100, position.y * 100); } } /** * 设置相机缩放 */ setCameraZoom(zoom: number): void { if (this.camera) { // 在 Cocos Creator 3.x 中使用 orthoHeight 控制缩放 this.camera.orthoHeight = 600 / zoom; // 基础高度 600 } } /** * 销毁渲染器 */ dispose(): void { this.clear(); console.log('PinballRenderer disposed'); } }