123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- using UnityEngine;
- using System.Collections.Generic;
- namespace Pathfinding {
- using Pathfinding.Util;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- [AddComponentMenu("Pathfinding/Modifiers/Raycast Modifier")]
- [RequireComponent(typeof(Seeker))]
- [System.Serializable]
- [HelpURL("http://arongranberg.com/astar/documentation/stable/class_pathfinding_1_1_raycast_modifier.php")]
- public class RaycastModifier : MonoModifier {
- #if UNITY_EDITOR
- [UnityEditor.MenuItem("CONTEXT/Seeker/Add Raycast Simplifier Modifier")]
- public static void AddComp (UnityEditor.MenuCommand command) {
- (command.context as Component).gameObject.AddComponent(typeof(RaycastModifier));
- }
- #endif
- public override int Order { get { return 40; } }
-
- public bool useRaycasting = true;
-
-
-
-
-
- public LayerMask mask = -1;
-
-
-
-
-
-
- [Tooltip("Checks around the line between two points, not just the exact line.\nMake sure the ground is either too far below or is not inside the mask since otherwise the raycast might always hit the ground.")]
- public bool thickRaycast;
-
- [Tooltip("Distance from the ray which will be checked for colliders")]
- public float thickRaycastRadius;
-
-
-
-
-
-
- [Tooltip("Check for intersections with 2D colliders instead of 3D colliders.")]
- public bool use2DPhysics;
-
-
-
-
- [Tooltip("Offset from the original positions to perform the raycast.\nCan be useful to avoid the raycast intersecting the ground or similar things you do not want to it intersect")]
- public Vector3 raycastOffset = Vector3.zero;
-
- [Tooltip("Use raycasting on the graphs. Only currently works with GridGraph and NavmeshGraph and RecastGraph. This is a pro version feature.")]
- public bool useGraphRaycasting;
-
-
-
-
-
- [Tooltip("When using the high quality mode the script will try harder to find a shorter path. This is significantly slower than the greedy low quality approach.")]
- public Quality quality = Quality.Medium;
- public enum Quality {
-
- Low,
-
- Medium,
-
- High,
-
- Highest
- }
- static readonly int[] iterationsByQuality = new [] { 1, 2, 1, 3 };
- static List<Vector3> buffer = new List<Vector3>();
- static float[] DPCosts = new float[16];
- static int[] DPParents = new int[16];
- Filter cachedFilter = new Filter();
- NNConstraint cachedNNConstraint = NNConstraint.None;
- class Filter {
- public Path path;
- public readonly System.Func<GraphNode, bool> cachedDelegate;
- public Filter() {
- cachedDelegate = this.CanTraverse;
- }
- bool CanTraverse (GraphNode node) {
- return path.CanTraverse(node);
- }
- }
- public override void Apply (Path p) {
- if (!useRaycasting && !useGraphRaycasting) return;
- var points = p.vectorPath;
- cachedFilter.path = p;
-
-
- cachedNNConstraint.graphMask = p.nnConstraint.graphMask;
- if (ValidateLine(null, null, p.vectorPath[0], p.vectorPath[p.vectorPath.Count-1], cachedFilter.cachedDelegate, cachedNNConstraint)) {
-
- var s = p.vectorPath[0];
- var e = p.vectorPath[p.vectorPath.Count-1];
- points.ClearFast();
- points.Add(s);
- points.Add(e);
- } else {
- int iterations = iterationsByQuality[(int)quality];
- for (int it = 0; it < iterations; it++) {
- if (it != 0) {
- Polygon.Subdivide(points, buffer, 3);
- Memory.Swap(ref buffer, ref points);
- buffer.ClearFast();
- points.Reverse();
- }
- points = quality >= Quality.High ? ApplyDP(p, points, cachedFilter.cachedDelegate, cachedNNConstraint) : ApplyGreedy(p, points, cachedFilter.cachedDelegate, cachedNNConstraint);
- }
- if ((iterations % 2) == 0) points.Reverse();
- }
- p.vectorPath = points;
- }
- List<Vector3> ApplyGreedy (Path p, List<Vector3> points, System.Func<GraphNode, bool> filter, NNConstraint nnConstraint) {
- bool canBeOriginalNodes = points.Count == p.path.Count;
- int startIndex = 0;
- while (startIndex < points.Count) {
- Vector3 start = points[startIndex];
- var startNode = canBeOriginalNodes && points[startIndex] == (Vector3)p.path[startIndex].position ? p.path[startIndex] : null;
- buffer.Add(start);
-
- int mn = 1, mx = 2;
- while (true) {
- int endIndex = startIndex + mx;
- if (endIndex >= points.Count) {
- mx = points.Count - startIndex;
- break;
- }
- Vector3 end = points[endIndex];
- var endNode = canBeOriginalNodes && end == (Vector3)p.path[endIndex].position ? p.path[endIndex] : null;
- if (!ValidateLine(startNode, endNode, start, end, filter, nnConstraint)) break;
- mn = mx;
- mx *= 2;
- }
- while (mn + 1 < mx) {
- int mid = (mn + mx)/2;
- int endIndex = startIndex + mid;
- Vector3 end = points[endIndex];
- var endNode = canBeOriginalNodes && end == (Vector3)p.path[endIndex].position ? p.path[endIndex] : null;
- if (ValidateLine(startNode, endNode, start, end, filter, nnConstraint)) {
- mn = mid;
- } else {
- mx = mid;
- }
- }
- startIndex += mn;
- }
- Memory.Swap(ref buffer, ref points);
- buffer.ClearFast();
- return points;
- }
- List<Vector3> ApplyDP (Path p, List<Vector3> points, System.Func<GraphNode, bool> filter, NNConstraint nnConstraint) {
- if (DPCosts.Length < points.Count) {
- DPCosts = new float[points.Count];
- DPParents = new int[points.Count];
- }
- for (int i = 0; i < DPParents.Length; i++) DPCosts[i] = DPParents[i] = -1;
- bool canBeOriginalNodes = points.Count == p.path.Count;
- for (int i = 0; i < points.Count; i++) {
- float d = DPCosts[i];
- Vector3 start = points[i];
- var startIsOriginalNode = canBeOriginalNodes && start == (Vector3)p.path[i].position;
- for (int j = i+1; j < points.Count; j++) {
-
-
-
- float d2 = d + (points[j] - start).magnitude + 0.0001f;
- if (DPParents[j] == -1 || d2 < DPCosts[j]) {
- var endIsOriginalNode = canBeOriginalNodes && points[j] == (Vector3)p.path[j].position;
- if (j == i+1 || ValidateLine(startIsOriginalNode ? p.path[i] : null, endIsOriginalNode ? p.path[j] : null, start, points[j], filter, nnConstraint)) {
- DPCosts[j] = d2;
- DPParents[j] = i;
- } else {
- break;
- }
- }
- }
- }
- int c = points.Count - 1;
- while (c != -1) {
- buffer.Add(points[c]);
- c = DPParents[c];
- }
- buffer.Reverse();
- Memory.Swap(ref buffer, ref points);
- buffer.ClearFast();
- return points;
- }
-
-
-
-
- protected bool ValidateLine (GraphNode n1, GraphNode n2, Vector3 v1, Vector3 v2, System.Func<GraphNode, bool> filter, NNConstraint nnConstraint) {
- if (useRaycasting) {
-
- if (use2DPhysics) {
- if (thickRaycast && thickRaycastRadius > 0 && Physics2D.CircleCast(v1 + raycastOffset, thickRaycastRadius, v2 - v1, (v2 - v1).magnitude, mask)) {
- return false;
- }
- if (Physics2D.Linecast(v1+raycastOffset, v2+raycastOffset, mask)) {
- return false;
- }
- } else {
-
-
-
-
-
-
- if (Physics.Linecast(v1+raycastOffset, v2+raycastOffset, mask)) {
- return false;
- }
-
- if (thickRaycast && thickRaycastRadius > 0) {
-
-
-
- if (Physics.CheckSphere(v1 + raycastOffset + (v2 - v1).normalized * thickRaycastRadius, thickRaycastRadius, mask)) {
- return false;
- }
- if (Physics.SphereCast(new Ray(v1+raycastOffset, v2-v1), thickRaycastRadius, (v2-v1).magnitude, mask)) {
- return false;
- }
- }
- }
- }
- if (useGraphRaycasting) {
- #if !ASTAR_NO_GRID_GRAPH
- bool betweenNodeCenters = n1 != null && n2 != null;
- #endif
- if (n1 == null) n1 = AstarPath.active.GetNearest(v1, nnConstraint).node;
- if (n2 == null) n2 = AstarPath.active.GetNearest(v2, nnConstraint).node;
- if (n1 != null && n2 != null) {
-
- NavGraph graph = n1.Graph;
- NavGraph graph2 = n2.Graph;
- if (graph != graph2) {
- return false;
- }
- var rayGraph = graph as IRaycastableGraph;
- #if !ASTAR_NO_GRID_GRAPH
- GridGraph gg = graph as GridGraph;
- if (betweenNodeCenters && gg != null) {
-
-
-
-
- return !gg.Linecast(n1 as GridNodeBase, n2 as GridNodeBase, filter);
- } else
- #endif
- if (rayGraph != null) {
- return !rayGraph.Linecast(v1, v2, out GraphHitInfo _, null, filter);
- }
- }
- }
- return true;
- }
- }
- }
|