public bool CheckForBlock(Vector3 pos) { float gridSize = BuildManager.GetGridSize(); NodeTD targetNode = PathFinder.GetNearestNode(pos, nodeGraph); for (int i = 0; i < subPathList.Count; i++) { SubPath subPath = subPathList[i]; if (Vector3.Distance(pos, subPath.startN.pos) < gridSize / 2) { return(true); } if (Vector3.Distance(pos, subPath.endN.pos) < gridSize / 2) { return(true); } if (subPath.IsNodeInPath(targetNode)) { subPath.altPath = PathFinder.ForceSearch(subPath.startN, subPath.endN, targetNode, nodeGraph); if (subPath.altPath.Count == 0) { return(true); } } } nextBuildNode = targetNode; return(false); }
public SearchQueue(NodeTD n1, NodeTD n2, NodeTD[] g, SetPathCallbackTD func) { startNode = n1; endNode = n2; graph = g; callBackFunc = func; }
public static void GetPath(NodeTD startN, NodeTD endN, NodeTD[] graph, SetPathCallbackTD callBackFunc) { if (instance == null) { Init(); } instance._GetPath(startN, endN, graph, callBackFunc); }
public void UnbuildTower(NodeTD node) { node.walkable = true; for (int i = 0; i < subPathList.Count; i++) { subPathList[i].SearchNewPath(nodeGraph); } }
public List <Vector3> altPath = new List <Vector3>(); //for checking if there's any block public void Init(PlatformTD platform) { parentPlatform = platform; startN = PathFinder.GetNearestNode(connectStart.position, platform.GetNodeGraph()); endN = PathFinder.GetNearestNode(connectEnd.position, platform.GetNodeGraph()); path.Add((connectStart.position + connectEnd.position) / 2); SearchNewPath(platform.GetNodeGraph()); }
public void _GetPath(NodeTD startN, NodeTD endN, NodeTD[] graph, SetPathCallbackTD callBackFunc) { if (!searching) { //commence search StartCoroutine(_SearchRoutine(startN, endN, graph, callBackFunc)); } else { //if a serach is in progress, put current request into the queue list SearchQueue q = new SearchQueue(startN, endN, graph, callBackFunc); searchQueueList.Add(q); } }
public bool IsNodeInPath(NodeTD node) { float gridSize = BuildManager.GetGridSize(); for (int i = 0; i < path.Count; i++) { float dist = Vector3.Distance(node.pos, path[i]); if (dist < gridSize * .85f) { return(true); } } return(false); }
void ResetSubPath(SubPath platformSubPath) { if (dummyT == null) { dummyT = new GameObject().transform; } Quaternion rot = Quaternion.LookRotation(subPath[subWaypointID] - thisT.position); dummyT.rotation = rot; dummyT.position = thisT.position; Vector3 pos = dummyT.TransformPoint(0, 0, BuildManager.GetGridSize() / 2); NodeTD startN = PathFinder.GetNearestNode(pos, platformSubPath.parentPlatform.GetNodeGraph()); PathFinder.GetPath(startN, platformSubPath.endN, platformSubPath.parentPlatform.GetNodeGraph(), this.SetSubPath); }
public static 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); }
public void BuildTower(Vector3 pos, UnitTower tower) { //pathfinding related code, only call if this platform is walkable; if (!walkable) { return; } if (tower.type != _TowerType.Mine) { NodeTD node = PathFinder.GetNearestNode(pos, nodeGraph); node.walkable = false; tower.SetPlatform(this, node); //if the node has been check before during CheckForBlock(), just use the altPath if (node == nextBuildNode) { for (int i = 0; i < subPathList.Count; i++) { if (subPathList[i].IsNodeInPath(node)) { subPathList[i].SwitchToSubPath(); } } return; } for (int i = 0; i < subPathList.Count; i++) { if (subPathList[i].IsNodeInPath(node)) { subPathList[i].SearchNewPath(nodeGraph); } } } }
//make cause system to slow down, use with care public static List <Vector3> ForceSearch(NodeTD startN, NodeTD endN, NodeTD blockN, NodeTD[] graph, int footprint = -1) { if (blockN != null) { blockN.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; } List <Vector3> p = new List <Vector3>(); if (pathFound) { while (currentNode != null) { p.Add(currentNode.pos); currentNode = currentNode.parent; } p = InvertArray(p); p = SmoothPath(p); } if (blockN != null) { blockN.walkable = true; } ResetGraph(graph); return(p); }
IEnumerator _SearchRoutine(NodeTD startN, NodeTD endN, NodeTD[] graph, SetPathCallbackTD callBackFunc) { //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); } } //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); p = SmoothPath(p); } callBackFunc(p); //clear searching so indicate the search has end and a new serach can be called searching = false; ResetGraph(graph); }
public void SetPlatform(PlatformTD platform, NodeTD node) { occupiedPlatform = platform; occupiedNode = node; }
public static NodeTD[] GenerateNode(PlatformTD platform, float heightOffset) { if (instance == null) { Init(); } Transform platformT = platform.thisT; float gridSize = BuildManager.GetGridSize(); float scaleX = platform.thisT.localScale.x; float scaleZ = platform.thisT.localScale.z; int countX = (int)(scaleX / gridSize); int countZ = (int)(scaleZ / gridSize); float x = -scaleX / 2 / scaleX; float z = -scaleZ / 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++) { Vector3 pos = thisT.position; pos.y = pos.y + 5000; LayerMask mask = 1 << LayerManager.LayerTower(); RaycastHit hit1; if (Physics.Raycast(pos, Vector3.down, out hit1, Mathf.Infinity, ~mask)) { nodeGraph[counter] = new NodeTD(new Vector3(pos.x, hit1.point.y + heightOffset, pos.z), counter); } else { nodeGraph[counter] = new NodeTD(pos, counter); nodeGraph[counter].walkable = false; } 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; 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; } } } float neighbourDistance = 0; float neighbourRange; if (instance.connectDiagonalNeighbour) { neighbourRange = gridSize * 1.5f; } else { neighbourRange = gridSize * 1.1f; } 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]; } if (id != countX * (countZ - 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); } counter += 1; } return(nodeGraph); }
public void ProcessNeighbour(NodeTD node) { ProcessNeighbour(node.pos); }