import { _decorator, Camera, Component, director, Node, tween, Vec3 } from 'cc'; import { EventDispatcher } from 'db://assets/core_tgx/easy_ui_framework/EventDispatcher'; import { GameEvent } from '../Enum/GameEvent'; const { ccclass, property } = _decorator; //相机切分动画时长 export const CAMERA_SPLIT_DURATION = 3; @ccclass('BulletComponent') export class BulletComponent extends Component { target: Node = null!; @property(Camera) camera: Camera = null!; // 相机节点 protected onLoad(): void { EventDispatcher.instance.on(GameEvent.EVENT_CAMERA_SPLIT, this.camerSlip, this); } private camerSlip(target: Node) { this.hideGun(); this.target = target; this.lookAtTarget(); this.flyToTarget(); } private hideGun() { const gun = this.camera.node.getChildByName('gun'); gun.active = false; } //朝向目标 lookAtTarget() { if (!this.target) return; // 计算子弹到目标的方向 const direction = new Vec3(); Vec3.subtract(direction, this.target.worldPosition, this.node.worldPosition); direction.normalize(); // 计算朝向角度(注意Y轴旋转180度) const angle = Math.atan2(direction.x, direction.z) * 180 / Math.PI; // 设置子弹旋转 this.node.setRotationFromEuler(0, angle, 0); } //飞向目标 flyToTarget() { if (!this.target || !this.camera) return; // 1. 计算相机起始位置(子弹后方) const bulletDir = new Vec3(); Vec3.subtract(bulletDir, this.target.worldPosition, this.node.worldPosition); bulletDir.normalize(); const startCameraPos = new Vec3(); Vec3.scaleAndAdd(startCameraPos, this.node.worldPosition, bulletDir, -5); this.camera.node.worldPosition = startCameraPos; this.camera.node.lookAt(this.node.worldPosition); // 2. 子弹飞行+相机跟随 const targetPos = this.target.worldPosition.clone(); let elapsedTime = 0; tween(this.node) .to(CAMERA_SPLIT_DURATION, { worldPosition: new Vec3(targetPos.x, targetPos.y, targetPos.z) }, { onUpdate: (target, ratio) => { elapsedTime = ratio! * 3; // 第一秒:相机跟随子弹后方 if (elapsedTime <= 1) { const followPos = new Vec3(); Vec3.scaleAndAdd(followPos, this.node.worldPosition, bulletDir, -5); followPos.y += 1; this.camera.node.worldPosition = followPos; this.camera.node.lookAt(this.node.worldPosition); } // 第二秒:平滑移动到侧后方45度 else if (elapsedTime <= 2) { // 计算侧后方45度方向向量 const sideBackDir = new Vec3(); Vec3.rotateY(sideBackDir, bulletDir, Vec3.UP, Math.PI / 2); // 起始位置(后方)和目标位置(侧后方) const startPos = new Vec3(); Vec3.scaleAndAdd(startPos, this.node.worldPosition, bulletDir, -5); startPos.y += 3; const targetPos = new Vec3(); Vec3.scaleAndAdd(targetPos, this.node.worldPosition, sideBackDir, -5); targetPos.y += 3; // 使用lerp平滑过渡 const currentPos = new Vec3(); const progress = (elapsedTime - 1) / 1; // 0-1之间的进度 Vec3.lerp(currentPos, startPos, targetPos, progress); this.camera.node.worldPosition = currentPos; this.camera.node.lookAt(this.node.worldPosition); } // 第三秒:相机对准目标节点 else { this.node.setScale(1, 1, 1); // 计算目标点前方5单位的位置(距离从10改为5) const targetViewPos = new Vec3( this.target.worldPosition.x, this.target.worldPosition.y + 2, // 高度偏移2单位 this.target.worldPosition.z + 3 // 前方5单位 ); this.camera.node.worldPosition = targetViewPos; this.camera.node.lookAt(this.target.worldPosition); } } }) .start(); } protected onDestroy(): void { EventDispatcher.instance.off(GameEvent.EVENT_CAMERA_SPLIT, this.camerSlip, this); } }