//~ static public void GetPathX(Vector3 startP, Vector3 endP, Node[] graph, SetPathCallback callBackFunc){ //~ Node startN=GetNearestNode(startP, graph); //~ Node endN=GetNearestNode(endP, graph); //~ //GetPath(startNode, endNode, null, graph, callBackFunc, false, true); //~ if(!searching){ //~ //commence search //~ Search(startN, endN, null, graph, callBackFunc, true); //~ } //~ else{ //~ //if a serach is in progress, put current request into a list //~ SearchQueue q=new SearchQueue(startN, endN, null, graph, callBackFunc); //~ if(urgent) queue.Insert(0, q); //~ else queue.Add(q); //~ } //~ } static public void GetPath(Vector3 startP, Vector3 endP, NodeTD[] graph, SetPathCallbackTD callBackFunc) { NodeTD startNode = GetNearestNode(startP, graph); NodeTD endNode = GetNearestNode(endP, graph); GetPath(startNode, endNode, null, graph, callBackFunc, false); }
public void InitNode(NodeTD[] nodeGraph) { Vector3 prevPoint; if (prevNeighbouringWP.platform != null) { Debug.Log("dong"); //place holder, platform to platform connection not supported yet prevPoint = prevNeighbouringWP.platform.thisT.position; } else { prevPoint = prevNeighbouringWP.pos; } startN = PathFinderTD.GetNearestNode(prevPoint, nodeGraph); Vector3 nextPoint; if (nextNeighbouringWP.platform != null) { Debug.Log("ding"); //place holder, platform to platform connection not supported yet nextPoint = nextNeighbouringWP.platform.thisT.position; } else { nextPoint = nextNeighbouringWP.pos; } endN = PathFinderTD.GetNearestNode(nextPoint, nodeGraph); //Debug.DrawLine(endN.pos, endN.pos+new Vector3(0, 2, 0), Color.red, 5); //Debug.DrawLine(startN.pos, startN.pos+new Vector3(0, 2, 0), Color.blue, 5); //Debug.DrawLine(nextNeighbouringWP.pos, nextNeighbouringWP.pos+new Vector3(0, 2, 0), Color.green, 5); }
public void Prebuild(Vector3 point, UnitTower tower) { if (nodeGraph == null || nodeGraph.Length == 0) { return; } NodeTD node = PathFinderTD.GetNearestNode(point, nodeGraph, 0); node.walkable = false; List <NodeTD> nodeList = PathFinderTD.GetNodeInFootprint(node, tower.GetFootprint()); foreach (NodeTD n in nodeList) { n.walkable = false; } tower.SetPlatform(this, node); foreach (PathOnPlatform pathObj in pathObjects) { queue.Add(pathObj.thisWP); PathFinderTD.GetPath(pathObj.startN, pathObj.endN, nodeGraph, this.SetPath); } }
public SearchQueue(NodeTD n1, NodeTD n2, NodeTD n3, NodeTD[] g, SetPathCallbackTD func) { startNode = n1; endNode = n2; blockNode = n3; graph = g; callBackFunc = func; }
public void Build(Vector3 point, UnitTower tower) { //pathfinding related code, only call if this platform is walkable; if (walkable) { if (tower.type != _TowerType.Mine) { //if build on the node last check for block, use the cached node and path if (nextBuildNode != null && Vector3.Distance(nextBuildNode.pos, point) < BuildManager.GetGridSize() / 2) { //Debug.Log("use cached path"); nextBuildNode.walkable = false; List <NodeTD> nodeList = PathFinderTD.GetNodeInFootprint(nextBuildNode, tower.GetFootprint()); foreach (NodeTD node in nodeList) { node.walkable = false; } tower.SetPlatform(this, nextBuildNode); foreach (PathOnPlatform pathObj in pathObjects) { int rand = pathObj.pathID; while (rand == pathObj.pathID) { rand = Random.Range(-999999, 999999); } pathObj.SetPath(pathObj.altPath, rand); //forceSearch doesnt smooth path so path smoothing is call //smoothPath will only valid path smoothing is enable in PathFinder pathObj.SmoothPath(); } } //if build on node that is unchecked, find the block node and initiate a new path search else { //Debug.Log("unexpected build point, query for new path"); NodeTD node = PathFinderTD.GetNearestNode(point, nodeGraph); node.walkable = false; //~ Debug.Log(node.ID); List <NodeTD> nodeList = PathFinderTD.GetNodeInFootprint(node, tower.GetFootprint()); foreach (NodeTD n in nodeList) { n.walkable = false; } tower.SetPlatform(this, node); foreach (PathOnPlatform pathObj in pathObjects) { queue.Add(pathObj.thisWP); PathFinderTD.GetPath(pathObj.startN, pathObj.endN, nodeGraph, this.SetPath); } } } } }
void BlockNode(Vector3 pos) { NodeTD node = GetNearestWalkableNode(pos); pos.y = node.pos.y; if (Vector3.Distance(pos, node.pos) < NodeGeneratorTD._gridSize / 2) { node.walkable = false; } }
void UnblockNode(Vector3 pos) { NodeTD node = GetNearestUnwalkableNode(pos); if (node != null) { pos.y = node.pos.y; if (Vector3.Distance(pos, node.pos) < NodeGeneratorTD._gridSize / 2) { node.walkable = true; } } }
IEnumerator CycleNode() { int counter = 0; while (true) { yield return(new WaitForSeconds(0.15f)); currentNode = nodeGraph[counter]; counter += 1; if (counter == nodeGraph.Length) { counter = 0; } } }
static public NodeTD GetNearestNode(Vector3 point, NodeTD[] graph, int searchMode) { float dist = Mathf.Infinity; float currentNearest = Mathf.Infinity; NodeTD nearestNode = null; foreach (NodeTD node in graph) { if (searchMode == 0) { dist = Vector3.Distance(point, node.pos); if (dist < currentNearest) { currentNearest = dist; nearestNode = node; } } else if (searchMode == 1) { if (node.walkable) { dist = Vector3.Distance(point, node.pos); if (dist < currentNearest) { currentNearest = dist; nearestNode = node; } } } else if (searchMode == 2) { if (!node.walkable) { dist = Vector3.Distance(point, node.pos); if (dist < currentNearest) { currentNearest = dist; nearestNode = node; } } } } return(nearestNode); }
NodeTD GetNearestUnwalkableNode(Vector3 point) { float dist = Mathf.Infinity; float currentNearest = Mathf.Infinity; NodeTD nearestNode = null; foreach (NodeTD node in nodeGraph) { if (!node.walkable) { dist = Vector3.Distance(point, node.pos); if (dist < currentNearest) { currentNearest = dist; nearestNode = node; } } } return(nearestNode); }
NodeTD GetNearestWalkableNode(Vector3 point) { float dist = Mathf.Infinity; float currentNearest = Mathf.Infinity; NodeTD nearestNode = null; //float rangeTH=gridSize*1.5; foreach (NodeTD node in nodeGraph) { if (node.walkable) { dist = Vector3.Distance(point, node.pos); if (dist < currentNearest) { currentNearest = dist; nearestNode = node; //if(currentNearest<rangeTH) break; } } } return(nearestNode); }
static public void GetPath(NodeTD startN, NodeTD endN, NodeTD blockN, NodeTD[] graph, SetPathCallbackTD callBackFunc, bool urgent) { CheckInit(); if (!searching) { //commence search Search(startN, endN, blockN, graph, callBackFunc); } else { //if a serach is in progress, put current request into a list SearchQueue q = new SearchQueue(startN, endN, blockN, graph, callBackFunc); if (urgent) { queue.Insert(0, q); } else { queue.Add(q); } } }
public void UnBuild(NodeTD node, int footprint) { footprint = 0; //Debug.Log("unbuild "+node.ID); node.walkable = true; List <NodeTD> nodeList = PathFinderTD.GetNodeInFootprint(node, footprint); foreach (NodeTD n in nodeList) { n.walkable = true; } foreach (PathOnPlatform pathObj in pathObjects) { //~ Debug.Log("update path"); queue.Add(pathObj.thisWP); PathFinderTD.GetPath(pathObj.startN, pathObj.endN, nodeGraph, this.SetPath); } }
public void UnBuild(NodeTD node) { UnBuild(node, 0); }
void GenerateNode() { //float gridSize=GameControl.gameControlCom.TDS.gridSize; agentHeight = Mathf.Max(agentHeight, gridSize); area.x = Mathf.Floor(area.x / gridSize) * gridSize; area.y = Mathf.Floor(area.y / gridSize) * gridSize; area.width = Mathf.Floor(area.width / gridSize) * gridSize; area.height = Mathf.Floor(area.height / gridSize) * gridSize; nodeGraph = new NodeTD[(int)((area.width - area.x) / gridSize * (area.height - area.y) / gridSize)]; float timeStart = Time.realtimeSinceStartup; int counter = 0; float heightOffset = agentHeight / 2; for (float j = area.y; j < area.height; j += gridSize) { for (float i = area.x; i < area.width; i += gridSize) { RaycastHit hit1; if (Physics.Raycast(new Vector3(i, 500, j), Vector3.down, out hit1)) { nodeGraph[counter] = new NodeTD(new Vector3(i, hit1.point.y + heightOffset, j), counter); } else { nodeGraph[counter] = new NodeTD(new Vector3(i, 0, j), counter); nodeGraph[counter].walkable = false; } counter += 1; } } //Debug.Log(counter); float timeUsed = Time.realtimeSinceStartup - timeStart; //Debug.Log("generate "+counter+" nodes, used "+timeUsed+"seconds"); counter = 0; RaycastHit hit2; foreach (NodeTD cNode in nodeGraph) { if (cNode.walkable) { if (Physics.SphereCast(cNode.pos + new Vector3(0, heightOffset + heightOffset * 0.1f, 0), gridSize * 0.45f, Vector3.down, out hit2, heightOffset)) { cNode.walkable = false; counter += 1; } } } //if(counter>0) Debug.Log(counter+" node is unwalkable"); float neighbourDistance = 0; float neighbourRange; if (connectDiagonalNeighbour) { neighbourRange = gridSize * 1.5f; } else { neighbourRange = gridSize * 1.1f; } timeStart = Time.realtimeSinceStartup; int rowLength = (int)Mathf.Floor((area.width - area.x) / gridSize); int columnLength = (int)Mathf.Floor((area.height - area.y) / gridSize); counter = 0; //assign the neighouring node for each node in the grid foreach (NodeTD currentNode in nodeGraph) { //only if that node is walkable if (currentNode.walkable) { //create an empty array List <NodeTD> neighbourNodeList = new List <NodeTD>(); List <float> neighbourCostList = new List <float>(); NodeTD[] neighbour = new NodeTD[8]; int id = currentNode.ID; if (id > rowLength - 1 && id < rowLength * columnLength - rowLength) { //print("middle rows"); if (id != rowLength) { neighbour[0] = nodeGraph[id - rowLength - 1]; } neighbour[1] = nodeGraph[id - rowLength]; neighbour[2] = nodeGraph[id - rowLength + 1]; neighbour[3] = nodeGraph[id - 1]; neighbour[4] = nodeGraph[id + 1]; neighbour[5] = nodeGraph[id + rowLength - 1]; neighbour[6] = nodeGraph[id + rowLength]; if (id != rowLength * columnLength - rowLength - 1) { neighbour[7] = nodeGraph[id + rowLength + 1]; } } else if (id <= rowLength - 1) { //print("first row"); if (id != 0) { neighbour[0] = nodeGraph[id - 1]; } neighbour[1] = nodeGraph[id + 1]; neighbour[2] = nodeGraph[id + rowLength - 1]; neighbour[3] = nodeGraph[id + rowLength]; neighbour[4] = nodeGraph[id + rowLength + 1]; } else if (id >= rowLength * columnLength - rowLength) { //print("last row"); neighbour[0] = nodeGraph[id - 1]; if (id != rowLength * columnLength - 1) { neighbour[1] = nodeGraph[id + 1]; } neighbour[2] = nodeGraph[id - rowLength - 1]; neighbour[3] = nodeGraph[id - rowLength]; neighbour[4] = nodeGraph[id - rowLength + 1]; } //scan through all the node in the grid foreach (NodeTD node in neighbour) { //if this the node is not currentNode if (node != null && node.walkable) { //if this node is within neighbour node range neighbourDistance = GetHorizontalDistance(currentNode.pos, node.pos); if (neighbourDistance < neighbourRange) { //if nothing's in the way between these two if (!Physics.Linecast(currentNode.pos, node.pos)) { //if the slop is not too steep if (Mathf.Abs(GetSlope(currentNode.pos, node.pos)) <= maxSlope) { //add to list //if(!node.walkable) Debug.Log("error"); neighbourNodeList.Add(node); neighbourCostList.Add(neighbourDistance); } //else print("too steep"); } //else print("something's in the way"); } //else print("out of range "+neighbourDistance); } } //set the list as the node neighbours array currentNode.SetNeighbour(neighbourNodeList, neighbourCostList); //if(neighbourNodeList.Count==0) //Debug.Log("no heighbour. node number "+counter+" "+neighbourNodeList.Count); } //Debug.Log(currentN.pos+" "+currentNode.neighbourNode.length); counter += 1; } //timeUsed=Time.realtimeSinceStartup-timeStart; //Debug.Log("connect neighbour for "+counter+" nodes, used "+timeUsed+"seconds"); }
static public NodeTD[] GenerateNode(PlatformTD platform, float heightOffset) { //check if node generator CheckInit(); //Debug.Log("generating nav node for "+platform.thisT); float timeStart = Time.realtimeSinceStartup; Transform platformT = platform.thisT; float gridSize = BuildManager.GetGridSize(); float scaleX = platform.thisT.localScale.x; float scaleZ = platform.thisT.localScale.z; int countX = (int)(10 * scaleX / gridSize); int countZ = (int)(10 * scaleZ / gridSize); //Debug.Log(countX+" "+countZ); float x = -scaleX * 10 / 2 / scaleX; float z = -scaleZ * 10 / 2 / scaleZ; Vector3 point = platformT.TransformPoint(new Vector3(x, 0, z)); thisT.position = point; thisT.rotation = platformT.rotation; thisT.position = thisT.TransformPoint(new Vector3(gridSize / 2, heightOffset, gridSize / 2)); NodeTD[] nodeGraph = new NodeTD[countZ * countX]; int counter = 0; for (int i = 0; i < countZ; i++) { for (int j = 0; j < countX; j++) { nodeGraph[counter] = new NodeTD(thisT.position, counter); counter += 1; thisT.position = thisT.TransformPoint(new Vector3(gridSize, 0, 0)); } thisT.position = thisT.TransformPoint(new Vector3(-(countX) * gridSize, 0, gridSize)); } thisT.position = Vector3.zero; thisT.rotation = Quaternion.identity; float timeUsed = Time.realtimeSinceStartup - timeStart; //Debug.Log("generate "+counter+" nodes, used "+timeUsed+"seconds"); counter = 0; foreach (NodeTD cNode in nodeGraph) { if (cNode.walkable) { //check if there's anything within the point LayerMask mask = 1 << LayerManager.LayerPlatform(); mask |= 1 << LayerManager.LayerTower(); if (LayerManager.LayerTerrain() >= 0) { mask |= 1 << LayerManager.LayerTerrain(); } Collider[] cols = Physics.OverlapSphere(cNode.pos, gridSize * 0.45f, ~mask); if (cols.Length > 0) { cNode.walkable = false; counter += 1; } } } //if(counter>0) Debug.Log(counter+" node is unwalkable"); float neighbourDistance = 0; float neighbourRange; if (nodeGenerator.connectDiagonalNeighbour) { neighbourRange = gridSize * 1.5f; } else { neighbourRange = gridSize * 1.1f; } timeStart = Time.realtimeSinceStartup; counter = 0; //assign the neighouring node for each node in the grid foreach (NodeTD currentNode in nodeGraph) { //only if that node is walkable if (currentNode.walkable) { //create an empty array List <NodeTD> neighbourNodeList = new List <NodeTD>(); List <float> neighbourCostList = new List <float>(); NodeTD[] neighbour = new NodeTD[8]; int id = currentNode.ID; if (id > countX - 1 && id < countX * countZ - countX) { //print("middle rows"); if (id != countX) { neighbour[0] = nodeGraph[id - countX - 1]; } neighbour[1] = nodeGraph[id - countX]; neighbour[2] = nodeGraph[id - countX + 1]; neighbour[3] = nodeGraph[id - 1]; neighbour[4] = nodeGraph[id + 1]; neighbour[5] = nodeGraph[id + countX - 1]; neighbour[6] = nodeGraph[id + countX]; if (id != countX * countZ - countX - 1) { neighbour[7] = nodeGraph[id + countX + 1]; } } else if (id <= countX - 1) { //print("first row"); if (id != 0) { neighbour[0] = nodeGraph[id - 1]; } if (nodeGraph.Length > id + 1) { neighbour[1] = nodeGraph[id + 1]; } if (countZ > 0) { if (nodeGraph.Length > id + countX - 1) { neighbour[2] = nodeGraph[id + countX - 1]; } if (nodeGraph.Length > id + countX) { neighbour[3] = nodeGraph[id + countX]; } if (nodeGraph.Length > id + countX + 1) { neighbour[4] = nodeGraph[id + countX + 1]; } } } else if (id >= countX * countZ - countX) { //print("last row"); neighbour[0] = nodeGraph[id - 1]; if (id != countX * countZ - 1) { neighbour[1] = nodeGraph[id + 1]; } neighbour[2] = nodeGraph[id - countX - 1]; neighbour[3] = nodeGraph[id - countX]; neighbour[4] = nodeGraph[id - countX + 1]; } //scan through all the node in the grid foreach (NodeTD node in neighbour) { //if this the node is not currentNode if (node != null && node.walkable) { //if this node is within neighbour node range neighbourDistance = GetHorizontalDistance(currentNode.pos, node.pos); if (neighbourDistance < neighbourRange) { //if nothing's in the way between these two LayerMask mask = 1 << LayerManager.LayerPlatform(); mask |= 1 << LayerManager.LayerTower(); if (!Physics.Linecast(currentNode.pos, node.pos, ~mask)) { //if the slop is not too steep //if(Mathf.Abs(GetSlope(currentNode.pos, node.pos))<=maxSlope){ //add to list //if(!node.walkable) Debug.Log("error"); neighbourNodeList.Add(node); neighbourCostList.Add(neighbourDistance); //}//else print("too steep"); } //else print("something's in the way"); } //else print("out of range "+neighbourDistance); } //else print("unwalkable"); } //set the list as the node neighbours array currentNode.SetNeighbour(neighbourNodeList, neighbourCostList); //if(neighbourNodeList.Count==0) //Debug.Log("no heighbour. node number "+counter+" "+neighbourNodeList.Count); } //Debug.Log(currentN.pos+" "+currentNode.neighbourNode.length); counter += 1; } //timeUsed=Time.realtimeSinceStartup-timeStart; //Debug.Log("connect neighbour for "+counter+" nodes, used "+timeUsed+"seconds"); return(nodeGraph); }
public void ProcessNeighbour(NodeTD node) { ProcessNeighbour(node.pos); }
//if this platform is part of a path, this function set the previous and next transform //public void SetNeighbouringWP(PathSection prev, PathSection next){ // prevNeighbouringWP=prev; // nextNeighbouringWP=next; //} //check if building on particular point of the platform will block all possible route //use brute force check to return a flag instantly. try find a more perfomance friendly solution public bool CheckForBlock(Vector3 pos, int footprint) { float gridSize = BuildManager.GetGridSize(); bool blocked = false; nextBuildNode = PathFinderTD.GetNearestNode(pos, nodeGraph); //Debug.DrawLine(nextBuildNode.pos, nextBuildNode.pos+new Vector3(0, 2, 0), Color.red, 0.5f); foreach (PathOnPlatform pathObj in pathObjects) { //Debug.Log("check path for "+pathObj.path); //check if the start of end has been blocked if (Vector3.Distance(pos, pathObj.startN.pos) < gridSize / 2) { return(true); } if (Vector3.Distance(pos, pathObj.endN.pos) < gridSize / 2) { return(true); } //check if the node is in currentPath, if not, then the node is buildable //this is only applicable if pathSmoothing is off if (!PathFinderTD.IsPathSmoothingOn()) { bool inCurrentPath = false; foreach (Vector3 pathPoint in pathObj.currentPath) { float dist = Vector3.Distance(pos, pathPoint); if (dist < gridSize / 2) { inCurrentPath = true; break; } } if (inCurrentPath) { //the current node is in current path, check to see if there's other alternative path if this one's blocked //while getting another path, cache it so it can be used later without redo the search //use force instant search so the path is return immediately pathObj.altPath = PathFinderTD.ForceSearch(pathObj.startN, pathObj.endN, nextBuildNode, nodeGraph, footprint); if (pathObj.altPath.Count == 0) { blocked = true; } } else { pathObj.altPath = pathObj.currentPath; } } else { //the current node is in current path, check to see if there's other alternative path if this one's blocked //while getting another path, cache it so it can be used later without redo the search //use force instant search so the path is return immediately pathObj.altPath = PathFinderTD.ForceSearch(pathObj.startN, pathObj.endN, nextBuildNode, nodeGraph, footprint); if (pathObj.altPath.Count == 0) { blocked = true; } if (blocked) { break; } } } return(blocked); /* * float gridSize=BuildManager.GetGridSize(); * * //check if the start of end has been blocked * if(Vector3.Distance(pos, startN.pos)<gridSize/2) return true; * if(Vector3.Distance(pos, endN.pos)<gridSize/2) return true; * * //check if the node is in currentPath, if not, then the node is buildable * //this is only applicable if pathSmoothing is off * if(!PathFinder.IsPathSmoothingOn()){ * bool InCurrentPath=false; * * foreach(Vector3 pathPoint in currentPath){ * float dist=Vector3.Distance(pos, pathPoint); * if(dist<gridSize/2){ * InCurrentPath=true; * break; * } * } * * if(!InCurrentPath) { * //Debug.Log("not in current path "); * return false; * } * } * * * Debug.Log("calling pathfinder, check for block"); * * //the current node is in current path, check to see if there's other alternative path if this one's blocked * //while getting another path, cache it so it can be used later without redo the search * nextBuildNode=PathFinder.GetNearestNode(pos, nodeGraph); * //use force instant search so the path is return immediately * altPath=PathFinder.ForceSearch(startN, endN, nextBuildNode, nodeGraph); * * if(altPath.Count>0) return false; */ //return true; }
static public void GetPath(NodeTD startN, NodeTD endN, NodeTD[] graph, SetPathCallbackTD callBackFunc) { GetPath(startN, endN, null, graph, callBackFunc, false); }
static public void GetPath(NodeTD startN, NodeTD endN, NodeTD[] graph, SetPathCallbackTD callBackFunc, bool urgent) { GetPath(startN, endN, null, graph, callBackFunc, urgent); }
//~ public List<Node> GetNeighbouringNode(Node origin, Node node, int iteration){ //~ float gridSize=Node.GetGridSize(); //~ List<Node> nodeList=new List<Node>(); //~ foreach(Node node in node.neighbourNode){ //~ if(Vector3.Distance(node.pos, origin.pos)<gridSize*1.5f){ //~ nodeList.Add(node); //~ } //~ } //~ } //make cause system to slow down, use with care static public List <Vector3> ForceSearch(NodeTD startN, NodeTD endN, NodeTD blockN, NodeTD[] graph, int footprint) { if (blockN != null) { blockN.walkable = false; //Debug.Log("block reference node"); List <NodeTD> tempList = GetNodeInFootprint(blockN, footprint); //Debug.Log(footprint+" "+tempList.Count); foreach (NodeTD node in tempList) { node.walkable = false; } } bool pathFound = true; int searchCounter = 0; //used to count the total amount of node that has been searched List <NodeTD> closeList = new List <NodeTD>(); NodeTD[] openList = new NodeTD[graph.Length]; List <int> openListRemoved = new List <int>(); int openListCounter = 0; NodeTD currentNode = startN; float currentLowestF = Mathf.Infinity; int id = 0; //use element num of the node with lowest score in the openlist during the comparison process int i = 0; //universal int value used for various looping operation while (true) { if (currentNode == endN) { break; } closeList.Add(currentNode); currentNode.listState = _ListStateTD.Close; currentNode.ProcessNeighbour(endN); foreach (NodeTD neighbour in currentNode.neighbourNode) { if (neighbour.listState == _ListStateTD.Unassigned && neighbour.walkable) { neighbour.listState = _ListStateTD.Open; if (openListRemoved.Count > 0) { openList[openListRemoved[0]] = neighbour; openListRemoved.RemoveAt(0); } else { openList[openListCounter] = neighbour; openListCounter += 1; } } } currentNode = null; currentLowestF = Mathf.Infinity; id = 0; for (i = 0; i < openListCounter; i++) { if (openList[i] != null) { if (openList[i].scoreF < currentLowestF) { currentLowestF = openList[i].scoreF; currentNode = openList[i]; id = i; } } } if (currentNode == null) { pathFound = false; break; } openList[id] = null; openListRemoved.Add(id); searchCounter += 1; } //~ float timeUsed=Time.realtimeSinceStartup-timeStart; //~ if(pathFound) Debug.Log("Path found. Searched "+searchCounter+" nodes, used "+timeUsed+"seconds"); //~ else Debug.Log("no path. Searched "+searchCounter+" nodes, used "+timeUsed+"seconds"); List <Vector3> p = new List <Vector3>(); if (pathFound) { while (currentNode != null) { p.Add(currentNode.pos); currentNode = currentNode.parent; } p = InvertArray(p); //if(pathFinder.pathSmoothing) { // p=pathFinder.LOSPathSmoothingBackward(p); // p=pathFinder.LOSPathSmoothingForward(p); //} } if (blockN != null) { blockN.walkable = true; //Debug.Log("unblock reference node"); List <NodeTD> tempList = GetNodeInFootprint(blockN, footprint); foreach (NodeTD node in tempList) { node.walkable = true; } } ResetGraph(graph); return(p); }
static public List <NodeTD> GetNodeInFootprint(NodeTD origin, int footprint) { if (footprint <= 0) { return(new List <NodeTD>()); } bool connectDNeighbour = NodeGeneratorTD.ConnectDiagonalNeighbour(); List <NodeTD> currentList = new List <NodeTD>(); List <NodeTD> openList = new List <NodeTD>(); List <NodeTD> closeList = new List <NodeTD>(); if (connectDNeighbour) { closeList.Add(origin); foreach (NodeTD node in origin.neighbourNode) { currentList.Add(node); } for (int i = 0; i < footprint; i++) { openList = currentList; currentList = new List <NodeTD>(); foreach (NodeTD node in openList) { foreach (NodeTD neighbour in node.neighbourNode) { if (!openList.Contains(neighbour) && !closeList.Contains(neighbour)) { currentList.Add(neighbour); } } closeList.Add(node); } } } else { closeList.Add(origin); foreach (NodeTD node in origin.neighbourNode) { currentList.Add(node); } //~ float range=1.5f*(footprint)*BuildManager.GetGridSize(); float range = 1 * (footprint) * BuildManager.GetGridSize() + BuildManager.GetGridSize() * 0.25f; for (int i = 0; i < footprint * 2; i++) { openList = currentList; currentList = new List <NodeTD>(); foreach (NodeTD node in openList) { foreach (NodeTD neighbour in node.neighbourNode) { //~ if(Vector3.Distance(origin.pos, neighbour.pos)<range){ if (Mathf.Abs(origin.pos.x - neighbour.pos.x) <= range && Mathf.Abs(origin.pos.z - neighbour.pos.z) <= range) { if (!openList.Contains(neighbour) && !closeList.Contains(neighbour)) { currentList.Add(neighbour); } } } closeList.Add(node); } } } return(closeList); }
IEnumerator _Search(NodeTD startN, NodeTD endN, NodeTD blockN, NodeTD[] graph, SetPathCallbackTD callBackFunc) { //~ foreach(NodeTD nn in graph){ //~ DebugDrawTD.Cross(nn.pos, nn.walkable!=true ? Color.red : Color.white, 6); //~ DebugDrawTD.Square(nn.pos, nn.neighbourNode==null ? Color.red : Color.white, 6); //~ } //block node is for checking if a path exist if that particular node is block if (blockN != null) { //var switched:boolean=true; //if(block.walkable) block.walkable=false; //else switched=false; blockN.walkable = false; } //time tracker for performance check float timeStart = Time.realtimeSinceStartup; //mark that a serac has started, any further query will be queued searching = true; bool pathFound = true; int searchCounter = 0; //used to count the total amount of node that has been searched int loopCounter = 0; //used to count how many node has been search in the loop, if it exceed a value, bring it to the next frame //float LoopTime=Time.realtimeSinceStartup; //closelist, used to store all the node that are on the path List <NodeTD> closeList = new List <NodeTD>(); //openlist, all the possible node that yet to be on the path, the number can only be as much as the number of node in the garph NodeTD[] openList = new NodeTD[graph.Length]; //an array use to record the element number in the open list which is empty after the node is removed to be use as currentNode, //so we can use builtin array with fixed length for openlist, also we can loop for the minimal amount of node in every search List <int> openListRemoved = new List <int>(); //current count of elements that are occupied in openlist, openlist[n>openListCounter] are null int openListCounter = 0; //set start as currentNode NodeTD currentNode = startN; //use to compare node in the openlist has the lowest score, alwyas set to Infinity when not in used float currentLowestF = Mathf.Infinity; int id = 0; //use element num of the node with lowest score in the openlist during the comparison process int i = 0; //universal int value used for various looping operation //loop start while (true) { //if we have reach the destination if (currentNode == endN) { break; } //for gizmo debug purpose //currentNodeBeingProcess=currentNode; //move currentNode to closeList; closeList.Add(currentNode); currentNode.listState = _ListStateTD.Close; //loop through the neighbour of current loop, calculate score and stuff currentNode.ProcessNeighbour(endN); //put all neighbour in openlist foreach (NodeTD neighbour in currentNode.neighbourNode) { if (neighbour.listState == _ListStateTD.Unassigned && neighbour.walkable) { //set the node state to open neighbour.listState = _ListStateTD.Open; //if there's an open space in openlist, fill the space if (openListRemoved.Count > 0) { openList[openListRemoved[0]] = neighbour; //remove the number from openListRemoved since this element has now been occupied openListRemoved.RemoveAt(0); } //else just stack on it and increase the occupication counter else { openList[openListCounter] = neighbour; openListCounter += 1; } } } //clear the current node, before getting a new one, so we know if there isnt any suitable next node currentNode = null; //get the next point from openlist, set it as current point //just loop through the openlist until we reach the maximum occupication //while that, get the node with the lowest score currentLowestF = Mathf.Infinity; id = 0; for (i = 0; i < openListCounter; i++) { if (openList[i] != null) { if (openList[i].scoreF < currentLowestF) { currentLowestF = openList[i].scoreF; currentNode = openList[i]; id = i; } } } //if there's no node left in openlist, path doesnt exist if (currentNode == null) { pathFound = false; break; } //remove the new currentNode from openlist openList[id] = null; //put the id into openListRemoved so we know there's an empty element that can be filled in the next loop openListRemoved.Add(id); //increase the counter searchCounter += 1; loopCounter += 1; //if exceed the search limit per frame, bring the search to the next frame if (loopCounter > ScanNodeLimitPerFrame) { loopCounter = 0; //reset the loopCounter for the next frame yield return(null); } } //see how long it has taken to complete the search //float timeUsed=Time.realtimeSinceStartup-timeStart; //if(pathFound) Debug.Log("Path found. Searched "+searchCounter+" nodes, used "+timeUsed+"seconds"); //else Debug.Log("no path. Searched "+searchCounter+" nodes, used "+timeUsed+"seconds"); //trace back the path through closeList List <Vector3> p = new List <Vector3>(); if (pathFound) { //track back the node's parent to form a path while (currentNode != null) { p.Add(currentNode.pos); currentNode = currentNode.parent; } //since the path is now tracked from endN ot startN, invert the list p = InvertArray(p); //~ if(pathSmoothing) { //~ //Debug.Log("smoothing path"); //~ p=LOSPathSmoothingBackward(p); //~ p=LOSPathSmoothingForward(p); //~ } if (pathSmoothing == _PathSmoothing.Mean) { p = MeanSmoothPath(p); } else if (pathSmoothing == _PathSmoothing.LOS) { p = LOSPathSmoothingBackward(p); p = LOSPathSmoothingForward(p); } //else Debug.Log("skip smoothing path"); } //~ else Debug.Log("no path found"); //if this is just to check if a path is blocked, now we can clear the assumed blocked node if (blockN != null) { blockN.walkable = true; } callBackFunc(p); //reset the all the nodegraph's node state? //Reset(); //clear searching so indicate the search has end and a new serach can be called searching = false; ResetGraph(graph); }
static private void Search(NodeTD startN, NodeTD endN, NodeTD blockN, NodeTD[] graph, SetPathCallbackTD callBackFunc) { pathFinder.StartCoroutine(pathFinder._Search(startN, endN, blockN, graph, callBackFunc)); }