import { _decorator, Component, Camera, Vec3, Quat, tween, Node, EventTarget } from 'cc'; const { ccclass, property } = _decorator; // 自定义事件 const cameraEvent = new EventTarget(); // 运镜基础类型 enum CameraMoveType { LINEAR, BEZIER, ORBIT } // 运镜配置接口 @ccclass('CameraShotConfig') class CameraShotConfig { @property({ type: Camera }) targetCamera: Camera = null; @property(Node) followTarget: Node = null; @property(Vec3) offset = new Vec3(0, 2, -5); @property(Node) lookAtTarget: Node = null; @property blendTime: number = 1.0; @property holdTime: number = 2.0; @property enableShake: boolean = false; @property shakeIntensity: number = 0.1; } // 运镜配置 class CameraTransitionManager { @property({ type: Camera }) targetCamera: Camera = null; @property blendTime: number = 1.0; @property holdTime: number = 2.0; @property(Node) followTarget: Node = null; @property(Vec3) offset = new Vec3(0, 2, -5); @property fov: number = 60; @property lookAtTarget: Node = null; @property enableShake: boolean = false; @property shakeIntensity: number = 0.1; } @ccclass('CameraRigSystem') export class CameraRigSystem extends Component { @property({ type: Camera }) defaultCamera: Camera = null; @property([CameraShotConfig]) shotSequence: CameraShotConfig[] = []; private currentCamera: Camera = null; private isTransitioning = false; start() { this.initializeCameras(); this.playSequence(); } // 初始化所有相机 private initializeCameras() { this.shotSequence.forEach(config => { if (config.targetCamera) { config.targetCamera.node.active = false; } }); this.defaultCamera.node.active = true; this.currentCamera = this.defaultCamera; } // 播放运镜序列 public async playSequence() { for (const shot of this.shotSequence) { await this.executeShot(shot); } this.returnToDefault(); } // 执行单个运镜镜头 private async executeShot(config: CameraShotConfig): Promise { return new Promise((resolve) => { if (!config.targetCamera) { console.warn("Missing target camera in shot config"); resolve(); return; } // 准备新相机 const newCamera = config.targetCamera; newCamera.node.active = true; // 相机跟随逻辑 if (config.followTarget) { this.setupFollowCamera(newCamera.node, config); } // 运镜过渡 this.blendCameras(this.currentCamera, newCamera, config.blendTime); // 相机震动 if (config.enableShake) { this.addCameraShake(newCamera.node, config.shakeIntensity); } // 保持时间 setTimeout(() => { this.currentCamera = newCamera; resolve(); }, config.holdTime * 1000); }); } // 相机混合过渡 private blendCameras(from: Camera, to: Camera, duration: number) { // 使用权重混合(需要自定义渲染逻辑或使用后期处理) // 此处使用简单激活切换 + 动画过渡 tween(from.node) .to(duration/2, { position: to.node.position }) .start(); tween(to.node) .to(duration, { position: to.node.position }) .call(() => { from.node.active = false; }) .start(); } // 设置跟随相机 private setupFollowCamera(cameraNode: Node, config: CameraShotConfig) { const updateFollow = () => { if (!config.followTarget) return; const targetPos = config.followTarget.worldPosition; const offset = config.offset; cameraNode.worldPosition = new Vec3( targetPos.x + offset.x, targetPos.y + offset.y, targetPos.z + offset.z ); if (config.lookAtTarget) { cameraNode.lookAt(config.lookAtTarget.worldPosition); } }; cameraNode.on(Node.EventType.TRANSFORM_CHANGED, updateFollow); } // 添加相机震动 private addCameraShake(cameraNode: Node, intensity: number) { const originalPos = cameraNode.position.clone(); let shakeTimer = 0; const updateShake = (dt: number) => { shakeTimer += dt; const x = originalPos.x + Math.sin(shakeTimer * 30) * intensity; const y = originalPos.y + Math.cos(shakeTimer * 25) * intensity; cameraNode.setPosition(x, y, originalPos.z); }; this.schedule(updateShake); } // 返回默认相机 private returnToDefault() { this.blendCameras(this.currentCamera, this.defaultCamera, 1.0); } }