using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Pathfinding {
using Pathfinding.Util;
using Pathfinding.Drawing;
///
/// Connects two nodes with a direct connection.
/// It is not possible to detect this link when following a path (which may be good or bad), for that you can use NodeLink2.
///
/// [Open online documentation to see images]
///
/// See: editing-graphs (view in online documentation for working links)
///
[AddComponentMenu("Pathfinding/Link")]
[HelpURL("https://arongranberg.com/astar/documentation/stable/nodelink.html")]
public class NodeLink : GraphModifier {
/// End position of the link
public Transform end;
///
/// The connection will be this times harder/slower to traverse.
/// Note that values lower than one will not always make the pathfinder choose this path instead of another path even though this one should
/// lead to a lower total cost unless you also adjust the Heuristic Scale in A* Inspector -> Settings -> Pathfinding or disable the heuristic altogether.
///
public float costFactor = 1.0f;
/// Make a one-way connection
public bool oneWay = false;
/// Delete existing connection instead of adding one
public bool deleteConnection = false;
public Transform Start {
get { return transform; }
}
public Transform End {
get { return end; }
}
public override void OnGraphsPostUpdateBeforeAreaRecalculation () {
Apply();
}
public static void DrawArch (Vector3 a, Vector3 b, Vector3 up, Color color) {
Vector3 dir = b - a;
if (dir == Vector3.zero) return;
var normal = Vector3.Cross(up, dir);
var normalUp = Vector3.Cross(dir, normal).normalized * dir.magnitude * 0.1f;
Draw.Bezier(a, a + normalUp, b + normalUp, b, color);
}
///
/// Connects the start and end points using a link or refreshes the existing link.
///
/// If you have moved the link or otherwise modified it you need to call this method.
///
/// Warning: This must only be done when it is safe to update the graph structure.
/// The easiest is to do it inside a work item. See .
///
public virtual void Apply () {
if (Start == null || End == null || AstarPath.active == null) return;
GraphNode startNode = AstarPath.active.GetNearest(Start.position).node;
GraphNode endNode = AstarPath.active.GetNearest(End.position).node;
if (startNode == null || endNode == null) return;
if (deleteConnection) {
GraphNode.Disconnect(startNode, endNode);
} else {
uint cost = (uint)System.Math.Round((startNode.position-endNode.position).costMagnitude*costFactor);
GraphNode.Connect(startNode, endNode, cost, oneWay ? OffMeshLinks.Directionality.OneWay : OffMeshLinks.Directionality.TwoWay);
}
}
public override void DrawGizmos () {
if (Start == null || End == null) return;
NodeLink.DrawArch(Start.position, End.position, Vector3.up, deleteConnection ? Color.red : Color.green);
}
#if UNITY_EDITOR
[UnityEditor.MenuItem("Edit/Pathfinding/Link Pair %&l")]
public static void LinkObjects () {
Transform[] tfs = Selection.transforms;
if (tfs.Length == 2) {
LinkObjects(tfs[0], tfs[1], false);
}
SceneView.RepaintAll();
}
[UnityEditor.MenuItem("Edit/Pathfinding/Unlink Pair %&u")]
public static void UnlinkObjects () {
Transform[] tfs = Selection.transforms;
if (tfs.Length == 2) {
LinkObjects(tfs[0], tfs[1], true);
}
SceneView.RepaintAll();
}
[UnityEditor.MenuItem("Edit/Pathfinding/Delete Links on Selected %&b")]
public static void DeleteLinks () {
Transform[] tfs = Selection.transforms;
for (int i = 0; i < tfs.Length; i++) {
NodeLink[] conns = tfs[i].GetComponents();
for (int j = 0; j < conns.Length; j++) DestroyImmediate(conns[j]);
}
SceneView.RepaintAll();
}
public static void LinkObjects (Transform a, Transform b, bool removeConnection) {
NodeLink connecting = null;
NodeLink[] conns = a.GetComponents();
for (int i = 0; i < conns.Length; i++) {
if (conns[i].end == b) {
connecting = conns[i];
break;
}
}
conns = b.GetComponents();
for (int i = 0; i < conns.Length; i++) {
if (conns[i].end == a) {
connecting = conns[i];
break;
}
}
if (removeConnection) {
if (connecting != null) DestroyImmediate(connecting);
} else {
if (connecting == null) {
connecting = a.gameObject.AddComponent();
connecting.end = b;
} else {
connecting.deleteConnection = !connecting.deleteConnection;
}
}
}
#endif
}
}