public void FindPath(PathRequest request, Action <PathResult> callback) { Stopwatch sw = new Stopwatch(); //check how long the method takes sw.Start(); Vector3[] waypoints = new Vector3[0]; //contains the path bool pathSuccess = false; //if path could be found Node startNode = grid.NodeFromWorldPoint(request.pathStart); //get start and end in node Node targetNode = grid.NodeFromWorldPoint(request.pathEnd); Heap <Node> openSet = new Heap <Node>(grid.MaxSize); //create heap for all nodes that can be moved to HashSet <Node> closedSet = new HashSet <Node>(); //hash set for all nodes that can't be moved to openSet.Add(startNode); //add the startnode for a starting point if (startNode.walkable && targetNode.walkable) { while (openSet.Count > 0) //only breaks if target node is unreacheble { Node currentNode = openSet.RemoveFirst(); //set current node to the first one in openSet and remove it from the openset closedSet.Add(currentNode); //so you can't move to current node again if (currentNode == targetNode) //if goal is reached { sw.Stop(); print("Path found: " + sw.ElapsedMilliseconds + " ms"); pathSuccess = true; break; } foreach (Node neighbour in grid.GetNeighbours(currentNode)) //if an open neighbour to the current node gets a lower gcost from using currents path (patrents), current is the neighbours parent { if (!neighbour.walkable || closedSet.Contains(neighbour)) //if neighbour is not walkable or on the closed set skip it { continue; } int movenCostToNeighbour = currentNode.gCost + GetDistance(currentNode, neighbour) + neighbour.movementPenalty; //the cost for moving to the neighbour if (movenCostToNeighbour < neighbour.gCost || !openSet.Contains(neighbour)) //if the new cost is lower than the old or neighbour has not yet been added to openset { neighbour.gCost = movenCostToNeighbour; //set g cost neighbour.hCost = GetDistance(neighbour, targetNode); //set h cost neighbour.parent = currentNode; //set parent to backtrack to start from goal if (!openSet.Contains(neighbour)) //if node was not in openset, add it { openSet.Add(neighbour); } else { openSet.UpdateItem(neighbour); //else, just update heap } } } } } if (pathSuccess) { waypoints = RetracePath(startNode, targetNode); //if path was found, save it in the array pathSuccess = waypoints.Length > 0; } callback(new PathResult(waypoints, pathSuccess, request.callback)); //tell request manager that the path is found //UnityEngine.Debug.Log(GC.GetTotalMemory(true) + " Bytes"); }
IEnumerator FindPath(Vector3 startPos, Vector3 targetPos) { Stopwatch sw = new Stopwatch(); sw.Start(); Vector3[] waypoints = new Vector3[0]; bool pathSuccess = false; Node startNode = grid.NodeFromWorldPoint(startPos); Node targetNode = grid.NodeFromWorldPoint(targetPos); Heap <Node> openSet = new Heap <Node>(grid.MaxSize); HashSet <Node> closedSet = new HashSet <Node>(); openSet.Add(startNode); if (startNode.walkable && targetNode.walkable) { while (openSet.Count > 0) //only breaks if target node is unreacheble { Node currentNode = openSet.RemoveFirst(); closedSet.Add(currentNode); if (currentNode == targetNode) //if goal is reached { sw.Stop(); print("Path found: " + sw.ElapsedMilliseconds + " ms"); pathSuccess = true; break; } foreach (Node neighbour in grid.GetNeighbours(currentNode)) //if open neighbour to current gets a lower gcost from using currents path(patrents), current is the neighbours parent, basically starts here { if (!neighbour.walkable || closedSet.Contains(neighbour)) { continue; } int movenCostToNeighbour = currentNode.gCost + getDistance(currentNode, neighbour); if (movenCostToNeighbour < neighbour.gCost || !openSet.Contains(neighbour)) { neighbour.gCost = movenCostToNeighbour; neighbour.hCost = getDistance(neighbour, targetNode); neighbour.parent = currentNode; if (!openSet.Contains(neighbour)) { openSet.Add(neighbour); } else { openSet.UpdateItem(neighbour); } } } } } yield return(null); if (pathSuccess) { waypoints = RetracePath(startNode, targetNode); } requsetManager.FinishedProcessingPath(waypoints, pathSuccess); }
IEnumerator FollowPath() //basiclly same as Update but can be started and stoped. for moving to target along path { bool grounded = false; Vector3 lastPos = transform.position; bool followingPath = true; int pathIndex = 0; //transform.LookAt(path.lookpoints[0]); //face first waypoint float speedPercent = 1; while (followingPath) { Vector2 pos2D = new Vector2(transform.position.x, transform.position.z); while (path.turnBoundaries[pathIndex].HasCrossedLine(pos2D)) { if (pathIndex == path.finishLineIndex) { followingPath = false; //FindNextPath(); break; } else { pathIndex++; } } if (followingPath) { speedPercent = 1; if (pathIndex >= path.slowDownIndex && stoppingDst > 0 && slowDown) { speedPercent = Mathf.Clamp01(path.turnBoundaries[path.finishLineIndex /*- 1*/].DistanceFromPoint(pos2D) / stoppingDst + 0.2f); //add to avoid stopping compleatly } Quaternion targetRotation = Quaternion.LookRotation(path.lookpoints[pathIndex] - transform.position); transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, Time.deltaTime * turnSpeed); transform.rotation = new Quaternion(0, transform.rotation.y, 0, transform.rotation.w); transform.Translate(Vector3.forward * Time.deltaTime * speed, Space.Self); frontCheck = new Ray(transform.position + Vector3.up / 3, transform.forward + Vector3.up * maxJumpHeight / 2); topCheck = new Ray(transform.position + Vector3.up * maxJumpHeight, transform.forward); groundCheck = new Ray(transform.position + Vector3.up / 2, Vector3.down); RaycastHit obstacle; timeSinceJump += Time.deltaTime; grounded = Physics.Raycast(groundCheck, 1); //check if AI is standing on ground if (Physics.Raycast(frontCheck.origin, frontCheck.direction, out obstacle, 4, grid.walkableMask.value, QueryTriggerInteraction.Ignore)) //something is in the way { if (!Physics.Raycast(topCheck, 5)) //check that the obstacle can be jumped over { if (grounded) //if AI is standing on the ground { if (timeSinceJump > 1) //this is to prevent the AI from jumping more than once per second { rb.velocity = new Vector3(rb.velocity.x, Mathf.Sqrt(maxJumpHeight * Physics.gravity.magnitude * 2), rb.velocity.z); //rb.AddForce(Vector3.up * Mathf.Sqrt(maxJumpHeight * Physics.gravity.magnitude * 2), ForceMode.Impulse); timeSinceJump = 0; } } } else { grid.NodeFromWorldPoint(obstacle.point).walkable = false; //tried jumping, didnt work. set this to unwalkable } } if (slowDown) { transform.Translate(Vector3.forward * Time.deltaTime * speed * speedPercent, Space.Self); } } yield return(null); //wait one frame } //Vector3.MoveTowards(transform.position, target.position, Time.deltaTime * speed); //yield return null; //wait one frame }