import { _decorator, Camera, Component, find, Node, Vec3 } from 'cc'; const { ccclass, property } = _decorator; /** * CameraController 摄像机控制器 * 负责让摄像机跟随指定的目标物体,并提供摄像机坐标转换功能 * 支持世界摄像机和UI摄像机的概念 */ @ccclass('CameraController') export class CameraController extends Component { /** 跟随目标 */ private target: Node = null; /** 世界摄像机节点 (Main Camera) */ private worldCameraNode: Node = null; /** 世界摄像机组件 */ private worldCamera: Camera = null; /** UI摄像机节点 (Canvas/Camera) */ private uiCameraNode: Node = null; /** UI摄像机组件 */ private uiCamera: Camera = null; /** 相对偏移量 */ private offset: Vec3 = new Vec3(0, 10, 8); /** 跟随速度 */ @property({ displayName: '跟随速度' }) public followSpeed: number = 5; /** 是否平滑跟随 */ @property({ displayName: '平滑跟随' }) public smoothFollow: boolean = true; onLoad() { this.findCameras(); } /** * 查找所有摄像机 */ private findCameras(): void { this.findWorldCamera(); this.findUICamera(); } /** * 查找世界摄像机 (Main Camera) */ private findWorldCamera(): void { // 查找名为 "Main Camera" 的世界摄像机 const mainCameraNode = find('Main Camera', this.node.scene); if (mainCameraNode) { this.worldCameraNode = mainCameraNode; this.worldCamera = mainCameraNode.getComponent(Camera); console.log('[CameraController] 找到世界摄像机:', mainCameraNode.name); } else { console.error('[CameraController] 未找到世界摄像机(Main Camera)'); } } /** * 查找UI摄像机 (Canvas/Camera) */ private findUICamera(): void { // 查找Canvas下的Camera作为UI摄像机 const canvasNode = find('Canvas', this.node.scene); if (canvasNode) { const uiCameraNode = canvasNode.getChildByName('Camera'); if (uiCameraNode) { this.uiCameraNode = uiCameraNode; this.uiCamera = uiCameraNode.getComponent(Camera); console.log('[CameraController] 找到UI摄像机:', uiCameraNode.name); } else { console.error('[CameraController] 未找到Canvas下的Camera节点'); } } else { console.error('[CameraController] 未找到Canvas节点'); } } /** * 设置跟随目标 * @param target 跟随的目标节点 */ public setTarget(target: Node): void { this.target = target; if (this.target && this.worldCameraNode) { // 立即设置初始位置 this.updateCameraPosition(false); console.log('[CameraController] 设置跟随目标:', target.name); } } /** * 设置摄像机偏移量 * @param offset 相对于目标的偏移量 */ public setOffset(offset: Vec3): void { this.offset.set(offset); } /** * 获取当前跟随目标 */ public getTarget(): Node { return this.target; } /** * 获取世界摄像机节点 */ public getWorldCameraNode(): Node { return this.worldCameraNode; } /** * 获取世界摄像机组件 */ public getWorldCamera(): Camera { return this.worldCamera; } /** * 获取UI摄像机节点 */ public getUICameraNode(): Node { return this.uiCameraNode; } /** * 获取UI摄像机组件 */ public getUICamera(): Camera { return this.uiCamera; } update(deltaTime: number) { if (this.target && this.worldCameraNode) { this.updateCameraPosition(this.smoothFollow, deltaTime); } } /** * 更新摄像机位置 * @param smooth 是否使用平滑跟随 * @param deltaTime 帧时间(smooth为true时需要) */ private updateCameraPosition(smooth: boolean = true, deltaTime: number = 0): void { if (!this.target || !this.worldCameraNode) { return; } // 计算目标位置 const targetPosition = new Vec3(); Vec3.add(targetPosition, this.target.worldPosition, this.offset); if (smooth && deltaTime > 0) { // 平滑跟随 const currentPosition = this.worldCameraNode.worldPosition; const newPosition = new Vec3(); Vec3.lerp(newPosition, currentPosition, targetPosition, this.followSpeed * deltaTime); this.worldCameraNode.setWorldPosition(newPosition); } else { // 立即跟随 this.worldCameraNode.setWorldPosition(targetPosition); } // 让摄像机看向目标 this.worldCameraNode.lookAt(this.target.worldPosition); } /** * 停止跟随 */ public stopFollow(): void { this.target = null; console.log('[CameraController] 停止跟随'); } /** * 将世界坐标转换为指定摄像机的屏幕坐标 * @param worldPosition 世界坐标(Vec3) * @param camera 目标摄像机 * @returns 摄像机坐标系下的屏幕坐标(Vec3),z为深度 */ public worldToCameraPosition(worldPosition: Vec3, camera: Camera): Vec3 { if (!camera) { console.warn('[CameraController] 摄像机参数为空,无法进行坐标转换'); return new Vec3(0, 0, 0); } // 使用摄像机的worldToScreen方法将世界坐标转换为屏幕坐标 const screenPos = new Vec3(); camera.worldToScreen(worldPosition, screenPos); return screenPos; } /** * 将摄像机屏幕坐标转换为指定Node的本地坐标 * 计算流程:摄像机坐标 -> 世界坐标 -> Node本地坐标 * @param screenPosition 摄像机屏幕坐标 * @param sourceCamera 源摄像机 * @param targetNode 目标Node节点 * @returns 目标Node的本地坐标 */ public CameraToNode(screenPosition: Vec3, sourceCamera: Camera, targetNode: Node): Vec3 { if (!sourceCamera || !targetNode) { console.warn('[CameraController] 摄像机或目标节点参数为空,无法进行坐标转换'); return new Vec3(0, 0, 0); } // 第一步:摄像机屏幕坐标转世界坐标 const worldPosition = new Vec3(); sourceCamera.screenToWorld(screenPosition, worldPosition); // 第二步:世界坐标转Node本地坐标 const localPosition = new Vec3(); targetNode.inverseTransformPoint(localPosition, worldPosition); return localPosition; } /** * 将世界坐标转换为UI摄像机节点的本地坐标 * @param worldPosition 世界坐标 * @returns UI摄像机节点的本地坐标 */ public worldToUICamera(worldPosition: Vec3, node: Node): Vec3 { if (!this.worldCamera || !this.uiCameraNode) { console.warn('[CameraController] 世界摄像机或UI摄像机节点未初始化'); return new Vec3(0, 0, 0); } // 第一步:世界坐标转世界摄像机屏幕坐标 const worldCameraPos = this.worldToCameraPosition(worldPosition, this.worldCamera); // 第二步:世界摄像机屏幕坐标转UI摄像机节点本地坐标 const uiCameraLocalPos = this.CameraToNode(worldCameraPos, this.uiCamera, node); return uiCameraLocalPos; // // 世界坐标转Node本地坐标 // const localPosition = new Vec3(); // node.inverseTransformPoint(localPosition, worldPosition); return worldPosition; } /** * 销毁控制器 */ onDestroy(): void { this.target = null; this.worldCameraNode = null; this.worldCamera = null; this.uiCameraNode = null; this.uiCamera = null; console.log('[CameraController] 摄像机控制器已销毁'); } }