Advertisement
Guest User

Untitled

a guest
Dec 6th, 2017
184
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 11.42 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3.  
  4. namespace Pathfinding {
  5.     using Pathfinding.Util;
  6.  
  7.     /** Connects two nodes via two intermediate point nodes.
  8.      * In contrast to the NodeLink component, this link type will not connect the nodes directly
  9.      * instead it will create two point nodes at the start and end position of this link and connect
  10.      * through those nodes.
  11.      *
  12.      * If the closest node to this object is called A and the closest node to the end transform is called
  13.      * D, then it will create one point node at this object's position (call it B) and one point node at
  14.      * the position of the end transform (call it C), it will then connect A to B, B to C and C to D.
  15.      *
  16.      * This link type is possible to detect while following since it has these special point nodes in the middle.
  17.      * The link corresponding to one of those intermediate nodes can be retrieved using the #GetNodeLink method
  18.      * which can be of great use if you want to, for example, play a link specific animation when reaching the link.
  19.      *
  20.      * \see The example scene RecastExample2 contains a few links which you can take a look at to see how they are used.
  21.      */
  22.     [AddComponentMenu("Pathfinding/Link2")]
  23.         public class NodeLink2 : GraphModifier {
  24.         protected static Dictionary<GraphNode, NodeLink2> reference = new Dictionary<GraphNode, NodeLink2>();
  25.         public static NodeLink2 GetNodeLink (GraphNode node) {
  26.             NodeLink2 v;
  27.  
  28.             reference.TryGetValue(node, out v);
  29.             return v;
  30.         }
  31.  
  32.         /** End position of the link */
  33.         public Transform end;
  34.  
  35.         /** The connection will be this times harder/slower to traverse.
  36.          * Note that values lower than 1 will not always make the pathfinder choose this path instead of another path even though this one should
  37.          * lead to a lower total cost unless you also adjust the Heuristic Scale in A* Inspector -> Settings -> Pathfinding or disable the heuristic altogether.
  38.          */
  39.         public float costFactor = 1.0f;
  40.  
  41.         /** Make a one-way connection */
  42.         public bool oneWay = false;
  43.  
  44.         public Transform StartTransform {
  45.             get { return transform; }
  46.         }
  47.  
  48.         public Transform EndTransform {
  49.             get { return end; }
  50.         }
  51.  
  52.         public PointNode startNode { get; private set; }
  53.         public PointNode endNode { get; private set; }
  54.         GraphNode connectedNode1, connectedNode2;
  55.         Vector3 clamped1, clamped2;
  56.         bool postScanCalled = false;
  57.  
  58.         [System.Obsolete("Use startNode instead (lowercase s)")]
  59.         public GraphNode StartNode {
  60.             get { return startNode; }
  61.         }
  62.  
  63.         [System.Obsolete("Use endNode instead (lowercase e)")]
  64.         public GraphNode EndNode {
  65.             get { return endNode; }
  66.         }
  67.  
  68.         public override void OnPostScan () {
  69.             if (EndTransform == null || StartTransform == null) return;
  70.  
  71. #if ASTAR_NO_POINT_GRAPH
  72.             throw new System.Exception("Point graph is not included. Check your A* optimization settings.");
  73. #else
  74.             if (AstarPath.active.data.pointGraph == null) {
  75.                 var graph = AstarPath.active.data.AddGraph(typeof(PointGraph)) as PointGraph;
  76.                 graph.name = "PointGraph (used for node links)";
  77.             }
  78.  
  79.             if (startNode != null && startNode.Destroyed) {
  80.                 reference.Remove(startNode);
  81.                 startNode = null;
  82.             }
  83.  
  84.             if (endNode != null && endNode.Destroyed) {
  85.                 reference.Remove(endNode);
  86.                 endNode = null;
  87.             }
  88.  
  89.             // Create new nodes on the point graph
  90.             if (startNode == null) startNode = AstarPath.active.data.pointGraph.AddNode((Int3)StartTransform.position);
  91.             if (endNode == null) endNode = AstarPath.active.data.pointGraph.AddNode((Int3)EndTransform.position);
  92.  
  93.             connectedNode1 = null;
  94.             connectedNode2 = null;
  95.  
  96.             if (startNode == null || endNode == null) {
  97.                 startNode = null;
  98.                 endNode = null;
  99.                 return;
  100.             }
  101.  
  102.             postScanCalled = true;
  103.             reference[startNode] = this;
  104.             reference[endNode] = this;
  105.             Apply(true);
  106. #endif
  107.         }
  108.  
  109.         public override void OnGraphsPostUpdate () {
  110.             // Don't bother running it now since OnPostScan will be called later anyway
  111.             if (AstarPath.active.isScanning)
  112.                 return;
  113.  
  114.             if (connectedNode1 != null && connectedNode1.Destroyed) {
  115.                 connectedNode1 = null;
  116.             }
  117.             if (connectedNode2 != null && connectedNode2.Destroyed) {
  118.                 connectedNode2 = null;
  119.             }
  120.  
  121.             if (!postScanCalled) {
  122.                 OnPostScan();
  123.             } else {
  124.                 Apply(false);
  125.             }
  126.         }
  127.  
  128.         protected override void OnEnable () {
  129.             base.OnEnable();
  130.  
  131. #if !ASTAR_NO_POINT_GRAPH
  132.             if (Application.isPlaying && AstarPath.active != null && AstarPath.active.data != null && AstarPath.active.data.pointGraph != null && !AstarPath.active.isScanning) {
  133.                 // Call OnGraphsPostUpdate as soon as possible when it is safe to update the graphs
  134.                 AstarPath.active.AddWorkItem(new AstarWorkItem((ctx, force) => {
  135.                     OnGraphsPostUpdate();
  136.                     ctx.QueueFloodFill();
  137.                     return true;
  138.                 }));
  139.             }
  140. #endif
  141.         }
  142.  
  143.         protected override void OnDisable () {
  144.             base.OnDisable();
  145.  
  146.             AstarPath.active.AddWorkItem(new AstarWorkItem((ctx, force) => {
  147.                 OnDisableWorkItem();
  148.                 ctx.QueueFloodFill();
  149.                 return true;
  150.             }));
  151.         }
  152.  
  153.         void OnDisableWorkItem () {
  154.             postScanCalled = false;
  155.             if (startNode != null) reference.Remove(startNode);
  156.             if (endNode != null) reference.Remove(endNode);
  157.            
  158.             if (startNode != null && endNode != null) {
  159.                 startNode.RemoveConnection(endNode);
  160.                 endNode.RemoveConnection(startNode);
  161.                
  162.                 if (connectedNode1 != null && connectedNode2 != null) {
  163.                     startNode.RemoveConnection(connectedNode1);
  164.                     connectedNode1.RemoveConnection(startNode);
  165.                    
  166.                     endNode.RemoveConnection(connectedNode2);
  167.                     connectedNode2.RemoveConnection(endNode);
  168.                 }
  169.             }
  170.         }
  171.  
  172.         void RemoveConnections (GraphNode node) {
  173.             //TODO, might be better to replace connection
  174.             node.ClearConnections(true);
  175.         }
  176.  
  177.         [ContextMenu("Recalculate neighbours")]
  178.         void ContextApplyForce () {
  179.             if (Application.isPlaying) {
  180.                 Apply(true);
  181.                 if (AstarPath.active != null) {
  182.                     AstarPath.active.FloodFill();
  183.                 }
  184.             }
  185.         }
  186.  
  187.         public void Apply (bool forceNewCheck) {
  188.             //TODO
  189.             //This function assumes that connections from the n1,n2 nodes never need to be removed in the future (e.g because the nodes move or something)
  190.             NNConstraint nn = NNConstraint.None;
  191.             int graph = (int)startNode.GraphIndex;
  192.  
  193.             //Search all graphs but the one which start and end nodes are on
  194.             nn.graphMask = ~(1 << graph);
  195.  
  196.             startNode.SetPosition((Int3)StartTransform.position);
  197.             endNode.SetPosition((Int3)EndTransform.position);
  198.  
  199.             RemoveConnections(startNode);
  200.             RemoveConnections(endNode);
  201.  
  202.             uint cost = (uint)Mathf.RoundToInt(((Int3)(StartTransform.position-EndTransform.position)).costMagnitude*costFactor);
  203.             startNode.AddConnection(endNode, cost);
  204.             endNode.AddConnection(startNode, cost);
  205.  
  206.             if (connectedNode1 == null || forceNewCheck) {
  207.                 var info = AstarPath.active.GetNearest(StartTransform.position, nn);
  208.                 connectedNode1 = info.node;
  209.                 clamped1 = info.position;
  210.             }
  211.  
  212.             if (connectedNode2 == null || forceNewCheck) {
  213.                 var info = AstarPath.active.GetNearest(EndTransform.position, nn);
  214.                 connectedNode2 = info.node;
  215.                 clamped2 = info.position;
  216.             }
  217.  
  218.             if (connectedNode2 == null || connectedNode1 == null) return;
  219.  
  220.             //Add connections between nodes, or replace old connections if existing
  221.             connectedNode1.AddConnection(startNode, (uint)Mathf.RoundToInt(((Int3)(clamped1 - StartTransform.position)).costMagnitude*costFactor));
  222.             if (!oneWay) connectedNode2.AddConnection(endNode, (uint)Mathf.RoundToInt(((Int3)(clamped2 - EndTransform.position)).costMagnitude*costFactor));
  223.  
  224.             if (!oneWay) startNode.AddConnection(connectedNode1, (uint)Mathf.RoundToInt(((Int3)(clamped1 - StartTransform.position)).costMagnitude*costFactor));
  225.             endNode.AddConnection(connectedNode2, (uint)Mathf.RoundToInt(((Int3)(clamped2 - EndTransform.position)).costMagnitude*costFactor));
  226.         }
  227.  
  228.         private readonly static Color GizmosColor = new Color(206.0f/255.0f, 136.0f/255.0f, 48.0f/255.0f, 0.5f);
  229.         private readonly static Color GizmosColorSelected = new Color(235.0f/255.0f, 123.0f/255.0f, 32.0f/255.0f, 1.0f);
  230.  
  231.         public virtual void OnDrawGizmosSelected () {
  232.             OnDrawGizmos(true);
  233.         }
  234.  
  235.         public void OnDrawGizmos () {
  236.             OnDrawGizmos(false);
  237.         }
  238.  
  239.         public void OnDrawGizmos (bool selected) {
  240.             Color color = selected ? GizmosColorSelected : GizmosColor;
  241.  
  242.             if (StartTransform != null) {
  243.                 Draw.Gizmos.CircleXZ(StartTransform.position, 0.4f, color);
  244.             }
  245.             if (EndTransform != null) {
  246.                 Draw.Gizmos.CircleXZ(EndTransform.position, 0.4f, color);
  247.             }
  248.  
  249.             if (StartTransform != null && EndTransform != null) {
  250.                 Draw.Gizmos.Bezier(StartTransform.position, EndTransform.position, color);
  251.                 if (selected) {
  252.                     Vector3 cross = Vector3.Cross(Vector3.up, (EndTransform.position-StartTransform.position)).normalized;
  253.                     Draw.Gizmos.Bezier(StartTransform.position+cross*0.1f, EndTransform.position+cross*0.1f, color);
  254.                     Draw.Gizmos.Bezier(StartTransform.position-cross*0.1f, EndTransform.position-cross*0.1f, color);
  255.                 }
  256.             }
  257.         }
  258.  
  259.         internal static void SerializeReferences (Pathfinding.Serialization.GraphSerializationContext ctx) {
  260.             var links = GetModifiersOfType<NodeLink2>();
  261.  
  262.             ctx.writer.Write(links.Count);
  263.             foreach (var link in links) {
  264.                 ctx.writer.Write(link.uniqueID);
  265.                 ctx.SerializeNodeReference(link.startNode);
  266.                 ctx.SerializeNodeReference(link.endNode);
  267.                 ctx.SerializeNodeReference(link.connectedNode1);
  268.                 ctx.SerializeNodeReference(link.connectedNode2);
  269.                 ctx.SerializeVector3(link.clamped1);
  270.                 ctx.SerializeVector3(link.clamped2);
  271.                 ctx.writer.Write(link.postScanCalled);
  272.             }
  273.         }
  274.  
  275.         internal static void DeserializeReferences (Pathfinding.Serialization.GraphSerializationContext ctx) {
  276.             int count = ctx.reader.ReadInt32();
  277.  
  278.             for (int i = 0; i < count; i++) {
  279.                 var linkID = ctx.reader.ReadUInt64();
  280.                 var startNode = ctx.DeserializeNodeReference();
  281.                 var endNode = ctx.DeserializeNodeReference();
  282.                 var connectedNode1 = ctx.DeserializeNodeReference();
  283.                 var connectedNode2 = ctx.DeserializeNodeReference();
  284.                 var clamped1 = ctx.DeserializeVector3();
  285.                 var clamped2 = ctx.DeserializeVector3();
  286.                 var postScanCalled = ctx.reader.ReadBoolean();
  287.  
  288.                 GraphModifier link;
  289.                 if (usedIDs.TryGetValue(linkID, out link)) {
  290.                     var link2 = link as NodeLink2;
  291.                     if (link2 != null) {
  292.                         if (startNode != null) reference[startNode] = link2;
  293.                         if (endNode != null) reference[endNode] = link2;
  294.  
  295.                         // If any nodes happened to be registered right now
  296.                         if (link2.startNode != null) reference.Remove(link2.startNode);
  297.                         if (link2.endNode != null) reference.Remove(link2.endNode);
  298.  
  299.                         link2.startNode = startNode as PointNode;
  300.                         link2.endNode = endNode as PointNode;
  301.                         link2.connectedNode1 = connectedNode1;
  302.                         link2.connectedNode2 = connectedNode2;
  303.                         link2.postScanCalled = postScanCalled;
  304.                         link2.clamped1 = clamped1;
  305.                         link2.clamped2 = clamped2;
  306.                     } else {
  307.                         throw new System.Exception("Tried to deserialize a NodeLink2 reference, but the link was not of the correct type or it has been destroyed.\nIf a NodeLink2 is included in serialized graph data, the same NodeLink2 component must be present in the scene when loading the graph data.");
  308.                     }
  309.                 } else {
  310.                     throw new System.Exception("Tried to deserialize a NodeLink2 reference, but the link could not be found in the scene.\nIf a NodeLink2 is included in serialized graph data, the same NodeLink2 component must be present in the scene when loading the graph data.");
  311.                 }
  312.             }
  313.         }
  314.     }
  315. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement