rabidus-test/Assets/Dreamteck/Splines/Components/Node.cs

413 lines
14 KiB
C#
Raw Permalink Normal View History

2023-07-24 16:38:13 +03:00
using UnityEngine;
using System.Collections;
namespace Dreamteck.Splines
{
[ExecuteInEditMode]
[AddComponentMenu("Dreamteck/Splines/Node Connector")]
public class Node : MonoBehaviour
{
[System.Serializable]
public class Connection
{
public SplineComputer spline
{
get { return _computer; }
}
public int pointIndex
{
get { return _pointIndex; }
}
public bool invertTangents = false;
[SerializeField]
private int _pointIndex = 0;
[SerializeField]
private SplineComputer _computer = null;
[SerializeField]
[HideInInspector]
internal SplinePoint point;
internal bool isValid
{
get
{
if (_computer == null) return false;
if (_pointIndex >= _computer.pointCount) return false;
return true;
}
}
internal Connection(SplineComputer comp, int index, SplinePoint inputPoint)
{
_pointIndex = index;
_computer = comp;
point = inputPoint;
}
}
public enum Type { Smooth, Free }
[HideInInspector]
public Type type = Type.Smooth;
public bool transformNormals
{
get { return _transformNormals; }
set
{
if (value != _transformNormals)
{
_transformNormals = value;
UpdatePoints();
}
}
}
public bool transformSize
{
get { return _transformSize; }
set
{
if (value != _transformSize)
{
_transformSize = value;
UpdatePoints();
}
}
}
public bool transformTangents
{
get { return _transformTangents; }
set
{
if (value != _transformTangents)
{
_transformTangents = value;
UpdatePoints();
}
}
}
[SerializeField]
[HideInInspector]
protected Connection[] connections = new Connection[0];
[SerializeField]
[HideInInspector]
private bool _transformSize = true;
[SerializeField]
[HideInInspector]
private bool _transformNormals = true;
[SerializeField]
[HideInInspector]
private bool _transformTangents = true;
private Vector3 _lastPosition, _lastScale;
private Quaternion _lastRotation;
private Transform _trs;
private void Awake()
{
_trs = transform;
SampleTransform();
}
void LateUpdate()
{
Run();
}
void Update()
{
Run();
}
bool TransformChanged()
{
#if UNITY_EDITOR
if(_trs == null) return _lastPosition != transform.position || _lastRotation != transform.rotation || _lastScale != transform.lossyScale;
#endif
return _lastPosition != _trs.position || _lastRotation != _trs.rotation || _lastScale != _trs.lossyScale;
}
void SampleTransform() {
#if UNITY_EDITOR
if (!Application.isPlaying)
{
_lastPosition = transform.position;
_lastScale = transform.lossyScale;
_lastRotation = transform.rotation;
}
else
{
_lastPosition = _trs.position;
_lastScale = _trs.lossyScale;
_lastRotation = _trs.rotation;
}
return;
#else
_lastPosition = _trs.position;
_lastScale = _trs.lossyScale;
_lastRotation = _trs.rotation;
#endif
}
private void Run()
{
if (TransformChanged())
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
UnityEditor.EditorUtility.SetDirty(this);
for (int i = 0; i < connections.Length; i++)
{
UnityEditor.EditorUtility.SetDirty(connections[i].spline);
}
}
#endif
UpdateConnectedComputers();
SampleTransform();
}
}
public SplinePoint GetPoint(int connectionIndex, bool swapTangents)
{
SplinePoint point = PointToWorld(connections[connectionIndex].point);
if (connections[connectionIndex].invertTangents && swapTangents)
{
Vector3 tempTan = point.tangent;
point.tangent = point.tangent2;
point.tangent2 = tempTan;
}
return point;
}
public void SetPoint(int connectionIndex, SplinePoint worldPoint, bool swappedTangents)
{
Connection connection = connections[connectionIndex];
connection.point = PointToLocal(worldPoint);
if (connection.invertTangents && swappedTangents)
{
Vector3 tempTan = connection.point.tangent;
connection.point.tangent = connection.point.tangent2;
connection.point.tangent2 = tempTan;
}
if (type == Type.Smooth)
{
if (connection.point.type == SplinePoint.Type.SmoothFree)
{
for (int i = 0; i < connections.Length; i++)
{
if (i == connectionIndex) continue;
Vector3 tanDir = (connection.point.tangent - connection.point.position).normalized;
if (tanDir == Vector3.zero) tanDir = -(connection.point.tangent2 - connection.point.position).normalized;
float tan1Length = (connections[i].point.tangent - connections[i].point.position).magnitude;
float tan2Length = (connections[i].point.tangent2 - connections[i].point.position).magnitude;
connections[i].point = connection.point;
connections[i].point.tangent = connections[i].point.position + tanDir * tan1Length;
connections[i].point.tangent2 = connections[i].point.position - tanDir * tan2Length;
}
}
else
{
for (int i = 0; i < connections.Length; i++)
{
if (i == connectionIndex) continue;
connections[i].point = connection.point;
}
}
}
}
void OnDestroy()
{
ClearConnections();
}
public void ClearConnections()
{
for (int i = connections.Length-1; i >= 0; i--)
{
if (connections[i].spline != null) connections[i].spline.DisconnectNode(connections[i].pointIndex);
}
connections = new Connection[0];
}
public void UpdateConnectedComputers(SplineComputer excludeComputer = null)
{
for (int i = connections.Length - 1; i >= 0; i--)
{
if (!connections[i].isValid)
{
RemoveConnection(i);
continue;
}
if (connections[i].spline == excludeComputer) continue;
if (type == Type.Smooth && i != 0)
{
SetPoint(i, GetPoint(0, false), false);
}
SplinePoint point = GetPoint(i, true);
if (!transformNormals)
{
point.normal = connections[i].spline.GetPointNormal(connections[i].pointIndex);
}
if (!transformTangents)
{
point.tangent = connections[i].spline.GetPointTangent(connections[i].pointIndex);
point.tangent2 = connections[i].spline.GetPointTangent2(connections[i].pointIndex);
}
if (!transformSize)
{
point.size = connections[i].spline.GetPointSize(connections[i].pointIndex);
}
connections[i].spline.SetPoint(connections[i].pointIndex, point);
}
}
public void UpdatePoint(SplineComputer computer, int pointIndex, SplinePoint point, bool updatePosition = true)
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
transform.position = point.position;
}
else
{
_trs.position = point.position;
}
#else
_trs.position = point.position;
#endif
for (int i = 0; i < connections.Length; i++)
{
if (connections[i].spline == computer && connections[i].pointIndex == pointIndex)
{
SetPoint(i, point, true);
}
}
}
public void UpdatePoints()
{
for (int i = connections.Length - 1; i >= 0; i--)
{
if (!connections[i].isValid)
{
RemoveConnection(i);
continue;
}
SplinePoint point = connections[i].spline.GetPoint(connections[i].pointIndex);
point.SetPosition(transform.position);
SetPoint(i, point, true);
}
}
#if UNITY_EDITOR
//Use this to maintain the connections between computers in the editor
public void EditorMaintainConnections()
{
RemoveInvalidConnections();
}
#endif
//Remove invalid connections
protected void RemoveInvalidConnections()
{
for (int i = connections.Length - 1; i >= 0; i--)
{
if (connections[i] == null || !connections[i].isValid) RemoveConnection(i);
}
}
public virtual void AddConnection(SplineComputer computer, int pointIndex)
{
RemoveInvalidConnections();
Node connected = computer.GetNode(pointIndex);
if (connected != null)
{
Debug.LogError(computer.name + " is already connected to node " + connected.name + " at point " + pointIndex);
return;
}
SplinePoint point = computer.GetPoint(pointIndex);
point.SetPosition(transform.position);
ArrayUtility.Add(ref connections, new Connection(computer, pointIndex, PointToLocal(point)));
if(connections.Length == 1) SetPoint(connections.Length - 1, point, true);
UpdateConnectedComputers();
}
protected SplinePoint PointToLocal(SplinePoint worldPoint)
{
worldPoint.position = Vector3.zero;
worldPoint.tangent = transform.InverseTransformPoint(worldPoint.tangent);
worldPoint.tangent2 = transform.InverseTransformPoint(worldPoint.tangent2);
worldPoint.normal = transform.InverseTransformDirection(worldPoint.normal);
worldPoint.size /= (transform.localScale.x + transform.localScale.y + transform.localScale.z)/ 3f;
return worldPoint;
}
protected SplinePoint PointToWorld(SplinePoint localPoint)
{
localPoint.position = transform.position;
localPoint.tangent = transform.TransformPoint(localPoint.tangent);
localPoint.tangent2 = transform.TransformPoint(localPoint.tangent2);
localPoint.normal = transform.TransformDirection(localPoint.normal);
localPoint.size *= (transform.localScale.x + transform.localScale.y + transform.localScale.z) / 3f;
return localPoint;
}
public virtual void RemoveConnection(SplineComputer computer, int pointIndex)
{
int index = -1;
for (int i = 0; i < connections.Length; i++)
{
if (connections[i].pointIndex == pointIndex && connections[i].spline == computer)
{
index = i;
break;
}
}
if (index < 0) return;
RemoveConnection(index);
}
private void RemoveConnection(int index)
{
Connection[] newConnections = new Connection[connections.Length - 1];
SplineComputer spline = connections[index].spline;
int pointIndex = connections[index].pointIndex;
for (int i = 0; i < connections.Length; i++)
{
if (i < index) newConnections[i] = connections[i];
else if (i == index) continue;
else newConnections[i - 1] = connections[i];
}
connections = newConnections;
}
public virtual bool HasConnection(SplineComputer computer, int pointIndex)
{
for (int i = connections.Length - 1; i >= 0; i--)
{
if (!connections[i].isValid)
{
RemoveConnection(i);
continue;
}
if (connections[i].spline == computer && connections[i].pointIndex == pointIndex) return true;
}
return false;
}
public Connection[] GetConnections()
{
return connections;
}
}
}