231 lines
5.2 KiB
C#
231 lines
5.2 KiB
C#
using UnityEngine;
|
|
|
|
namespace BezierSolution
|
|
{
|
|
[AddComponentMenu( "Bezier Solution/Bezier Attachment" )]
|
|
[HelpURL( "https://github.com/yasirkula/UnityBezierSolution" )]
|
|
[ExecuteInEditMode]
|
|
public class BezierAttachment : MonoBehaviour
|
|
{
|
|
public enum RotationMode { No = 0, UseSplineNormals = 1, UseEndPointRotations = 2 };
|
|
|
|
#pragma warning disable 0649
|
|
[SerializeField]
|
|
private BezierSpline m_spline;
|
|
public BezierSpline spline
|
|
{
|
|
get { return m_spline; }
|
|
set
|
|
{
|
|
if( m_spline != value )
|
|
{
|
|
if( m_spline )
|
|
m_spline.onSplineChanged -= OnSplineChanged;
|
|
|
|
m_spline = value;
|
|
|
|
if( m_spline && isActiveAndEnabled )
|
|
{
|
|
m_spline.onSplineChanged -= OnSplineChanged;
|
|
m_spline.onSplineChanged += OnSplineChanged;
|
|
|
|
OnSplineChanged( m_spline, DirtyFlags.All );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
[Range( 0f, 1f )]
|
|
private float m_normalizedT = 0f;
|
|
public float normalizedT
|
|
{
|
|
get { return m_normalizedT; }
|
|
set
|
|
{
|
|
value = Mathf.Clamp01( value );
|
|
|
|
if( m_normalizedT != value )
|
|
{
|
|
m_normalizedT = value;
|
|
|
|
if( isActiveAndEnabled )
|
|
OnSplineChanged( m_spline, DirtyFlags.All );
|
|
}
|
|
}
|
|
}
|
|
|
|
[Header( "Position" )]
|
|
[SerializeField]
|
|
private bool m_updatePosition = true;
|
|
public bool updatePosition
|
|
{
|
|
get { return m_updatePosition; }
|
|
set
|
|
{
|
|
if( m_updatePosition != value )
|
|
{
|
|
m_updatePosition = value;
|
|
|
|
if( m_updatePosition && isActiveAndEnabled )
|
|
OnSplineChanged( m_spline, DirtyFlags.SplineShapeChanged );
|
|
}
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private Vector3 m_positionOffset;
|
|
public Vector3 positionOffset
|
|
{
|
|
get { return m_positionOffset; }
|
|
set
|
|
{
|
|
if( m_positionOffset != value )
|
|
{
|
|
m_positionOffset = value;
|
|
|
|
if( m_updatePosition && isActiveAndEnabled )
|
|
OnSplineChanged( m_spline, DirtyFlags.SplineShapeChanged );
|
|
}
|
|
}
|
|
}
|
|
|
|
[Header( "Rotation" )]
|
|
[SerializeField]
|
|
private RotationMode m_updateRotation = RotationMode.UseSplineNormals;
|
|
public RotationMode updateRotation
|
|
{
|
|
get { return m_updateRotation; }
|
|
set
|
|
{
|
|
if( m_updateRotation != value )
|
|
{
|
|
m_updateRotation = value;
|
|
|
|
if( m_updateRotation != RotationMode.No && isActiveAndEnabled )
|
|
OnSplineChanged( m_spline, DirtyFlags.SplineShapeChanged );
|
|
}
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private Vector3 m_rotationOffset;
|
|
public Vector3 rotationOffset
|
|
{
|
|
get { return m_rotationOffset; }
|
|
set
|
|
{
|
|
if( m_rotationOffset != value )
|
|
{
|
|
m_rotationOffset = value;
|
|
|
|
if( m_updateRotation != RotationMode.No && isActiveAndEnabled )
|
|
OnSplineChanged( m_spline, DirtyFlags.SplineShapeChanged );
|
|
}
|
|
}
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
[Header( "Other Settings" )]
|
|
[SerializeField]
|
|
private bool executeInEditMode = false;
|
|
|
|
[SerializeField, HideInInspector]
|
|
private BezierSpline prevSpline;
|
|
#endif
|
|
#pragma warning restore 0649
|
|
|
|
private void OnEnable()
|
|
{
|
|
if( m_spline )
|
|
{
|
|
m_spline.onSplineChanged -= OnSplineChanged;
|
|
m_spline.onSplineChanged += OnSplineChanged;
|
|
|
|
OnSplineChanged( m_spline, DirtyFlags.All );
|
|
}
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
if( m_spline )
|
|
m_spline.onSplineChanged -= OnSplineChanged;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
private void OnValidate()
|
|
{
|
|
UnityEditor.Undo.RecordObject( transform, "Modify BezierAttachment" );
|
|
|
|
BezierSpline _spline = m_spline;
|
|
m_spline = prevSpline;
|
|
spline = prevSpline = _spline;
|
|
|
|
if( isActiveAndEnabled )
|
|
OnSplineChanged( m_spline, DirtyFlags.All );
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if( transform.hasChanged )
|
|
OnSplineChanged( m_spline, DirtyFlags.All );
|
|
}
|
|
#endif
|
|
|
|
private void OnSplineChanged( BezierSpline spline, DirtyFlags dirtyFlags )
|
|
{
|
|
#if UNITY_EDITOR
|
|
if( !executeInEditMode && !UnityEditor.EditorApplication.isPlaying )
|
|
return;
|
|
#endif
|
|
|
|
RefreshInternal( dirtyFlags );
|
|
}
|
|
|
|
public void Refresh()
|
|
{
|
|
RefreshInternal( DirtyFlags.All );
|
|
}
|
|
|
|
private void RefreshInternal( DirtyFlags dirtyFlags )
|
|
{
|
|
if( !m_spline || m_spline.Count < 2 )
|
|
return;
|
|
|
|
if( !m_updatePosition && m_updateRotation == RotationMode.No )
|
|
return;
|
|
|
|
BezierSpline.Segment segment = m_spline.GetSegmentAt( m_normalizedT );
|
|
|
|
switch( m_updateRotation )
|
|
{
|
|
case RotationMode.UseSplineNormals:
|
|
if( m_rotationOffset == Vector3.zero )
|
|
transform.rotation = Quaternion.LookRotation( segment.GetTangent(), segment.GetNormal() );
|
|
else
|
|
transform.rotation = Quaternion.LookRotation( segment.GetTangent(), segment.GetNormal() ) * Quaternion.Euler( m_rotationOffset );
|
|
|
|
break;
|
|
case RotationMode.UseEndPointRotations:
|
|
if( m_rotationOffset == Vector3.zero )
|
|
transform.rotation = Quaternion.LerpUnclamped( segment.point1.rotation, segment.point2.rotation, segment.localT );
|
|
else
|
|
transform.rotation = Quaternion.LerpUnclamped( segment.point1.rotation, segment.point2.rotation, segment.localT ) * Quaternion.Euler( m_rotationOffset );
|
|
|
|
break;
|
|
}
|
|
|
|
if( m_updatePosition && ( dirtyFlags & DirtyFlags.SplineShapeChanged ) == DirtyFlags.SplineShapeChanged )
|
|
{
|
|
if( m_positionOffset == Vector3.zero )
|
|
transform.position = segment.GetPoint();
|
|
else
|
|
transform.position = segment.GetPoint() + transform.rotation * m_positionOffset;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
transform.hasChanged = false;
|
|
#endif
|
|
}
|
|
}
|
|
} |