123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766 |
- using UnityEngine;
- using System.Collections.Generic;
- using Pathfinding.Serialization;
- namespace Pathfinding {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- [JsonOptIn]
- [Pathfinding.Util.Preserve]
- public class PointGraph : NavGraph
- , IUpdatableGraph {
-
- [JsonMember]
- public Transform root;
-
- [JsonMember]
- public string searchTag;
-
-
-
-
-
-
-
-
-
- [JsonMember]
- public float maxDistance;
-
- [JsonMember]
- public Vector3 limits;
-
- [JsonMember]
- public bool raycast = true;
-
- [JsonMember]
- public bool use2DPhysics;
-
- [JsonMember]
- public bool thickRaycast;
-
- [JsonMember]
- public float thickRaycastRadius = 1;
-
- [JsonMember]
- public bool recursive = true;
-
- [JsonMember]
- public LayerMask mask;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- [JsonMember]
- public bool optimizeForSparseGraph;
- PointKDTree lookupTree = new PointKDTree();
-
-
-
-
-
-
- long maximumConnectionLength = 0;
-
-
-
-
-
-
- public PointNode[] nodes;
-
-
-
-
-
-
-
-
- [JsonMember]
- public NodeDistanceMode nearestNodeDistanceMode;
-
- public int nodeCount { get; protected set; }
-
-
-
-
-
-
-
-
-
-
-
-
- public enum NodeDistanceMode {
-
-
-
-
- Node,
-
-
-
-
-
- Connection,
- }
- public override int CountNodes () {
- return nodeCount;
- }
- public override void GetNodes (System.Action<GraphNode> action) {
- if (nodes == null) return;
- var count = nodeCount;
- for (int i = 0; i < count; i++) action(nodes[i]);
- }
- public override NNInfoInternal GetNearest (Vector3 position, NNConstraint constraint, GraphNode hint) {
- return GetNearestInternal(position, constraint, true);
- }
- public override NNInfoInternal GetNearestForce (Vector3 position, NNConstraint constraint) {
- return GetNearestInternal(position, constraint, false);
- }
- NNInfoInternal GetNearestInternal (Vector3 position, NNConstraint constraint, bool fastCheck) {
- if (nodes == null) return new NNInfoInternal();
- var iposition = (Int3)position;
- if (optimizeForSparseGraph) {
- if (nearestNodeDistanceMode == NodeDistanceMode.Node) {
- return new NNInfoInternal(lookupTree.GetNearest(iposition, fastCheck ? null : constraint));
- } else {
- var closestNode = lookupTree.GetNearestConnection(iposition, fastCheck ? null : constraint, maximumConnectionLength);
- if (closestNode == null) return new NNInfoInternal();
- return FindClosestConnectionPoint(closestNode as PointNode, position);
- }
- }
- float maxDistSqr = constraint == null || constraint.constrainDistance ? AstarPath.active.maxNearestNodeDistanceSqr : float.PositiveInfinity;
- maxDistSqr *= Int3.FloatPrecision * Int3.FloatPrecision;
- var nnInfo = new NNInfoInternal(null);
- long minDist = long.MaxValue;
- long minConstDist = long.MaxValue;
- for (int i = 0; i < nodeCount; i++) {
- PointNode node = nodes[i];
- long dist = (iposition - node.position).sqrMagnitudeLong;
- if (dist < minDist) {
- minDist = dist;
- nnInfo.node = node;
- }
- if (dist < minConstDist && (float)dist < maxDistSqr && (constraint == null || constraint.Suitable(node))) {
- minConstDist = dist;
- nnInfo.constrainedNode = node;
- }
- }
- if (!fastCheck) nnInfo.node = nnInfo.constrainedNode;
- nnInfo.UpdateInfo();
- return nnInfo;
- }
- NNInfoInternal FindClosestConnectionPoint (PointNode node, Vector3 position) {
- var closestConnectionPoint = (Vector3)node.position;
- var conns = node.connections;
- var nodePos = (Vector3)node.position;
- var bestDist = float.PositiveInfinity;
- if (conns != null) {
- for (int i = 0; i < conns.Length; i++) {
- var connectionMidpoint = ((UnityEngine.Vector3)conns[i].node.position + nodePos) * 0.5f;
- var closestPoint = VectorMath.ClosestPointOnSegment(nodePos, connectionMidpoint, position);
- var dist = (closestPoint - position).sqrMagnitude;
- if (dist < bestDist) {
- bestDist = dist;
- closestConnectionPoint = closestPoint;
- }
- }
- }
- var result = new NNInfoInternal();
- result.node = node;
- result.clampedPosition = closestConnectionPoint;
- return result;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public PointNode AddNode (Int3 position) {
- return AddNode(new PointNode(active), position);
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public T AddNode<T>(T node, Int3 position) where T : PointNode {
- if (nodes == null || nodeCount == nodes.Length) {
- var newNodes = new PointNode[nodes != null ? System.Math.Max(nodes.Length+4, nodes.Length*2) : 4];
- if (nodes != null) nodes.CopyTo(newNodes, 0);
- nodes = newNodes;
- }
- node.SetPosition(position);
- node.GraphIndex = graphIndex;
- node.Walkable = true;
- nodes[nodeCount] = node;
- nodeCount++;
- if (optimizeForSparseGraph) AddToLookup(node);
- return node;
- }
-
- protected static int CountChildren (Transform tr) {
- int c = 0;
- foreach (Transform child in tr) {
- c++;
- c += CountChildren(child);
- }
- return c;
- }
-
- protected void AddChildren (ref int c, Transform tr) {
- foreach (Transform child in tr) {
- nodes[c].position = (Int3)child.position;
- nodes[c].Walkable = true;
- nodes[c].gameObject = child.gameObject;
- c++;
- AddChildren(ref c, child);
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public void RebuildNodeLookup () {
- if (!optimizeForSparseGraph || nodes == null) {
- lookupTree = new PointKDTree();
- } else {
- lookupTree.Rebuild(nodes, 0, nodeCount);
- }
- RebuildConnectionDistanceLookup();
- }
-
- public void RebuildConnectionDistanceLookup () {
- maximumConnectionLength = 0;
- if (nearestNodeDistanceMode == NodeDistanceMode.Connection) {
- for (int j = 0; j < nodeCount; j++) {
- var node = nodes[j];
- var conns = node.connections;
- if (conns != null) {
- for (int i = 0; i < conns.Length; i++) {
- var dist = (node.position - conns[i].node.position).sqrMagnitudeLong;
- RegisterConnectionLength(dist);
- }
- }
- }
- }
- }
- void AddToLookup (PointNode node) {
- lookupTree.Add(node);
- }
-
-
-
-
-
-
-
-
-
-
- public void RegisterConnectionLength (long sqrLength) {
- maximumConnectionLength = System.Math.Max(maximumConnectionLength, sqrLength);
- }
- protected virtual PointNode[] CreateNodes (int count) {
- var nodes = new PointNode[count];
- for (int i = 0; i < nodeCount; i++) nodes[i] = new PointNode(active);
- return nodes;
- }
- protected override IEnumerable<Progress> ScanInternal () {
- yield return new Progress(0, "Searching for GameObjects");
- if (root == null) {
-
- GameObject[] gos = searchTag != null? GameObject.FindGameObjectsWithTag(searchTag) : null;
- if (gos == null) {
- nodes = new PointNode[0];
- nodeCount = 0;
- } else {
- yield return new Progress(0.1f, "Creating nodes");
-
- nodeCount = gos.Length;
- nodes = CreateNodes(nodeCount);
- for (int i = 0; i < gos.Length; i++) {
- nodes[i].position = (Int3)gos[i].transform.position;
- nodes[i].Walkable = true;
- nodes[i].gameObject = gos[i].gameObject;
- }
- }
- } else {
-
- if (!recursive) {
- nodeCount = root.childCount;
- nodes = CreateNodes(nodeCount);
- int c = 0;
- foreach (Transform child in root) {
- nodes[c].position = (Int3)child.position;
- nodes[c].Walkable = true;
- nodes[c].gameObject = child.gameObject;
- c++;
- }
- } else {
- nodeCount = CountChildren(root);
- nodes = CreateNodes(nodeCount);
- int startID = 0;
- AddChildren(ref startID, root);
- }
- }
- yield return new Progress(0.15f, "Building node lookup");
-
- RebuildNodeLookup();
- foreach (var progress in ConnectNodesAsync()) yield return progress.MapTo(0.15f, 0.95f);
- yield return new Progress(0.95f, "Building connection distances");
-
- RebuildConnectionDistanceLookup();
- }
-
-
-
-
- public void ConnectNodes () {
- var ie = ConnectNodesAsync().GetEnumerator();
- while (ie.MoveNext()) {}
- RebuildConnectionDistanceLookup();
- }
-
-
-
-
- IEnumerable<Progress> ConnectNodesAsync () {
- if (maxDistance >= 0) {
-
- var connections = new List<Connection>();
- var candidateConnections = new List<GraphNode>();
- long maxSquaredRange;
-
-
- if (maxDistance == 0 && (limits.x == 0 || limits.y == 0 || limits.z == 0)) {
- maxSquaredRange = long.MaxValue;
- } else {
- maxSquaredRange = (long)(Mathf.Max(limits.x, Mathf.Max(limits.y, Mathf.Max(limits.z, maxDistance))) * Int3.Precision) + 1;
- maxSquaredRange *= maxSquaredRange;
- }
-
- const int YieldEveryNNodes = 512;
-
- for (int i = 0; i < nodeCount; i++) {
- if (i % YieldEveryNNodes == 0) {
- yield return new Progress(i/(float)nodeCount, "Connecting nodes");
- }
- connections.Clear();
- var node = nodes[i];
- if (optimizeForSparseGraph) {
- candidateConnections.Clear();
- lookupTree.GetInRange(node.position, maxSquaredRange, candidateConnections);
- for (int j = 0; j < candidateConnections.Count; j++) {
- var other = candidateConnections[j] as PointNode;
- float dist;
- if (other != node && IsValidConnection(node, other, out dist)) {
- connections.Add(new Connection(
- other,
-
- (uint)Mathf.RoundToInt(dist*Int3.FloatPrecision)
- ));
- }
- }
- } else {
-
- for (int j = 0; j < nodeCount; j++) {
- if (i == j) continue;
- PointNode other = nodes[j];
- float dist;
- if (IsValidConnection(node, other, out dist)) {
- connections.Add(new Connection(
- other,
-
- (uint)Mathf.RoundToInt(dist*Int3.FloatPrecision)
- ));
- }
- }
- }
- node.connections = connections.ToArray();
- node.SetConnectivityDirty();
- }
- }
- }
-
-
-
-
-
-
-
-
- public virtual bool IsValidConnection (GraphNode a, GraphNode b, out float dist) {
- dist = 0;
- if (!a.Walkable || !b.Walkable) return false;
- var dir = (Vector3)(b.position-a.position);
- if (
- (!Mathf.Approximately(limits.x, 0) && Mathf.Abs(dir.x) > limits.x) ||
- (!Mathf.Approximately(limits.y, 0) && Mathf.Abs(dir.y) > limits.y) ||
- (!Mathf.Approximately(limits.z, 0) && Mathf.Abs(dir.z) > limits.z)) {
- return false;
- }
- dist = dir.magnitude;
- if (maxDistance == 0 || dist < maxDistance) {
- if (raycast) {
- var ray = new Ray((Vector3)a.position, dir);
- var invertRay = new Ray((Vector3)b.position, -dir);
- if (use2DPhysics) {
- if (thickRaycast) {
- return !Physics2D.CircleCast(ray.origin, thickRaycastRadius, ray.direction, dist, mask) && !Physics2D.CircleCast(invertRay.origin, thickRaycastRadius, invertRay.direction, dist, mask);
- } else {
- return !Physics2D.Linecast((Vector2)(Vector3)a.position, (Vector2)(Vector3)b.position, mask) && !Physics2D.Linecast((Vector2)(Vector3)b.position, (Vector2)(Vector3)a.position, mask);
- }
- } else {
- if (thickRaycast) {
- return !Physics.SphereCast(ray, thickRaycastRadius, dist, mask) && !Physics.SphereCast(invertRay, thickRaycastRadius, dist, mask);
- } else {
- return !Physics.Linecast((Vector3)a.position, (Vector3)b.position, mask) && !Physics.Linecast((Vector3)b.position, (Vector3)a.position, mask);
- }
- }
- } else {
- return true;
- }
- }
- return false;
- }
- GraphUpdateThreading IUpdatableGraph.CanUpdateAsync (GraphUpdateObject o) {
- return GraphUpdateThreading.UnityThread;
- }
- void IUpdatableGraph.UpdateAreaInit (GraphUpdateObject o) {}
- void IUpdatableGraph.UpdateAreaPost (GraphUpdateObject o) {}
-
-
-
-
- void IUpdatableGraph.UpdateArea (GraphUpdateObject guo) {
- if (nodes == null) return;
- for (int i = 0; i < nodeCount; i++) {
- var node = nodes[i];
- if (guo.bounds.Contains((Vector3)node.position)) {
- guo.WillUpdateNode(node);
- guo.Apply(node);
- }
- }
- if (guo.updatePhysics) {
-
- Bounds bounds = guo.bounds;
- if (thickRaycast) {
-
- bounds.Expand(thickRaycastRadius*2);
- }
-
- List<Connection> tmpList = Pathfinding.Util.ListPool<Connection>.Claim();
- for (int i = 0; i < nodeCount; i++) {
- PointNode node = nodes[i];
- var nodePos = (Vector3)node.position;
- List<Connection> conn = null;
- for (int j = 0; j < nodeCount; j++) {
- if (j == i) continue;
- var otherNodePos = (Vector3)nodes[j].position;
-
-
- if (VectorMath.SegmentIntersectsBounds(bounds, nodePos, otherNodePos)) {
- float dist;
- PointNode other = nodes[j];
- bool contains = node.ContainsConnection(other);
- bool validConnection = IsValidConnection(node, other, out dist);
-
- if (conn == null && (contains != validConnection)) {
- tmpList.Clear();
- conn = tmpList;
- conn.AddRange(node.connections);
- }
- if (!contains && validConnection) {
-
- uint cost = (uint)Mathf.RoundToInt(dist*Int3.FloatPrecision);
- conn.Add(new Connection(other, cost));
- RegisterConnectionLength((other.position - node.position).sqrMagnitudeLong);
- } else if (contains && !validConnection) {
-
- for (int q = 0; q < conn.Count; q++) {
- if (conn[q].node == other) {
- conn.RemoveAt(q);
- break;
- }
- }
- }
- }
- }
-
- if (conn != null) {
- node.connections = conn.ToArray();
- node.SetConnectivityDirty();
- }
- }
-
- Pathfinding.Util.ListPool<Connection>.Release(ref tmpList);
- }
- }
- #if UNITY_EDITOR
- public override void OnDrawGizmos (Pathfinding.Util.RetainedGizmos gizmos, bool drawNodes) {
- base.OnDrawGizmos(gizmos, drawNodes);
- if (!drawNodes) return;
- Gizmos.color = new Color(0.161f, 0.341f, 1f, 0.5f);
- if (root != null) {
- DrawChildren(this, root);
- } else if (!string.IsNullOrEmpty(searchTag)) {
- GameObject[] gos = GameObject.FindGameObjectsWithTag(searchTag);
- for (int i = 0; i < gos.Length; i++) {
- Gizmos.DrawCube(gos[i].transform.position, Vector3.one*UnityEditor.HandleUtility.GetHandleSize(gos[i].transform.position)*0.1F);
- }
- }
- }
- static void DrawChildren (PointGraph graph, Transform tr) {
- foreach (Transform child in tr) {
- Gizmos.DrawCube(child.position, Vector3.one*UnityEditor.HandleUtility.GetHandleSize(child.position)*0.1F);
- if (graph.recursive) DrawChildren(graph, child);
- }
- }
- #endif
- protected override void PostDeserialization (GraphSerializationContext ctx) {
- RebuildNodeLookup();
- }
- public override void RelocateNodes (Matrix4x4 deltaMatrix) {
- base.RelocateNodes(deltaMatrix);
- RebuildNodeLookup();
- }
- protected override void DeserializeSettingsCompatibility (GraphSerializationContext ctx) {
- base.DeserializeSettingsCompatibility(ctx);
- root = ctx.DeserializeUnityObject() as Transform;
- searchTag = ctx.reader.ReadString();
- maxDistance = ctx.reader.ReadSingle();
- limits = ctx.DeserializeVector3();
- raycast = ctx.reader.ReadBoolean();
- use2DPhysics = ctx.reader.ReadBoolean();
- thickRaycast = ctx.reader.ReadBoolean();
- thickRaycastRadius = ctx.reader.ReadSingle();
- recursive = ctx.reader.ReadBoolean();
- ctx.reader.ReadBoolean();
- mask = (LayerMask)ctx.reader.ReadInt32();
- optimizeForSparseGraph = ctx.reader.ReadBoolean();
- ctx.reader.ReadBoolean();
- }
- protected override void SerializeExtraInfo (GraphSerializationContext ctx) {
-
- if (nodes == null) ctx.writer.Write(-1);
-
- ctx.writer.Write(nodeCount);
- for (int i = 0; i < nodeCount; i++) {
-
- if (nodes[i] == null) ctx.writer.Write(-1);
- else {
- ctx.writer.Write(0);
- nodes[i].SerializeNode(ctx);
- }
- }
- }
- protected override void DeserializeExtraInfo (GraphSerializationContext ctx) {
- int count = ctx.reader.ReadInt32();
- if (count == -1) {
- nodes = null;
- return;
- }
- nodes = new PointNode[count];
- nodeCount = count;
- for (int i = 0; i < nodes.Length; i++) {
- if (ctx.reader.ReadInt32() == -1) continue;
- nodes[i] = new PointNode(active);
- nodes[i].DeserializeNode(ctx);
- }
- }
- }
- }
|