HeavenStudio/Assets/Plugins/BezierSolution/Utilities/BezierLineRenderer.cs

206 lines
5.2 KiB
C#

using UnityEngine;
namespace BezierSolution
{
[AddComponentMenu( "Bezier Solution/Bezier Line Renderer" )]
[HelpURL( "https://github.com/yasirkula/UnityBezierSolution" )]
[RequireComponent( typeof( LineRenderer ) )]
[ExecuteInEditMode]
public class BezierLineRenderer : MonoBehaviour
{
#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]
[MinMaxRange( 0f, 1f )]
private Vector2 m_splineSampleRange = new Vector2( 0f, 1f );
public Vector2 SplineSampleRange
{
get { return m_splineSampleRange; }
set
{
value.x = Mathf.Clamp01( value.x );
value.y = Mathf.Clamp01( value.y );
if( m_splineSampleRange != value )
{
m_splineSampleRange = value;
if( isActiveAndEnabled )
OnSplineChanged( m_spline, DirtyFlags.All );
}
}
}
[Header( "Line Options" )]
[SerializeField]
[Range( 0, 30 )]
private int m_smoothness = 5;
public int smoothness
{
get { return m_smoothness; }
set
{
if( m_smoothness != value )
{
m_smoothness = value;
if( isActiveAndEnabled )
OnSplineChanged( m_spline, DirtyFlags.All );
}
}
}
#if UNITY_EDITOR
[Header( "Other Settings" )]
[SerializeField]
private bool executeInEditMode = false;
[SerializeField, HideInInspector]
private BezierSpline prevSpline;
#endif
#pragma warning restore 0649
private LineRenderer lineRenderer;
private Vector3[] lineRendererPoints;
#if UNITY_EDITOR
private bool lineRendererUseWorldSpace = true;
#endif
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 Update()
{
if( lineRenderer && lineRenderer.useWorldSpace != lineRendererUseWorldSpace )
{
lineRendererUseWorldSpace = !lineRendererUseWorldSpace;
if( isActiveAndEnabled )
OnSplineChanged( m_spline, DirtyFlags.All );
}
}
private void OnValidate()
{
BezierSpline _spline = m_spline;
m_spline = prevSpline;
spline = prevSpline = _spline;
if( isActiveAndEnabled )
OnSplineChanged( m_spline, DirtyFlags.All );
}
#endif
private void OnSplineChanged( BezierSpline spline, DirtyFlags dirtyFlags )
{
#if UNITY_EDITOR
if( !executeInEditMode && !UnityEditor.EditorApplication.isPlaying )
return;
#endif
if( ( dirtyFlags & DirtyFlags.SplineShapeChanged ) == DirtyFlags.SplineShapeChanged )
Refresh( m_smoothness );
}
public void Refresh( int smoothness )
{
if( !m_spline || m_spline.Count < 2 )
return;
if( !lineRenderer )
lineRenderer = GetComponent<LineRenderer>();
smoothness = Mathf.Clamp( smoothness, 1, 30 );
int numberOfPoints = ( m_spline.Count - 1 ) * smoothness;
if( !m_spline.loop )
numberOfPoints++; // spline.GetPoint( 1f )
else
numberOfPoints += smoothness; // Final point is connected to the first point via lineRenderer.loop, so no "numberOfPoints++" here
if( lineRendererPoints == null || lineRendererPoints.Length != numberOfPoints )
lineRendererPoints = new Vector3[numberOfPoints];
if( m_splineSampleRange.x <= 0f && m_splineSampleRange.y >= 1f )
{
int pointIndex = 0;
float smoothnessStep = 1f / smoothness;
for( int i = 0; i < m_spline.Count - 1; i++ )
{
BezierSpline.Segment segment = new BezierSpline.Segment( m_spline[i], m_spline[i + 1], 0f );
for( int j = 0; j < smoothness; j++, pointIndex++ )
lineRendererPoints[pointIndex] = segment.GetPoint( j * smoothnessStep );
}
if( !m_spline.loop )
lineRendererPoints[numberOfPoints - 1] = m_spline.GetPoint( 1f );
else
{
BezierSpline.Segment segment = new BezierSpline.Segment( m_spline[m_spline.Count - 1], m_spline[0], 0f );
for( int j = 0; j < smoothness; j++, pointIndex++ )
lineRendererPoints[pointIndex] = segment.GetPoint( j * smoothnessStep );
}
}
else
{
float smoothnessStep = ( m_splineSampleRange.y - m_splineSampleRange.x ) / ( numberOfPoints - 1 );
for( int i = 0; i < numberOfPoints; i++ )
lineRendererPoints[i] = spline.GetPoint( m_splineSampleRange.x + i * smoothnessStep );
}
#if UNITY_EDITOR
lineRendererUseWorldSpace = lineRenderer.useWorldSpace;
#endif
if( !lineRenderer.useWorldSpace )
{
Vector3 initialPoint = m_spline.GetPoint( 0f );
for( int i = 0; i < numberOfPoints; i++ )
lineRendererPoints[i] -= initialPoint;
}
lineRenderer.positionCount = lineRendererPoints.Length;
lineRenderer.SetPositions( lineRendererPoints );
lineRenderer.loop = m_spline.loop && m_splineSampleRange.x <= 0f && m_splineSampleRange.y >= 1f;
}
}
}