MoveComponent.cs 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. using System;
  2. using System.Threading;
  3. using UnityEngine;
  4. namespace ET
  5. {
  6. public class MoveComponent: Entity
  7. {
  8. public Vector3 Target;
  9. // 开启移动协程的时间
  10. public long StartTime;
  11. // 开启移动协程的Unit的位置
  12. public Vector3 StartPos;
  13. public long needTime;
  14. // 当前的移动速度
  15. public float Speed = 5;
  16. // 开启协程移动,每100毫秒移动一次,并且协程取消的时候会计算玩家真实移动
  17. // 比方说玩家移动了2500毫秒,玩家有新的目标,这时旧的移动协程结束,将计算250毫秒移动的位置,而不是300毫秒移动的位置
  18. public async ETTask StartMove(ETCancellationToken cancellationToken)
  19. {
  20. Unit unit = this.GetParent<Unit>();
  21. this.StartPos = unit.Position;
  22. this.StartTime = TimeHelper.ClientNow();
  23. float distance = (this.Target - this.StartPos).magnitude;
  24. if (Math.Abs(distance) < 0.1f)
  25. {
  26. return;
  27. }
  28. this.needTime = (long)(distance / this.Speed * 1000);
  29. TimerComponent timerComponent = Game.Scene.GetComponent<TimerComponent>();
  30. // 协程如果取消,将算出玩家的真实位置,赋值给玩家
  31. cancellationToken?.Add(() =>
  32. {
  33. long timeNow = TimeHelper.ClientNow();
  34. if (timeNow - this.StartTime >= this.needTime)
  35. {
  36. unit.Position = this.Target;
  37. }
  38. else
  39. {
  40. float amount = (timeNow - this.StartTime) * 1f / this.needTime;
  41. unit.Position = Vector3.Lerp(this.StartPos, this.Target, amount);
  42. }
  43. });
  44. while (true)
  45. {
  46. //新版TimerComponent实现不同于5.0的TimerComponent,需要自己判断是取消还是自然结束,并且return,否则将不会取消任务,并可能会造成cancellationToken泄漏
  47. if (!await timerComponent.WaitAsync(50, cancellationToken))
  48. {
  49. return;
  50. }
  51. long timeNow = TimeHelper.ClientNow();
  52. if (timeNow - this.StartTime >= this.needTime)
  53. {
  54. unit.Position = this.Target;
  55. break;
  56. }
  57. float amount = (timeNow - this.StartTime) * 1f / this.needTime;
  58. unit.Position = Vector3.Lerp(this.StartPos, this.Target, amount);
  59. }
  60. }
  61. public async ETTask MoveToAsync(Vector3 target, ETCancellationToken cancellationToken)
  62. {
  63. // 新目标点离旧目标点太近,不设置新的
  64. if ((target - this.Target).sqrMagnitude < 0.01f)
  65. {
  66. return;
  67. }
  68. // 距离当前位置太近
  69. if ((this.GetParent<Unit>().Position - target).sqrMagnitude < 0.01f)
  70. {
  71. return;
  72. }
  73. this.Target = target;
  74. // 开启协程移动
  75. await StartMove(cancellationToken);
  76. }
  77. }
  78. }