BulletComponent.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import { _decorator, Camera, Component, director, Node, tween, Vec3 } from 'cc';
  2. import { EventDispatcher } from 'db://assets/core_tgx/easy_ui_framework/EventDispatcher';
  3. import { GameEvent } from '../Enum/GameEvent';
  4. const { ccclass, property } = _decorator;
  5. //相机切分动画时长
  6. export const CAMERA_SPLIT_DURATION = 3;
  7. @ccclass('BulletComponent')
  8. export class BulletComponent extends Component {
  9. target: Node = null!;
  10. @property(Camera)
  11. camera: Camera = null!; // 相机节点
  12. protected onLoad(): void {
  13. EventDispatcher.instance.on(GameEvent.EVENT_CAMERA_SPLIT, this.camerSlip, this);
  14. }
  15. private camerSlip(target: Node) {
  16. this.hideGun();
  17. this.target = target;
  18. this.lookAtTarget();
  19. this.flyToTarget();
  20. }
  21. private hideGun() {
  22. const gun = this.camera.node.getChildByName('gun');
  23. gun.active = false;
  24. }
  25. //朝向目标
  26. lookAtTarget() {
  27. if (!this.target) return;
  28. // 计算子弹到目标的方向
  29. const direction = new Vec3();
  30. Vec3.subtract(direction, this.target.worldPosition, this.node.worldPosition);
  31. direction.normalize();
  32. // 计算朝向角度(注意Y轴旋转180度)
  33. const angle = Math.atan2(direction.x, direction.z) * 180 / Math.PI;
  34. // 设置子弹旋转
  35. this.node.setRotationFromEuler(0, angle, 0);
  36. }
  37. //飞向目标
  38. flyToTarget() {
  39. if (!this.target || !this.camera) return;
  40. // 1. 计算相机起始位置(子弹后方)
  41. const bulletDir = new Vec3();
  42. Vec3.subtract(bulletDir, this.target.worldPosition, this.node.worldPosition);
  43. bulletDir.normalize();
  44. const startCameraPos = new Vec3();
  45. Vec3.scaleAndAdd(startCameraPos, this.node.worldPosition, bulletDir, -5);
  46. this.camera.node.worldPosition = startCameraPos;
  47. this.camera.node.lookAt(this.node.worldPosition);
  48. // 2. 子弹飞行+相机跟随
  49. const targetPos = this.target.worldPosition.clone();
  50. let elapsedTime = 0;
  51. tween(this.node)
  52. .to(CAMERA_SPLIT_DURATION, { worldPosition: new Vec3(targetPos.x, targetPos.y, targetPos.z) }, {
  53. onUpdate: (target, ratio) => {
  54. elapsedTime = ratio! * 3;
  55. // 第一秒:相机跟随子弹后方
  56. if (elapsedTime <= 1) {
  57. const followPos = new Vec3();
  58. Vec3.scaleAndAdd(followPos, this.node.worldPosition, bulletDir, -5);
  59. followPos.y += 1;
  60. this.camera.node.worldPosition = followPos;
  61. this.camera.node.lookAt(this.node.worldPosition);
  62. }
  63. // 第二秒:平滑移动到侧后方45度
  64. else if (elapsedTime <= 2) {
  65. // 计算侧后方45度方向向量
  66. const sideBackDir = new Vec3();
  67. Vec3.rotateY(sideBackDir, bulletDir, Vec3.UP, Math.PI / 2);
  68. // 起始位置(后方)和目标位置(侧后方)
  69. const startPos = new Vec3();
  70. Vec3.scaleAndAdd(startPos, this.node.worldPosition, bulletDir, -5);
  71. startPos.y += 3;
  72. const targetPos = new Vec3();
  73. Vec3.scaleAndAdd(targetPos, this.node.worldPosition, sideBackDir, -5);
  74. targetPos.y += 3;
  75. // 使用lerp平滑过渡
  76. const currentPos = new Vec3();
  77. const progress = (elapsedTime - 1) / 1; // 0-1之间的进度
  78. Vec3.lerp(currentPos, startPos, targetPos, progress);
  79. this.camera.node.worldPosition = currentPos;
  80. this.camera.node.lookAt(this.node.worldPosition);
  81. }
  82. // 第三秒:相机对准目标节点
  83. else {
  84. this.node.setScale(1, 1, 1);
  85. // 计算目标点前方5单位的位置(距离从10改为5)
  86. const targetViewPos = new Vec3(
  87. this.target.worldPosition.x,
  88. this.target.worldPosition.y + 2, // 高度偏移2单位
  89. this.target.worldPosition.z + 3 // 前方5单位
  90. );
  91. this.camera.node.worldPosition = targetViewPos;
  92. this.camera.node.lookAt(this.target.worldPosition);
  93. }
  94. }
  95. })
  96. .start();
  97. }
  98. protected onDestroy(): void {
  99. EventDispatcher.instance.off(GameEvent.EVENT_CAMERA_SPLIT, this.camerSlip, this);
  100. }
  101. }