第七章 寻路与地图对象(Pathfinding and Map Object)
这一章主要进行寻路与地图对象的部分工作。
文章目录
五 搜索移动范围与路径(Search Move Range and Path)
就像我们之前说的,移动范围与攻击范围的搜索算法十分的类似,只需要修改少部分内容:
-
计算消耗G;
-
在判断是否能加入开放集时,需要判断格子是否有效(是否可移动);
-
对外调用的函数,加入移动消耗。
1 修改寻路(Extend Pathfinding)
这个方法,我们在PathFinding
类中添加。
-
首先,修改对外调用函数:
// 修改后寻找移动范围 public bool SearchMoveRange(IHowToFind howToFind, CellData start, float movePoint, MoveConsumption consumption) { if (howToFind == null || start == null || movePoint < 0) { return false; } Reset(); m_HowToFind = howToFind; m_MoveConsumption = consumption; m_StartCell = start; m_StartCell.ResetAStar(); m_Range.y = movePoint; m_Reachable.Add(m_StartCell); return SearchRangeInternal(); } // 修改后搜寻路径 public bool SearchPath(IHowToFind howToFind, CellData start, CellData end, MoveConsumption consumption) { if (howToFind == null || start == null || end == null) { return false; } Reset(); m_HowToFind = howToFind; m_MoveConsumption = consumption; m_StartCell = start; m_StartCell.ResetAStar(); m_EndCell = end; m_EndCell.ResetAStar(); m_Reachable.Add(m_StartCell); m_StartCell.h = m_HowToFind.CalcH(this, m_StartCell); return SearchRangeInternal(); } /// 修改后寻找攻击范围 /// 这里添加的参数 `useEndCell` , /// 是在 `移动范围` 与 `攻击范围` 一起显示时, /// 不破坏 `起始节点`。 public bool SearchAttackRange(IHowToFind howToFind, CellData start, int minRange, int maxRange, bool useEndCell = false) { if (howToFind == null || start == null || minRange < 1 || maxRange < minRange) { return false; } Reset(); m_HowToFind = howToFind; m_Range = new Vector2(minRange, maxRange); // 在重置时,不重置 `父亲节点` , // 其一:没有用到 // 其二:二次查找时不破坏路径,否则路径将被破坏 if (useEndCell) { m_EndCell = start; m_EndCell.g = 0f; m_Reachable.Add(m_EndCell); } else { m_StartCell = start; m_StartCell.g = 0f; m_Reachable.Add(m_StartCell); } return SearchRangeInternal(); }
当然,你还要记得修改
MapGraph
里的对应函数。 -
其次,修改
Reset
函数:在寻路过程中,我们会不断的重新计算A星的G和H,还有父亲节点。
在
Reset
时,我们不必每个都重置,只需要之前做的修改那样,将关键点重置(例如起始结束节点,而攻击范围没有用到父亲节点,所以只重置G)。/// <summary> /// 重置 /// </summary> public void Reset() { m_Reachable.Clear(); m_Explored.Clear(); m_Result.Clear(); m_Range = Vector2.zero; m_StartCell = null; m_EndCell = null; m_CurrentCell = null; m_Finished = false; m_HowToFind = null; m_MoveConsumption = null; m_SearchCount = 0; }
-
再次,添加获取消耗方法:
/// <summary> /// 获取移动消耗 /// </summary> /// <param name="terrainType"></param> /// <returns></returns> public float GetMoveConsumption(TerrainType terrainType) { if (m_MoveConsumption == null) { return 1f; } return m_MoveConsumption[terrainType]; }
-
最后,添加建立路径方法:
/// <summary> /// 建立路径List /// </summary> /// <param name="endCell"></param> /// <param name="useResult"></param> /// <returns></returns> public List<CellData> BuildPath(CellData endCell, bool useResult) { if (endCell == null) { Debug.LogError("PathFinding -> Argument named `endCell` is null."); return null; } List<CellData> path = useResult ? m_Result : new List<CellData>(); CellData current = endCell; path.Add(current); while (current.previous != null) { current = current.previous; path.Insert(0, current); } return path; } /// <summary> /// 建立路径Stack /// </summary> /// <param name="endCell"></param> /// <returns></returns> public Stack<CellData> BuildPath(CellData endCell) { if (endCell == null) { Debug.LogError("PathFinding -> Argument named `endCell` is null."); return null; } Stack<CellData> path = new Stack<CellData>(); CellData current = endCell; path.Push(current); while (current.previous != null) { current = current.previous; path.Push(c