导航地图NavMap,会把之前的逻辑串联起来,有关键字partial分部类和方法,声明了,各个寻路顶点的数据容器,寻路区域的数组; 还有边界字典borderDic和areaIDDic,用来处理,可用的区域边界; 另外还有3个Action委托函数,用来处理,Scene场景,配合NavView相关逻辑,绘制寻路结果;

GetBorderLstByAreaID函数接口,通过区域id,从边界字典borderDic,拿到对应的边界队列容器

设置基础节点数据,是遍历所有的,节点,根据索引大小,设置key关联字符

继续,如果borderDic边界字典容器,包含上述key索引,就会调用边界的areaID1和areaID2,两个区域ID,完成新key构建,放到areaIDDic边界字典容器;而且这个不是单独的边界,isShared布尔,会设置为true;

一开始的时候,是没有对应key的,就往边界字典borderDic里面,构建NavBorder边界体,加到容器即可;

这是单独边界

这些是isShared为true的共享边界

继续,通过边界的isShared布尔变量,加到singleLst队列容器,再从边界字典borderDic中移除它们; 使用,上述解析的GetBorderLstByAreaID函数,通过区域id索引areaID,对区域的边界队列borderLst完成赋值;

GetBorderByAreaIDKey接口,通过key在区域字典areaIDDic中,拿到它的边界

OnXZSegment接口,判断叉乘是否为0,也就是面积为0,点乘为负数,也就是方向相反,判断落点是否在线条上; 这个接口,后续是用于,判断落点是否在,寻路的检测区域内,如果在线上,那就肯定在区域内了,所以直接返回true即可,参考向量Dot点乘与Cross叉乘的概念及几何意义

通过PNPoly算法,配合OnXZSegment接口,判断向量点,是否在检测区域内

算法对应的C语言公式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
{
  int i, j, c = 0;
  for (i = 0, j = nvert-1; i < nvert; j = i++) {
    if ( ((verty[i]>testy) != (verty[j]>testy)) &&
	 (testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
       c = !c;
  }
  return c;
}

调用,上述检测区域接口,判断传参坐标pos,是否在检测区域,然后返回,对应的检测区域id即可

这是一个自定义堆队列类PEQue,也是继承自IComparable接口,具体逻辑解析,参考基于堆实现优先级队列即可

导航地图NavMap的分部类,对应的脚本位置

它的结构,是由两个region组成,分别是A星算法和漏斗算法

A星算法,主要是用于,检测开始点,和结束点,它们之间的寻路路径,所路过的NavArea寻路区域; 声明开始点、结束点,所在对应的区域m_startArea和m_endArea; 而检测队列m_detectQue会使用,上述优先级队列相关逻辑; 另外还有两个队列容器,分别是已完成检测的m_finishLst,和最终返回得到的,所路过的m_pathLst区域队列容器;

检测周边区域的核心逻辑; 完成邻近区域的,前一个区域preArea字段,和总距离sumDistance字段赋值; 通过一系列布尔判断后,放到已检测队列容器m_detectQue,参考IsPositiveInfinity; 通过寻路区域的,CalcNavAreaDis接口,拿到跟最终位置区域的距离,加上当前寻路总距离sumDistance,作为priority优先级赋值,具体逻辑解析, A星寻路算法即可;

跟A星算法相关逻辑一样,倒着获取,寻路的前一个节点preArea; 从最终寻路的结束点end,通过while死循环函数,倒着找,前一个节点preArea,直到它是null空值为止; 然后,使用分部类NavMap中GetBorderByAreaIDKey接口,通过key,在区域字典areaIDDic中,拿到对应的边界即可