float CaculateNodeCost(PlayerAtt player, PathFindNodeItem a, PathFindNodeItem b) { bool needClimb = false; bool needJump = false; if (b.Height - a.Height > grid.CanPathThrethhold) { needClimb = true; } else if (a.Height - b.Height > grid.CanPathThrethhold) { needJump = true; } float distance = getDistanceNodes(a, b); float cost = distance / player.moveSpeed; if (needClimb) { if (player.climbSpeed > 0.0f) { float climpcost = (b.Height - a.Height) / player.climbSpeed; cost += climpcost; } else { cost = -1.0f; } } if (needJump) { } return(cost); }
// 生成路径 void generatePath(PathFindNodeItem startNode, PathFindNodeItem endNode) { List <PathFindNodeItem> path = new List <PathFindNodeItem>(); if (endNode != null) { PathFindNodeItem temp = endNode; while (temp != startNode) { path.Add(temp); temp = temp.parent; } // 反转路径 path.Reverse(); } // 更新路径 grid.updatePath(path); }
// 获取两个节点之间的距离 float getDistanceNodes(PathFindNodeItem a, PathFindNodeItem b) { float ret; float cntX = Mathf.Abs(a.x - b.x); float cntY = Mathf.Abs(a.y - b.y); // 判断到底是那个轴相差的距离更远 if (cntX > cntY) { ret = 14.14f * cntY + 10.0f * (cntX - cntY); } else { ret = 14.14f * cntX + 10.0f * (cntY - cntX); } float heightdiff = Mathf.Abs(b.Height - a.Height); ret += heightdiff; return(ret); }
void Awake() { // 初始化格子 w = Mathf.RoundToInt(transform.localScale.x * 2); h = Mathf.RoundToInt(transform.localScale.y * 2); grid = new PathFindNodeItem[w, h]; WallRange = new GameObject("WallRange"); PathRange = new GameObject("PathRange"); // 将墙的信息写入格子中 for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { Vector3 pos = new Vector3(x * 0.5f, y * 0.5f, 0); // 通过节点中心发射圆形射线,检测当前位置是否可以行走 bool isWall = Physics.CheckSphere(pos, NodeRadius, WhatLayer); // 构建一个节点 grid[x, y] = new PathFindNodeItem(isWall, pos, x, y); if (isWall) { grid[x, y].Height = 3.0f; } // 如果是墙体,则画出不可行走的区域 if (isWall) { GameObject obj = GameObject.Instantiate(NodeWall, pos, Quaternion.identity) as GameObject; obj.transform.SetParent(WallRange.transform); } else { // GameObject obj = GameObject.Instantiate( Node, pos, Quaternion.identity ) as GameObject; // / obj.transform.SetParent( WallRange.transform ); } } } }
// 取得周围的节点 public List <PathFindNodeItem> getNeibourhood(PathFindNodeItem node) { List <PathFindNodeItem> list = new List <PathFindNodeItem>(); for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { // 如果是自己,则跳过 if (i == 0 && j == 0) { continue; } int x = node.x + i; int y = node.y + j; // 判断是否越界,如果没有,加到列表中 if (x < w && x >= 0 && y < h && y >= 0) { list.Add(grid[x, y]); } } } return(list); }
// A*寻路 void FindingPath(PlayerAtt player, Vector3 s, Vector3 e) { PathFindNodeItem startNode = grid.getItem(s); PathFindNodeItem endNode = grid.getItem(e); List <PathFindNodeItem> openSet = new List <PathFindNodeItem>(); HashSet <PathFindNodeItem> closeSet = new HashSet <PathFindNodeItem>(); openSet.Add(startNode); while (openSet.Count > 0) { PathFindNodeItem curNode = openSet[0]; for (int i = 0, max = openSet.Count; i < max; i++) { if (openSet[i].fCost <= curNode.fCost) { curNode = openSet[i]; } } openSet.Remove(curNode); closeSet.Add(curNode); // 找到的目标节点 if (curNode == endNode) { Debug.Log("cost is :" + curNode.gCost.ToString()); generatePath(startNode, endNode); return; } // 判断周围节点,选择一个最优的节点 foreach (var item in grid.getNeibourhood(curNode)) { // 如果是墙或者已经在关闭列表中 float neibourCost = CaculateNodeCost(player, curNode, item); if (neibourCost == -1.0f || closeSet.Contains(item)) { continue; } // 计算当前相领节点现开始节点距离 float newCost = curNode.gCost + neibourCost; // 如果距离更小,或者原来不在开始列表中 if (newCost < item.gCost || !openSet.Contains(item)) { // 更新与开始节点的距离 item.gCost = newCost; // 更新与终点的距离 item.hCost = getDistanceNodes(item, endNode) / player.moveSpeed; // 更新父节点为当前选定的节点 item.parent = curNode; // 如果节点是新加入的,将它加入打开列表中 if (!openSet.Contains(item)) { openSet.Add(item); } } } } generatePath(startNode, null); }