123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760 |
- using UnityEngine;
- using System.Collections.Generic;
- namespace Pathfinding {
-
-
-
-
-
-
-
-
-
- public class ABPath : Path {
-
- public GraphNode startNode;
-
- public GraphNode endNode;
-
- public Vector3 originalStartPoint;
-
- public Vector3 originalEndPoint;
-
-
-
-
- public Vector3 startPoint;
-
-
-
-
- public Vector3 endPoint;
-
-
-
-
-
- protected virtual bool hasEndPoint {
- get {
- return true;
- }
- }
- public Int3 startIntPoint;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public bool calculatePartial;
-
-
-
-
- protected PathNode partialBestTarget;
-
- protected int[] endNodeCosts;
- #if !ASTAR_NO_GRID_GRAPH
-
- GridNode gridSpecialCaseNode;
- #endif
-
-
-
-
-
- public ABPath () {}
-
-
-
-
-
-
-
-
- public static ABPath Construct (Vector3 start, Vector3 end, OnPathDelegate callback = null) {
- var p = PathPool.GetPath<ABPath>();
- p.Setup(start, end, callback);
- return p;
- }
- protected void Setup (Vector3 start, Vector3 end, OnPathDelegate callbackDelegate) {
- callback = callbackDelegate;
- UpdateStartEnd(start, end);
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public static ABPath FakePath (List<Vector3> vectorPath, List<GraphNode> nodePath = null) {
- var path = PathPool.GetPath<ABPath>();
- for (int i = 0; i < vectorPath.Count; i++) path.vectorPath.Add(vectorPath[i]);
- path.completeState = PathCompleteState.Complete;
- ((IPathInternals)path).AdvanceState(PathState.Returned);
- if (vectorPath.Count > 0) {
- path.UpdateStartEnd(vectorPath[0], vectorPath[vectorPath.Count - 1]);
- }
- if (nodePath != null) {
- for (int i = 0; i < nodePath.Count; i++) path.path.Add(nodePath[i]);
- if (nodePath.Count > 0) {
- path.startNode = nodePath[0];
- path.endNode = nodePath[nodePath.Count - 1];
- }
- }
- return path;
- }
-
-
-
-
-
- protected void UpdateStartEnd (Vector3 start, Vector3 end) {
- originalStartPoint = start;
- originalEndPoint = end;
- startPoint = start;
- endPoint = end;
- startIntPoint = (Int3)start;
- hTarget = (Int3)end;
- }
- public override uint GetConnectionSpecialCost (GraphNode a, GraphNode b, uint currentCost) {
- if (startNode != null && endNode != null) {
- if (a == startNode) {
- return (uint)((startIntPoint - (b == endNode ? hTarget : b.position)).costMagnitude * (currentCost*1.0/(a.position-b.position).costMagnitude));
- }
- if (b == startNode) {
- return (uint)((startIntPoint - (a == endNode ? hTarget : a.position)).costMagnitude * (currentCost*1.0/(a.position-b.position).costMagnitude));
- }
- if (a == endNode) {
- return (uint)((hTarget - b.position).costMagnitude * (currentCost*1.0/(a.position-b.position).costMagnitude));
- }
- if (b == endNode) {
- return (uint)((hTarget - a.position).costMagnitude * (currentCost*1.0/(a.position-b.position).costMagnitude));
- }
- } else {
-
- if (a == startNode) {
- return (uint)((startIntPoint - b.position).costMagnitude * (currentCost*1.0/(a.position-b.position).costMagnitude));
- }
- if (b == startNode) {
- return (uint)((startIntPoint - a.position).costMagnitude * (currentCost*1.0/(a.position-b.position).costMagnitude));
- }
- }
- return currentCost;
- }
-
-
-
-
-
- protected override void Reset () {
- base.Reset();
- startNode = null;
- endNode = null;
- originalStartPoint = Vector3.zero;
- originalEndPoint = Vector3.zero;
- startPoint = Vector3.zero;
- endPoint = Vector3.zero;
- calculatePartial = false;
- partialBestTarget = null;
- startIntPoint = new Int3();
- hTarget = new Int3();
- endNodeCosts = null;
- #if !ASTAR_NO_GRID_GRAPH
- gridSpecialCaseNode = null;
- #endif
- }
- #if !ASTAR_NO_GRID_GRAPH
-
- static readonly NNConstraint NNConstraintNone = NNConstraint.None;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- protected virtual bool EndPointGridGraphSpecialCase (GraphNode closestWalkableEndNode) {
- var gridNode = closestWalkableEndNode as GridNode;
- if (gridNode != null) {
- var gridGraph = GridNode.GetGridGraph(gridNode.GraphIndex);
-
- var endNNInfo2 = AstarPath.active.GetNearest(originalEndPoint, NNConstraintNone);
- var gridNode2 = endNNInfo2.node as GridNode;
- if (gridNode != gridNode2 && gridNode2 != null && gridNode.GraphIndex == gridNode2.GraphIndex) {
-
- var x1 = gridNode.NodeInGridIndex % gridGraph.width;
- var z1 = gridNode.NodeInGridIndex / gridGraph.width;
- var x2 = gridNode2.NodeInGridIndex % gridGraph.width;
- var z2 = gridNode2.NodeInGridIndex / gridGraph.width;
- bool wasClose = false;
- switch (gridGraph.neighbours) {
- case NumNeighbours.Four:
- if ((x1 == x2 && System.Math.Abs(z1-z2) == 1) || (z1 == z2 && System.Math.Abs(x1-x2) == 1)) {
-
-
-
-
- wasClose = true;
- }
- break;
- case NumNeighbours.Eight:
- if (System.Math.Abs(x1-x2) <= 1 && System.Math.Abs(z1-z2) <= 1) {
-
-
-
-
- wasClose = true;
- }
- break;
- case NumNeighbours.Six:
-
- for (int i = 0; i < 6; i++) {
- var nx = x2 + gridGraph.neighbourXOffsets[GridGraph.hexagonNeighbourIndices[i]];
- var nz = z2 + gridGraph.neighbourZOffsets[GridGraph.hexagonNeighbourIndices[i]];
- if (x1 == nx && z1 == nz) {
-
-
-
-
- wasClose = true;
- break;
- }
- }
- break;
- default:
-
- throw new System.Exception("Unhandled NumNeighbours");
- }
- if (wasClose) {
-
- SetFlagOnSurroundingGridNodes(gridNode2, 1, true);
-
- endPoint = (Vector3)gridNode2.position;
- hTarget = gridNode2.position;
- endNode = gridNode2;
-
-
-
-
-
-
- hTargetNode = endNode;
-
-
- gridSpecialCaseNode = gridNode2;
- return true;
- }
- }
- }
- return false;
- }
-
- void SetFlagOnSurroundingGridNodes (GridNode gridNode, int flag, bool flagState) {
-
- var gridGraph = GridNode.GetGridGraph(gridNode.GraphIndex);
-
- int mxnum = gridGraph.neighbours == NumNeighbours.Four ? 4 : (gridGraph.neighbours == NumNeighbours.Eight ? 8 : 6);
-
- var x = gridNode.NodeInGridIndex % gridGraph.width;
- var z = gridNode.NodeInGridIndex / gridGraph.width;
- if (flag != 1 && flag != 2)
- throw new System.ArgumentOutOfRangeException("flag");
- for (int i = 0; i < mxnum; i++) {
- int nx, nz;
- if (gridGraph.neighbours == NumNeighbours.Six) {
-
- nx = x + gridGraph.neighbourXOffsets[GridGraph.hexagonNeighbourIndices[i]];
- nz = z + gridGraph.neighbourZOffsets[GridGraph.hexagonNeighbourIndices[i]];
- } else {
- nx = x + gridGraph.neighbourXOffsets[i];
- nz = z + gridGraph.neighbourZOffsets[i];
- }
-
- if (nx >= 0 && nz >= 0 && nx < gridGraph.width && nz < gridGraph.depth) {
- var adjacentNode = gridGraph.nodes[nz*gridGraph.width + nx];
- var pathNode = pathHandler.GetPathNode(adjacentNode);
- if (flag == 1) pathNode.flag1 = flagState;
- else pathNode.flag2 = flagState;
- }
- }
- }
- #endif
-
- protected override void Prepare () {
- AstarProfiler.StartProfile("Get Nearest");
-
- nnConstraint.tags = enabledTags;
- var startNNInfo = AstarPath.active.GetNearest(startPoint, nnConstraint);
-
- var pathNNConstraint = nnConstraint as PathNNConstraint;
- if (pathNNConstraint != null) {
- pathNNConstraint.SetStart(startNNInfo.node);
- }
- startPoint = startNNInfo.position;
- startIntPoint = (Int3)startPoint;
- startNode = startNNInfo.node;
- if (startNode == null) {
- FailWithError("Couldn't find a node close to the start point");
- return;
- }
- if (!CanTraverse(startNode)) {
- FailWithError("The node closest to the start point could not be traversed");
- return;
- }
-
-
- if (hasEndPoint) {
- var endNNInfo = AstarPath.active.GetNearest(endPoint, nnConstraint);
- endPoint = endNNInfo.position;
- endNode = endNNInfo.node;
- if (endNode == null) {
- FailWithError("Couldn't find a node close to the end point");
- return;
- }
-
- if (!CanTraverse(endNode)) {
- FailWithError("The node closest to the end point could not be traversed");
- return;
- }
-
- if (startNode.Area != endNode.Area) {
- FailWithError("There is no valid path to the target");
- return;
- }
- #if !ASTAR_NO_GRID_GRAPH
-
-
-
-
- if (!EndPointGridGraphSpecialCase(endNNInfo.node))
- #endif
- {
-
- hTarget = (Int3)endPoint;
- hTargetNode = endNode;
-
- pathHandler.GetPathNode(endNode).flag1 = true;
- }
- }
- AstarProfiler.EndProfile();
- }
-
-
-
-
-
-
-
- protected virtual void CompletePathIfStartIsValidTarget () {
-
- if (hasEndPoint && pathHandler.GetPathNode(startNode).flag1) {
- CompleteWith(startNode);
- Trace(pathHandler.GetPathNode(startNode));
- }
- }
- protected override void Initialize () {
-
-
- if (startNode != null) pathHandler.GetPathNode(startNode).flag2 = true;
- if (endNode != null) pathHandler.GetPathNode(endNode).flag2 = true;
-
- PathNode startRNode = pathHandler.GetPathNode(startNode);
- startRNode.node = startNode;
- startRNode.pathID = pathHandler.PathID;
- startRNode.parent = null;
- startRNode.cost = 0;
- startRNode.G = GetTraversalCost(startNode);
- startRNode.H = CalculateHScore(startNode);
-
- CompletePathIfStartIsValidTarget();
- if (CompleteState == PathCompleteState.Complete) return;
-
- startNode.Open(this, startRNode, pathHandler);
- searchedNodes++;
- partialBestTarget = startRNode;
-
- if (pathHandler.heap.isEmpty) {
- if (calculatePartial) {
- CompletePartial(partialBestTarget);
- } else {
- FailWithError("The start node either had no neighbours, or no neighbours that the path could traverse");
- }
- return;
- }
-
- currentR = pathHandler.heap.Remove();
- }
- protected override void Cleanup () {
-
- if (startNode != null) {
- var pathStartNode = pathHandler.GetPathNode(startNode);
- pathStartNode.flag1 = false;
- pathStartNode.flag2 = false;
- }
- if (endNode != null) {
- var pathEndNode = pathHandler.GetPathNode(endNode);
- pathEndNode.flag1 = false;
- pathEndNode.flag2 = false;
- }
- #if !ASTAR_NO_GRID_GRAPH
-
-
-
-
-
-
-
- if (gridSpecialCaseNode != null) {
- var pathNode = pathHandler.GetPathNode(gridSpecialCaseNode);
- pathNode.flag1 = false;
- pathNode.flag2 = false;
- SetFlagOnSurroundingGridNodes(gridSpecialCaseNode, 1, false);
- SetFlagOnSurroundingGridNodes(gridSpecialCaseNode, 2, false);
- }
- #endif
- }
- void CompletePartial (PathNode node) {
- CompleteState = PathCompleteState.Partial;
- endNode = node.node;
- endPoint = endNode.ClosestPointOnNode(originalEndPoint);
- Trace(node);
- }
-
-
-
-
-
- void CompleteWith (GraphNode node) {
- #if !ASTAR_NO_GRID_GRAPH
- if (endNode == node) {
-
-
- } else {
-
- var gridNode = node as GridNode;
- if (gridNode == null) {
- throw new System.Exception("Some path is not cleaning up the flag1 field. This is a bug.");
- }
-
-
-
- endPoint = gridNode.ClosestPointOnNode(originalEndPoint);
-
-
-
- endNode = node;
- }
- #else
-
-
-
-
- node.MustBeEqual(endNode);
- #endif
-
- CompleteState = PathCompleteState.Complete;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- protected override void CalculateStep (long targetTick) {
- int counter = 0;
-
- while (CompleteState == PathCompleteState.NotCalculated) {
- searchedNodes++;
-
- if (currentR.flag1) {
-
-
- CompleteWith(currentR.node);
- break;
- }
- if (currentR.H < partialBestTarget.H) {
- partialBestTarget = currentR;
- }
- AstarProfiler.StartFastProfile(4);
-
- currentR.node.Open(this, currentR, pathHandler);
- AstarProfiler.EndFastProfile(4);
-
- if (pathHandler.heap.isEmpty) {
- if (calculatePartial && partialBestTarget != null) {
- CompletePartial(partialBestTarget);
- } else {
- FailWithError("Searched all reachable nodes, but could not find target. This can happen if you have nodes with a different tag blocking the way to the goal. You can enable path.calculatePartial to handle that case workaround (though this comes with a performance cost).");
- }
- return;
- }
-
- AstarProfiler.StartFastProfile(7);
- currentR = pathHandler.heap.Remove();
- AstarProfiler.EndFastProfile(7);
-
- if (counter > 500) {
-
- if (System.DateTime.UtcNow.Ticks >= targetTick) {
-
- return;
- }
- counter = 0;
-
- if (searchedNodes > 1000000) {
- throw new System.Exception("Probable infinite loop. Over 1,000,000 nodes searched");
- }
- }
- counter++;
- }
- AstarProfiler.StartProfile("Trace");
- if (CompleteState == PathCompleteState.Complete) {
- Trace(currentR);
- } else if (calculatePartial && partialBestTarget != null) {
- CompletePartial(partialBestTarget);
- }
- AstarProfiler.EndProfile();
- }
-
- protected override string DebugString (PathLog logMode) {
- if (logMode == PathLog.None || (!error && logMode == PathLog.OnlyErrors)) {
- return "";
- }
- var text = new System.Text.StringBuilder();
- DebugStringPrefix(logMode, text);
- if (!error && logMode == PathLog.Heavy) {
- if (hasEndPoint && endNode != null) {
- PathNode nodeR = pathHandler.GetPathNode(endNode);
- text.Append("\nEnd Node\n G: ");
- text.Append(nodeR.G);
- text.Append("\n H: ");
- text.Append(nodeR.H);
- text.Append("\n F: ");
- text.Append(nodeR.F);
- text.Append("\n Point: ");
- text.Append(((Vector3)endPoint).ToString());
- text.Append("\n Graph: ");
- text.Append(endNode.GraphIndex);
- }
- text.Append("\nStart Node");
- text.Append("\n Point: ");
- text.Append(((Vector3)startPoint).ToString());
- text.Append("\n Graph: ");
- if (startNode != null) text.Append(startNode.GraphIndex);
- else text.Append("< null startNode >");
- }
- DebugStringSuffix(logMode, text);
- return text.ToString();
- }
-
-
-
-
-
-
-
-
- [System.Obsolete()]
- public Vector3 GetMovementVector (Vector3 point) {
- if (vectorPath == null || vectorPath.Count == 0) {
- return Vector3.zero;
- }
- if (vectorPath.Count == 1) {
- return vectorPath[0]-point;
- }
- float minDist = float.PositiveInfinity;
- int minSegment = 0;
- for (int i = 0; i < vectorPath.Count-1; i++) {
- Vector3 closest = VectorMath.ClosestPointOnSegment(vectorPath[i], vectorPath[i+1], point);
- float dist = (closest-point).sqrMagnitude;
- if (dist < minDist) {
- minDist = dist;
- minSegment = i;
- }
- }
- return vectorPath[minSegment+1]-point;
- }
-
- }
- }
|