MoveToPath.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import { Node, Vec3 } from "cc";
  2. import { Timer } from "../../../../../../extensions/oops-plugin-framework/assets/core/common/timer/Timer";
  3. import { Vec3Util } from "../../../../../../extensions/oops-plugin-framework/assets/core/utils/Vec3Util";
  4. import { ecs } from "../../../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
  5. /** 向目标移动,移动过程中目标位置变化会自动修正移动目标点,直到未修正前移动到目标点停止 */
  6. @ecs.register('MoveToPath')
  7. export class MoveToPathComp extends ecs.Comp {
  8. /** 移动节点 */
  9. node: Node = null!;
  10. /** 移动速度(每秒移动的像素距离) */
  11. speed: number = 0;
  12. /** 移动方向 */
  13. velocity: Vec3 = Vec3Util.zero;
  14. /** 路径数组 */
  15. paths: Vec3[] | null = null;
  16. /** 坐标标(默认本地坐标) */
  17. ns: number = Node.NodeSpace.LOCAL;
  18. /** 移动完成回调 */
  19. onComplete: Function | null = null;
  20. /** 距离变化时 */
  21. onChange: Function | null = null;
  22. reset() {
  23. this.ns = Node.NodeSpace.LOCAL;
  24. this.onComplete = null;
  25. this.onChange = null;
  26. }
  27. }
  28. @ecs.register('VariableMoveToPath')
  29. class VariableMoveToPathComponent extends ecs.Comp {
  30. /** 延时触发器 */
  31. timer: Timer = new Timer();
  32. /** 距离 */
  33. distance: number = 0;
  34. /** 起点备份 */
  35. start: Vec3 | null = null;
  36. /** 终点备份 */
  37. end: Vec3 | null = null;
  38. /** 目标位置 */
  39. target!: Vec3;
  40. isComplete: boolean = false
  41. reset() {
  42. this.end = null;
  43. this.isComplete = false
  44. this.timer.reset();
  45. }
  46. }
  47. /** 按照路径移动 */
  48. export class MoveToPathSystem extends ecs.ComblockSystem<ecs.Entity> implements ecs.IEntityEnterSystem, ecs.IEntityRemoveSystem, ecs.ISystemUpdate {
  49. filter(): ecs.IMatcher {
  50. return ecs.allOf(MoveToPathComp);
  51. }
  52. entityEnter(e: ecs.Entity): void {
  53. e.add(VariableMoveToPathComponent);
  54. }
  55. entityRemove(e: ecs.Entity): void {
  56. e.remove(VariableMoveToPathComponent);
  57. }
  58. update(e: ecs.Entity) {
  59. let move = e.get(MoveToPathComp);
  60. let mtv = e.get(VariableMoveToPathComponent);
  61. // console.assert(move.speed > 0, "移动速度必须要大于零");
  62. // 如果没有路径点或者已经完成当前路径点的移动,则获取下一个路径点
  63. if ((move.paths && move.paths.length > 0)) {
  64. if ((mtv.end == null || mtv.isComplete)) {
  65. mtv.reset()
  66. let end = move.paths.shift();
  67. this.prepareMovement(e, move, mtv, end);
  68. }
  69. } else if (mtv.end == null || mtv.isComplete) {
  70. this.exit(e)
  71. }
  72. // 执行移动
  73. if (move.speed > 0 && mtv.end != null && !mtv.isComplete) {
  74. let trans = Vec3Util.mul(move.velocity, move.speed * this.dt);
  75. let start = move.ns == Node.NodeSpace.WORLD ? move.node.worldPosition : move.node.position;
  76. let end = Vec3Util.add(start, trans)
  77. if (Vec3Util.sub(end, mtv.start).length() > mtv.distance||mtv.timer.update(this.dt)) {
  78. this.finishMovement(e, move, mtv);
  79. mtv.isComplete = true
  80. } else {
  81. move.node.translate(trans, move.ns);
  82. move.node.forward = trans
  83. }
  84. }
  85. }
  86. private prepareMovement(e: ecs.Entity, move: MoveToPathComp, mtv: VariableMoveToPathComponent, end: Vec3) {
  87. let target = end.clone();
  88. let start = move.ns == Node.NodeSpace.WORLD ? move.node.worldPosition : move.node.position;
  89. move.velocity = Vec3Util.sub(target, start).normalize();
  90. let distance = Vec3.distance(start, target);
  91. move.onChange?.call(this);
  92. if (distance <= 0) {
  93. // this.exit(e);
  94. mtv.isComplete = true
  95. } else {
  96. mtv.timer.step = distance / move.speed;
  97. mtv.end = end.clone();
  98. mtv.target = target;
  99. mtv.start = start.clone()
  100. mtv.distance = Vec3.distance(mtv.end, mtv.start);
  101. }
  102. }
  103. private finishMovement(e: ecs.Entity, move: MoveToPathComp, mtv: VariableMoveToPathComponent) {
  104. if (move.ns == Node.NodeSpace.WORLD)
  105. move.node.worldPosition = mtv.target;
  106. else
  107. move.node.position = mtv.target;
  108. // this.exit(e);
  109. }
  110. private exit(e: ecs.Entity) {
  111. let move = e.get(MoveToPathComp);
  112. move.onComplete?.call(this);
  113. e.remove(VariableMoveToPathComponent);
  114. e.remove(MoveToPathComp);
  115. }
  116. }