public bool LineTest2(CMap map, CCreature cc, int x1, int y1, int x2, int y2, ref Vector2 lastPos) { //Profiler.BeginSample("LineTest2"); int dx = x2 - x1; int dy = y2 - y1; int ux = (dx > 0) ? 1 : -1; //x的增量方向,取或-1 int uy = (dy > 0) ? 1 : -1; //y的增量方向,取或-1 int x = x1, y = y1, eps; //eps为累加误差 //算法问题需要向增量方向在+1 x2 += ux; y2 += uy; eps = 0; dx = Mathf.Abs(dx); dy = Mathf.Abs(dy); if (dx > dy) { for (x = x1; x != x2; x += ux) { if (!map.CanArrive(cc, x, y)) { //Profiler.EndSample(); return(false); } lastPos.x = x; lastPos.y = y; //mpaths.Add(new Vector2(x, y)); eps += dy; if ((eps << 1) >= dx) { y += uy; eps -= dx; } } } else { for (y = y1; y != y2; y += uy) { if (!map.CanArrive(cc, x, y)) { //Profiler.EndSample(); return(false); } lastPos.x = x; lastPos.y = y; eps += dx; if ((eps << 1) >= dy) { x += ux; eps -= dy; } } } //Profiler.EndSample(); return(true); }
// 开始寻路 开始点、结束点、结果路径列表、最大搜索节点数 public bool FindPath(CMap map, CCreature cc, Vector2 startPt, Vector2 endPos, ref List <Vector2> paths, int maxRoute) { // 如果检测到是能走的直线,就取最后一个点为目的地 // 如果检测到不是能走的直线,取靠近目标点最近的并且能走的点,作为寻路的目标点 Vector2 vLastPos = Vector2.zero; if (LineTest2(map, cc, (int)startPt.x, (int)startPt.y, (int)endPos.x, (int)endPos.y, ref vLastPos)) { paths.Add(vLastPos); return(true); } // 如果目标点不能走,取检测直线时得出的,靠近目标点最近的并且能走的点 //if (null == map || !map.CanArriveDoubleInt(ref startPt) || !map.CanArriveDoubleInt(ref endPos)) if (null == map || !map.CanArrive(cc, (int)endPos.x, (int)endPos.y)) { m_nErrorType = ErrorCode.eErrParam; if (vLastPos != Vector2.zero) { paths.Add(vLastPos); //直线走到最近能走到的那个点需要缩放回去 //Profiler.EndSample(); return(true); } //Profiler.EndSample(); return(false); } // sPaths.Clear(); InitLists(0, 0); openNote((int)startPt.x, (int)startPt.y, 0, 0, 0); int currTry = 0; int currId = 0; int currNoteX = 0; int currNoteY = 0; int checkingId = 0; int cost = 0; int score = 0; Vector2[] aroundNodes = new Vector2[8]; int aroundCount = 0; while (m_nOpenCount > 0) { // 超时返回 if (++currTry > maxRoute) { m_nErrorType = ErrorCode.eErrMaxTry; //Profiler.EndSample(); //Debug.Log("超过最大遍历次数"); return(false); } // 每次取出开放列表最前面的ID currId = m_vOpenList[0]; //将编码为此ID的元素列入关闭列表 closeNote(currId); currNoteX = m_vXList[currId]; currNoteY = m_vYList[currId]; //如果终点被放入关闭列表寻路结束,返回路径 if (currNoteX == (int)endPos.x && currNoteY == (int)endPos.y) { bool bRef = getPath(ref startPt, ref endPos, currId, paths); //Profiler.EndSample(); return(bRef); } //获取周围节点,排除不可通过和已在关闭列表中的 getArounds(map, cc, currNoteX, currNoteY, ref aroundNodes, ref aroundCount); for (int index = 0; index < aroundCount; index++) { // 计算F和G值 cost = m_vMovementCostList[currId] + ((aroundNodes[index].x == currNoteX || aroundNodes[index].y == currNoteY) ? (int)CostSave.CostStraight : (int)CostSave.CostDiagonal); score = cost + (int)((Mathf.Abs(endPos.x - aroundNodes[index].x) + Mathf.Abs(endPos.y - aroundNodes[index].y)) * (float)CostSave.CostStraight); if (isOpen(map, (int)aroundNodes[index].x, (int)aroundNodes[index].y))//如果节点已在播放列表中 { checkingId = m_GlobleintAStar[(int)aroundNodes[index].y, (int)aroundNodes[index].x]; if (checkingId >= m_vMovementCostList.Count) { //Debug.LogWarning(string.Format("寻路出现问题场景{0}起始坐标[{1},{2}], 目标坐标[{3}, {4}]", map.GetMapID(), startPt.x, startPt.y, endPos.x, endPos.y)); return(false); } //如果新的G值比节点原来的G值小,修改F,G值,换父节点 if (cost < m_vMovementCostList[checkingId]) { m_vMovementCostList[checkingId] = cost; m_vPathScoreList[checkingId] = score; m_vFatherList[checkingId] = currId; aheadNote(getIndex(checkingId)); } } else//如果节点不在开放列表中 { //将节点放入开放列表 openNote((int)aroundNodes[index].x, (int)aroundNodes[index].y, score, cost, currId); } } } //如果找不到。那么走到可以走到的那个点上 if (vLastPos.x > 0 && paths.Count == 0) { //直线走到最近能走到的那个点需要缩放回去 //Profiler.EndSample(); return(true); } // 开放列表已空,找不到路径 m_nErrorType = ErrorCode.eErrCannotFind; //Profiler.EndSample(); return(false); }
// 获取某节点的周围节点,排除不能通过和已在关闭列表中的 bool getArounds(CMap map, CCreature cc, int p_x, int p_y, ref Vector2[] aroundNodes, ref int aroundCount) { //Vector2 pt = Vector2.zero; int checkX = 0; int checkY = 0; bool canDiagonal = false; bool canRight = false; bool canDown = false; bool canLeft = false; bool canUp = false; aroundCount = 0; // 右 checkX = p_x + 1; checkY = p_y; canRight = map.CanArrive(cc, checkX, checkY); if (canRight && !isClosed(checkX, checkY)) { aroundNodes[aroundCount++] = new Vector2(checkX, checkY); } // 下 checkX = p_x; checkY = p_y + 1; canDown = map.CanArrive(cc, checkX, checkY); if (canDown && !isClosed(checkX, checkY)) { aroundNodes[aroundCount++] = new Vector2(checkX, checkY); } // 左 checkX = p_x - 1; checkY = p_y; canLeft = map.CanArrive(cc, checkX, checkY); if (canLeft && !isClosed(checkX, checkY)) { aroundNodes[aroundCount++] = new Vector2(checkX, checkY); } // 上 checkX = p_x; checkY = p_y - 1; canUp = map.CanArrive(cc, checkX, checkY); if (canUp && !isClosed(checkX, checkY)) { aroundNodes[aroundCount++] = new Vector2(checkX, checkY); } // 右下 checkX = p_x + 1; checkY = p_y + 1; canDiagonal = map.CanArrive(cc, checkX, checkY); if (canDiagonal && canRight && canDown && !isClosed(checkX, checkY)) { aroundNodes[aroundCount++] = new Vector2(checkX, checkY); } // 左下 checkX = p_x - 1; checkY = p_y + 1; canDiagonal = map.CanArrive(cc, checkX, checkY); if (canDiagonal && canLeft && canDown && !isClosed(checkX, checkY)) { aroundNodes[aroundCount++] = new Vector2(checkX, checkY); } // 左上 checkX = p_x - 1; checkY = p_y - 1; canDiagonal = map.CanArrive(cc, checkX, checkY); if (canDiagonal && canLeft && canUp && !isClosed(checkX, checkY)) { aroundNodes[aroundCount++] = new Vector2(checkX, checkY); } // 右上 checkX = p_x + 1; checkY = p_y - 1; canDiagonal = map.CanArrive(cc, checkX, checkY); if (canDiagonal && canRight && canUp && !isClosed(checkX, checkY)) { aroundNodes[aroundCount++] = new Vector2(checkX, checkY); } return(true); }