/// <summary> /// 得到指定点周围的八个点 /// </summary> private void OnGetStartBorderPos(gridItem gridItem_) { // 得到周围格子中位置最小点(目标格子相邻左下角的格子) float findMinX = gridItem_.gridPos.x - (1 + space); float findMinZ = gridItem_.gridPos.z - (1 + space); // 得到周围的格子 for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { float x = i * (1 + space); float z = j * (1 + space); Vector3 nPos = new Vector3(findMinX + x, 0, findMinZ + z); // 在格子列表中查找格子 gridItem gridItem = null; foreach (KeyValuePair <GameObject, gridItem> val in gridDict) { // 通过位置找到相邻格子 if (val.Value.gridPos == nPos) { // 过滤掉自己和障碍物和寻到的格子 if (val.Value.gridObj != startPosObj && !barrierGridDict.ContainsKey(val.Value.gridObj) && !pathList.ContainsKey(val.Value.gridObj)) { gridItem = val.Value; break; } } } // 如果格子存在,填充到零时列表中 if (gridItem != null) { //Debug.Log("找到 " + nPos); borderGridList.Add(gridItem); } else { //Debug.Log("没有找到 " + nPos); } } } }
/// <summary> /// 得到相邻格子的移动成本 /// </summary> private void OnGetBorderGridMoveCost(gridItem startPos_) { for (int i = 0; i < borderGridList.Count; ++i) { gridItem item = borderGridList[i]; if (item.gridPos.x == startPos_.gridPos.x || item.gridPos.z == startPos_.gridPos.z) { //Debug.Log("成本小 " + item.gridObj.name); item.moveCost = 10; } else { //Debug.Log("成本大 " + item.gridObj.name); item.moveCost = 14; } } }
/// <summary> /// 创建格子 /// </summary> private void OnCreatGrid() { for (int i = 0; i < xNum; ++i) { for (int j = 0; j < yNum; ++j) { float posX = i + (i * space); float posY = 0; float posZ = j + (j * space); GameObject gridObj = GameObject.Instantiate(objTemp); gridObj.name = "Grid X=" + posX + " Z=" + posZ; gridObj.layer = LayerMask.NameToLayer("Grid"); gridObj.gameObject.SetActive(true); gridObj.transform.SetParent(parent.transform); gridObj.transform.position = new Vector3(posX, posY, posZ); gridDict[gridObj] = new gridItem(new Vector3(posX, posY, posZ), gridObj); } } }
/// <summary> /// 得到相邻格子到目标到的长度 /// </summary> private void OnGetBorderGridTargetLength(gridItem targetGridItem_) { for (int i = 0; i < borderGridList.Count; ++i) { gridItem item = borderGridList[i]; // ---------曼哈顿估价法(自己的实现)--------- (乘10是为了简化估价计算) // PS:计算估价有三种算法:曼哈顿估价法、几何估价法、对角线估价法 // 曼哈顿估价法和我这里实现是一样,不过有些问题,如果两个格子在同一行(x轴相同),并且中间隔了障碍物。这个时候在起始点会多寻出点 // 具体原因:是因为查找相邻八个格子顺序问题,导致先找到的格子会被先使用。暂时没有想到更好的办法 //float xLength = Mathf.Abs(targetGridItem_.gridPos.x - item.gridPos.x) * 10; //float zLength = Mathf.Abs(targetGridItem_.gridPos.z - item.gridPos.z) * 10; //item.targetLength = (int)(xLength + zLength); // ---------曼哈顿估价法(自己的实现)--------- // ---------对角线估价法(网上的算法)--------- // 为了解决上面曼哈顿算法的问题和使计算步长更优,这里就使用对角线算法。 // 当然还有几何算法,但是个人感觉不是最优的,因为对角线是集合了曼哈顿和几何算法思路的。 // 对角线估价法,暂时还没弄的很明白,乘14和乘10应该也是为了简化计算和计算移动代价没关系 float cntX = Mathf.Abs(item.gridPos.x - targetGridItem_.gridPos.x); float cntZ = Mathf.Abs(item.gridPos.z - targetGridItem_.gridPos.z); if (cntX > cntZ) { item.targetLength = (int)(14 * cntZ + 10 * (cntX - cntZ)); } else { item.targetLength = (int)(14 * cntX + 10 * (cntZ - cntX)); } // ---------对角线估价法(网上的算法)--------- // 计算权重(因为这里是得到计算权重值的最后一个参数) item.weight = item.moveCost + item.targetLength; //Debug.Log(item.gridObj.name + " 步长 " + item.targetLength); } }
/// <summary> /// 添加格子到路径列表中 /// </summary> private void OnAddPaht(gridItem pathGrid_) { // 加入新的路径 pathList[pathGrid_.gridObj] = pathGrid_; }
/// <summary> /// 执行寻路 /// </summary> private void OnPlayerFindPath() { // 清空相邻格子 borderGridList.Clear(); gridItem startGridItem = gridDict[startPosObj]; gridItem targetGridItem = gridDict[TargetPosObj]; // 得到八个相邻格子 OnGetStartBorderPos(startGridItem); // 得到相邻格子的移动成本 OnGetBorderGridMoveCost(startGridItem); // 得到相邻格子到目标到的步长 OnGetBorderGridTargetLength(targetGridItem); // 得到下一个移动点(权重最小的格子) gridItem newStarGridItem = null; for (int i = 0; i < borderGridList.Count; ++i) { gridItem item = borderGridList[i]; //Debug.Log("权重 " + item.weight); if (newStarGridItem != null) { if (item.weight < newStarGridItem.weight) { newStarGridItem = item; } } else { newStarGridItem = item; } } //Debug.Log("权重最小 "+ newStarGridItem.gridObj.name +" " + newStarGridItem.weight); // 将新的路径点加入路径列表并更新起始点 if (newStarGridItem != null) { // ------------判断是否需要继续寻路------------ bool isFindPath = true; for (int i = 0; i < borderGridList.Count; ++i) { gridItem item = borderGridList[i]; if (item.gridObj == targetGridItem.gridObj) { isFindPath = false; break; } } if (isFindPath) { startPosObj = newStarGridItem.gridObj; OnAddPaht(newStarGridItem); // 将路径格子改变颜色(调试使用功能) OnSetModelMaterColor(newStarGridItem.gridObj, Color.gray); OnPlayerFindPath(); } // ------------判断是否需要继续寻路------------ } }