123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697 |
- using UnityEngine;
- using System.Collections.Generic;
- namespace Pathfinding {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public class MultiTargetPath : ABPath {
-
- public OnPathDelegate[] callbacks;
-
- public GraphNode[] targetNodes;
-
- protected int targetNodeCount;
-
- public bool[] targetsFound;
-
- public Vector3[] targetPoints;
-
- public Vector3[] originalTargetPoints;
-
- public List<Vector3>[] vectorPaths;
-
- public List<GraphNode>[] nodePaths;
-
- public bool pathsForAll = true;
-
- public int chosenTarget = -1;
-
-
-
-
- int sequentialTarget;
-
-
-
-
-
-
-
-
-
-
-
- public HeuristicMode heuristicMode = HeuristicMode.Sequential;
- public enum HeuristicMode {
- None,
- Average,
- MovingAverage,
- Midpoint,
- MovingMidpoint,
- Sequential
- }
-
- public bool inverted { get; protected set; }
-
-
-
-
- public MultiTargetPath () {}
- public static MultiTargetPath Construct (Vector3[] startPoints, Vector3 target, OnPathDelegate[] callbackDelegates, OnPathDelegate callback = null) {
- MultiTargetPath p = Construct(target, startPoints, callbackDelegates, callback);
- p.inverted = true;
- return p;
- }
- public static MultiTargetPath Construct (Vector3 start, Vector3[] targets, OnPathDelegate[] callbackDelegates, OnPathDelegate callback = null) {
- var p = PathPool.GetPath<MultiTargetPath>();
- p.Setup(start, targets, callbackDelegates, callback);
- return p;
- }
- protected void Setup (Vector3 start, Vector3[] targets, OnPathDelegate[] callbackDelegates, OnPathDelegate callback) {
- inverted = false;
- this.callback = callback;
- callbacks = callbackDelegates;
- if (callbacks != null && callbacks.Length != targets.Length) throw new System.ArgumentException("The targets array must have the same length as the callbackDelegates array");
- targetPoints = targets;
- originalStartPoint = start;
- startPoint = start;
- startIntPoint = (Int3)start;
- if (targets.Length == 0) {
- FailWithError("No targets were assigned to the MultiTargetPath");
- return;
- }
- endPoint = targets[0];
- originalTargetPoints = new Vector3[targetPoints.Length];
- for (int i = 0; i < targetPoints.Length; i++) {
- originalTargetPoints[i] = targetPoints[i];
- }
- }
- protected override void Reset () {
- base.Reset();
- pathsForAll = true;
- chosenTarget = -1;
- sequentialTarget = 0;
- inverted = true;
- heuristicMode = HeuristicMode.Sequential;
- }
- protected override void OnEnterPool () {
- if (vectorPaths != null)
- for (int i = 0; i < vectorPaths.Length; i++)
- if (vectorPaths[i] != null) Util.ListPool<Vector3>.Release(vectorPaths[i]);
- vectorPaths = null;
- vectorPath = null;
- if (nodePaths != null)
- for (int i = 0; i < nodePaths.Length; i++)
- if (nodePaths[i] != null) Util.ListPool<GraphNode>.Release(nodePaths[i]);
- nodePaths = null;
- path = null;
- callbacks = null;
- targetNodes = null;
- targetsFound = null;
- targetPoints = null;
- originalTargetPoints = null;
- base.OnEnterPool();
- }
-
- void ChooseShortestPath () {
-
-
- chosenTarget = -1;
- if (nodePaths != null) {
- uint bestG = int.MaxValue;
- for (int i = 0; i < nodePaths.Length; i++) {
- var currentPath = nodePaths[i];
- if (currentPath != null) {
-
-
- var g = pathHandler.GetPathNode(currentPath[inverted ? 0 : currentPath.Count-1]).G;
- if (chosenTarget == -1 || g < bestG) {
- chosenTarget = i;
- bestG = g;
- }
- }
- }
- }
- }
- void SetPathParametersForReturn (int target) {
- path = nodePaths[target];
- vectorPath = vectorPaths[target];
- if (inverted) {
- startNode = targetNodes[target];
- startPoint = targetPoints[target];
- originalStartPoint = originalTargetPoints[target];
- } else {
- endNode = targetNodes[target];
- endPoint = targetPoints[target];
- originalEndPoint = originalTargetPoints[target];
- }
- }
- protected override void ReturnPath () {
- if (error) {
-
- if (callbacks != null) {
- for (int i = 0; i < callbacks.Length; i++)
- if (callbacks[i] != null) callbacks[i] (this);
- }
- if (callback != null) callback(this);
- return;
- }
- bool anySucceded = false;
-
-
-
- if (inverted) {
- endPoint = startPoint;
- endNode = startNode;
- originalEndPoint = originalStartPoint;
- }
- for (int i = 0; i < nodePaths.Length; i++) {
- if (nodePaths[i] != null) {
-
-
-
- completeState = PathCompleteState.Complete;
- anySucceded = true;
- } else {
- completeState = PathCompleteState.Error;
- }
- if (callbacks != null && callbacks[i] != null) {
- SetPathParametersForReturn(i);
- callbacks[i] (this);
-
- vectorPaths[i] = vectorPath;
- }
- }
- if (anySucceded) {
- completeState = PathCompleteState.Complete;
- SetPathParametersForReturn(chosenTarget);
- } else {
- completeState = PathCompleteState.Error;
- }
- if (callback != null) {
- callback(this);
- }
- }
- protected void FoundTarget (PathNode nodeR, int i) {
- nodeR.flag1 = false;
- Trace(nodeR);
- vectorPaths[i] = vectorPath;
- nodePaths[i] = path;
- vectorPath = Util.ListPool<Vector3>.Claim();
- path = Util.ListPool<GraphNode>.Claim();
- targetsFound[i] = true;
- targetNodeCount--;
-
-
-
- if (!pathsForAll) {
- CompleteState = PathCompleteState.Complete;
- targetNodeCount = 0;
- return;
- }
-
- if (targetNodeCount <= 0) {
- CompleteState = PathCompleteState.Complete;
- return;
- }
- RecalculateHTarget(false);
- }
- protected void RebuildOpenList () {
- BinaryHeap heap = pathHandler.heap;
- for (int j = 0; j < heap.numberOfItems; j++) {
- PathNode nodeR = heap.GetNode(j);
- nodeR.H = CalculateHScore(nodeR.node);
- heap.SetF(j, nodeR.F);
- }
- pathHandler.heap.Rebuild();
- }
- protected override void Prepare () {
- nnConstraint.tags = enabledTags;
- var startNNInfo = AstarPath.active.GetNearest(startPoint, nnConstraint);
- startNode = startNNInfo.node;
- if (startNode == null) {
- FailWithError("Could not find start node for multi target path");
- return;
- }
- if (!CanTraverse(startNode)) {
- FailWithError("The node closest to the start point could not be traversed");
- return;
- }
-
- var pathNNConstraint = nnConstraint as PathNNConstraint;
- if (pathNNConstraint != null) {
- pathNNConstraint.SetStart(startNNInfo.node);
- }
- vectorPaths = new List<Vector3>[targetPoints.Length];
- nodePaths = new List<GraphNode>[targetPoints.Length];
- targetNodes = new GraphNode[targetPoints.Length];
- targetsFound = new bool[targetPoints.Length];
- targetNodeCount = targetPoints.Length;
- bool anyWalkable = false;
- bool anySameArea = false;
- bool anyNotNull = false;
- for (int i = 0; i < targetPoints.Length; i++) {
- var endNNInfo = AstarPath.active.GetNearest(targetPoints[i], nnConstraint);
- targetNodes[i] = endNNInfo.node;
- targetPoints[i] = endNNInfo.position;
- if (targetNodes[i] != null) {
- anyNotNull = true;
- endNode = targetNodes[i];
- }
- bool notReachable = false;
- if (endNNInfo.node != null && CanTraverse(endNNInfo.node)) {
- anyWalkable = true;
- } else {
- notReachable = true;
- }
- if (endNNInfo.node != null && endNNInfo.node.Area == startNode.Area) {
- anySameArea = true;
- } else {
- notReachable = true;
- }
- if (notReachable) {
-
- targetsFound[i] = true;
- targetNodeCount--;
- }
- }
- startPoint = startNNInfo.position;
- startIntPoint = (Int3)startPoint;
- if (!anyNotNull) {
- FailWithError("Couldn't find a valid node close to the any of the end points");
- return;
- }
- if (!anyWalkable) {
- FailWithError("No target nodes could be traversed");
- return;
- }
- if (!anySameArea) {
- FailWithError("There are no valid paths to the targets");
- return;
- }
- RecalculateHTarget(true);
- }
- void RecalculateHTarget (bool firstTime) {
-
-
- if (!pathsForAll) {
- heuristic = Heuristic.None;
- heuristicScale = 0.0F;
- return;
- }
-
-
- switch (heuristicMode) {
- case HeuristicMode.None:
- heuristic = Heuristic.None;
- heuristicScale = 0F;
- break;
- case HeuristicMode.Average:
- if (!firstTime) return;
-
-
-
-
- goto case HeuristicMode.MovingAverage;
- case HeuristicMode.MovingAverage:
-
- var avg = Vector3.zero;
- int count = 0;
- for (int j = 0; j < targetPoints.Length; j++) {
- if (!targetsFound[j]) {
- avg += (Vector3)targetNodes[j].position;
- count++;
- }
- }
-
-
-
- if (count == 0) throw new System.Exception("Should not happen");
- avg /= count;
- hTarget = (Int3)avg;
- break;
- case HeuristicMode.Midpoint:
- if (!firstTime) return;
-
-
-
-
- goto case HeuristicMode.MovingMidpoint;
- case HeuristicMode.MovingMidpoint:
- Vector3 min = Vector3.zero;
- Vector3 max = Vector3.zero;
- bool set = false;
-
-
- for (int j = 0; j < targetPoints.Length; j++) {
- if (!targetsFound[j]) {
- if (!set) {
- min = (Vector3)targetNodes[j].position;
- max = (Vector3)targetNodes[j].position;
- set = true;
- } else {
- min = Vector3.Min((Vector3)targetNodes[j].position, min);
- max = Vector3.Max((Vector3)targetNodes[j].position, max);
- }
- }
- }
- var midpoint = (Int3)((min+max)*0.5F);
- hTarget = midpoint;
- break;
- case HeuristicMode.Sequential:
-
-
-
- if (!firstTime && !targetsFound[sequentialTarget]) {
- return;
- }
- float dist = 0;
-
- for (int j = 0; j < targetPoints.Length; j++) {
- if (!targetsFound[j]) {
- float d = (targetNodes[j].position-startNode.position).sqrMagnitude;
- if (d > dist) {
- dist = d;
- hTarget = (Int3)targetPoints[j];
- sequentialTarget = j;
- }
- }
- }
- break;
- }
-
-
-
- if (!firstTime) {
- RebuildOpenList();
- }
- }
- protected override void Initialize () {
-
-
- PathNode startRNode = pathHandler.GetPathNode(startNode);
- startRNode.node = startNode;
- startRNode.pathID = pathID;
- startRNode.parent = null;
- startRNode.cost = 0;
- startRNode.G = GetTraversalCost(startNode);
- startRNode.H = CalculateHScore(startNode);
- for (int j = 0; j < targetNodes.Length; j++) {
- if (startNode == targetNodes[j]) {
-
-
- FoundTarget(startRNode, j);
- } else if (targetNodes[j] != null) {
-
- pathHandler.GetPathNode(targetNodes[j]).flag1 = true;
- }
- }
-
- if (targetNodeCount <= 0) {
- CompleteState = PathCompleteState.Complete;
- return;
- }
-
-
-
- startNode.Open(this, startRNode, pathHandler);
-
- searchedNodes++;
-
- if (pathHandler.heap.isEmpty) {
- FailWithError("No open points, the start node didn't open any nodes");
- return;
- }
-
- currentR = pathHandler.heap.Remove();
- }
- protected override void Cleanup () {
-
-
- ChooseShortestPath();
- ResetFlags();
- }
-
- void ResetFlags () {
-
- if (targetNodes != null) {
- for (int i = 0; i < targetNodes.Length; i++) {
- if (targetNodes[i] != null) pathHandler.GetPathNode(targetNodes[i]).flag1 = false;
- }
- }
- }
- protected override void CalculateStep (long targetTick) {
- int counter = 0;
-
- while (CompleteState == PathCompleteState.NotCalculated) {
-
- searchedNodes++;
-
- if (currentR.flag1) {
-
- for (int i = 0; i < targetNodes.Length; i++) {
- if (!targetsFound[i] && currentR.node == targetNodes[i]) {
- FoundTarget(currentR, i);
- if (CompleteState != PathCompleteState.NotCalculated) {
- break;
- }
- }
- }
- if (targetNodeCount <= 0) {
- CompleteState = PathCompleteState.Complete;
- break;
- }
- }
-
- currentR.node.Open(this, currentR, pathHandler);
-
- if (pathHandler.heap.isEmpty) {
- CompleteState = PathCompleteState.Complete;
- break;
- }
-
- AstarProfiler.StartFastProfile(7);
- currentR = pathHandler.heap.Remove();
- AstarProfiler.EndFastProfile(7);
-
- if (counter > 500) {
-
- if (System.DateTime.UtcNow.Ticks >= targetTick) {
-
- return;
- }
- counter = 0;
- }
- counter++;
- }
- }
- protected override void Trace (PathNode node) {
- base.Trace(node);
- if (inverted) {
-
- int half = path.Count/2;
- for (int i = 0; i < half; i++) {
- GraphNode tmp = path[i];
- path[i] = path[path.Count-i-1];
- path[path.Count-i-1] = tmp;
- }
- for (int i = 0; i < half; i++) {
- Vector3 tmp = vectorPath[i];
- vectorPath[i] = vectorPath[vectorPath.Count-i-1];
- vectorPath[vectorPath.Count-i-1] = tmp;
- }
- }
- }
- protected override string DebugString (PathLog logMode) {
- if (logMode == PathLog.None || (!error && logMode == PathLog.OnlyErrors)) {
- return "";
- }
- System.Text.StringBuilder text = pathHandler.DebugStringBuilder;
- text.Length = 0;
- DebugStringPrefix(logMode, text);
- if (!error) {
- text.Append("\nShortest path was ");
- text.Append(chosenTarget == -1 ? "undefined" : nodePaths[chosenTarget].Count.ToString());
- text.Append(" nodes long");
- if (logMode == PathLog.Heavy) {
- text.Append("\nPaths (").Append(targetsFound.Length).Append("):");
- for (int i = 0; i < targetsFound.Length; i++) {
- text.Append("\n\n Path ").Append(i).Append(" Found: ").Append(targetsFound[i]);
- if (nodePaths[i] != null) {
- text.Append("\n Length: ");
- text.Append(nodePaths[i].Count);
- GraphNode node = nodePaths[i][nodePaths[i].Count-1];
- if (node != null) {
- PathNode nodeR = pathHandler.GetPathNode(endNode);
- if (nodeR != null) {
- text.Append("\n End Node");
- text.Append("\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);
- } else {
- text.Append("\n End Node: Null");
- }
- }
- }
- }
- text.Append("\nStart Node");
- text.Append("\n Point: ");
- text.Append(((Vector3)endPoint).ToString());
- text.Append("\n Graph: ");
- text.Append(startNode.GraphIndex);
- text.Append("\nBinary Heap size at completion: ");
- text.AppendLine(pathHandler.heap == null ? "Null" : (pathHandler.heap.numberOfItems-2).ToString());
- }
- }
- DebugStringSuffix(logMode, text);
- return text.ToString();
- }
- }
- }
|