前言
为了准备老师的课设作业,我决定做一个RPG小游戏,在处理寻路的时候遇到了点小麻烦。
首先是解决方案的选取,Unity自带的Navgation Mesh挺强大的(至少在客户端是这样,hh),我之前一直用的A*,但是不知道为什么老版本的A*在Unity 2019.3的InspectorGUI是坏掉的。。。又没钱买正版。。。
emmm,勉为其难的选择Navgation Mesh吧。
但是Navgation Mesh好像只有带有加速度的移动方式,这就有点蛋疼,说实话我个人挺不喜欢那种手感的,所以查了查官方文档,发现了NavMeshPath这么个东西,用它就可以得到我们一次寻路过程中所有的转折点,从而自己处理寻路,那么,我们开始吧。
思路
通过调用NavMeshAgent的CalculatePath来得到NavMeshPath,并使用NavMeshPath的corners数组(记录了每一处拐点的位置)和Transform.Translate做匀速运动,人物方向的改变需要自己处理。
代码
重要部分已注释,核心就是RunToTarget函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
   | namespace ETModel {     [ObjectSystem]     public class NavComponentAwakeSystem : AwakeSystem<NavComponent>     {         public override void Awake(NavComponent self)         {                          self.NavMeshAgent = self.Entity.GameObject.AddComponent<NavMeshAgent>();                          self.UserInputComponent = Game.Scene.GetComponent<UserInputComponent>();                          self.CameraComponent = Game.Scene.GetComponent<CameraComponent>();                          self.Transform = self.Entity.GameObject.transform;         }     }
      [ObjectSystem]     public class NavComponentUpdateSystem : UpdateSystem<NavComponent>     {         public override void Update(NavComponent self)         {                          self.Update();         }     }
      public class NavComponent : Component     {         public NavMeshAgent NavMeshAgent;
          public UserInputComponent UserInputComponent;
          public CameraComponent CameraComponent;
          private Ray m_Ray;
          public Transform Transform;                  private NavMeshPath m_NavMeshPath = new NavMeshPath();
                                     private int m_PreviousPathPointIndex = 0;                                             private int m_CurrentPathPointIndex = 1;
                                     public void RunToTarget()         {                          if (m_CurrentPathPointIndex > m_NavMeshPath.corners.Length - 1) return;
                           if ((Transform.position - m_NavMeshPath.corners[m_CurrentPathPointIndex]).magnitude <= 0.1f)             {                                  m_PreviousPathPointIndex++;                 m_CurrentPathPointIndex++;                                  if (m_CurrentPathPointIndex > m_NavMeshPath.corners.Length - 1)                 {                                          Entity.GetComponent<StackFsmComponent>().AddState(StateTypes.Idle, "Idle", 1);                     return;                 }
                                   Entity.GetComponent<TurnComponent>().Turn(m_NavMeshPath.corners[m_CurrentPathPointIndex]);             }
                           Transform.Translate(                 ((-m_NavMeshPath.corners[m_PreviousPathPointIndex] +                   m_NavMeshPath.corners[m_CurrentPathPointIndex]).normalized) *                 (Time.deltaTime * 8.0f), Space.World);         }
                                     public override void Dispose()         {             if (IsDisposed)             {                 return;             }
              base.Dispose();             NavMeshAgent = null;             UserInputComponent = null;             UnityEngine.Object.Destroy(Entity.GameObject.GetComponent<NavMeshAgent>());         }
          public void Update()         {                          if (UserInputComponent.RightMouseDown)             {                 m_Ray = CameraComponent.mainCamera.ScreenPointToRay(Input.mousePosition);                 if (Physics.Raycast(m_Ray, out var hit, 2000))                 {                                          NavMeshAgent.CalculatePath(hit.point, m_NavMeshPath);                                          m_PreviousPathPointIndex = 0;                     m_CurrentPathPointIndex = 1;                                          Entity.GetComponent<TurnComponent>().Turn(m_NavMeshPath.corners[1]);                                          Entity.GetComponent<StackFsmComponent>().AddState(StateTypes.Run, "Run", 1);                 }             }
                           RunToTarget();         }     } }
   | 
 
效果演示
