259 lines
8.1 KiB
C#
259 lines
8.1 KiB
C#
/// Credit mgear, SimonDarksideJ
|
|
/// Sourced from - https://forum.unity3d.com/threads/radial-slider-circle-slider.326392/#post-3143582
|
|
/// Updated to include lerping features and programatic access to angle/value
|
|
|
|
using System;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.EventSystems;
|
|
|
|
namespace UnityEngine.UI.Extensions
|
|
{
|
|
[AddComponentMenu("UI/Extensions/Radial Slider")]
|
|
[RequireComponent(typeof(Image))]
|
|
public class RadialSlider : MonoBehaviour, IPointerEnterHandler, IPointerDownHandler, IPointerUpHandler, IDragHandler
|
|
{
|
|
private bool isPointerDown, isPointerReleased, lerpInProgress;
|
|
private Vector2 m_localPos, m_screenPos;
|
|
private float m_targetAngle, m_lerpTargetAngle, m_startAngle, m_currentLerpTime, m_lerpTime;
|
|
private Camera m_eventCamera;
|
|
private Image m_image;
|
|
|
|
[SerializeField]
|
|
[Tooltip("Radial Gradient Start Color")]
|
|
private Color m_startColor = Color.green;
|
|
[SerializeField]
|
|
[Tooltip("Radial Gradient End Color")]
|
|
private Color m_endColor = Color.red;
|
|
[Tooltip("Move slider absolute or use Lerping?\nDragging only supported with absolute")]
|
|
[SerializeField]
|
|
private bool m_lerpToTarget;
|
|
[Tooltip("Curve to apply to the Lerp\nMust be set to enable Lerp")]
|
|
[SerializeField]
|
|
private AnimationCurve m_lerpCurve;
|
|
[Tooltip("Event fired when value of control changes, outputs an INT angle value")]
|
|
[SerializeField]
|
|
private RadialSliderValueChangedEvent _onValueChanged = new RadialSliderValueChangedEvent();
|
|
[Tooltip("Event fired when value of control changes, outputs a TEXT angle value")]
|
|
[SerializeField]
|
|
private RadialSliderTextValueChangedEvent _onTextValueChanged = new RadialSliderTextValueChangedEvent();
|
|
|
|
public float Angle
|
|
{
|
|
get { return RadialImage.fillAmount * 360f; }
|
|
set
|
|
{
|
|
if (LerpToTarget)
|
|
{
|
|
StartLerp(value / 360f);
|
|
}
|
|
else
|
|
{
|
|
UpdateRadialImage(value / 360f);
|
|
}
|
|
}
|
|
}
|
|
|
|
public float Value
|
|
{
|
|
get { return RadialImage.fillAmount; }
|
|
set
|
|
{
|
|
if (LerpToTarget)
|
|
{
|
|
StartLerp(value);
|
|
}
|
|
else
|
|
{
|
|
UpdateRadialImage(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public Color EndColor
|
|
{
|
|
get { return m_endColor; }
|
|
set { m_endColor = value; }
|
|
}
|
|
|
|
public Color StartColor
|
|
{
|
|
get { return m_startColor; }
|
|
set { m_startColor = value; }
|
|
}
|
|
|
|
public bool LerpToTarget
|
|
{
|
|
get { return m_lerpToTarget; }
|
|
set { m_lerpToTarget = value; }
|
|
}
|
|
|
|
public AnimationCurve LerpCurve
|
|
{
|
|
get { return m_lerpCurve; }
|
|
set { m_lerpCurve = value; m_lerpTime = LerpCurve[LerpCurve.length - 1].time; }
|
|
}
|
|
|
|
public bool LerpInProgress
|
|
{
|
|
get { return lerpInProgress; }
|
|
}
|
|
|
|
[Serializable]
|
|
public class RadialSliderValueChangedEvent : UnityEvent<int> { }
|
|
[Serializable]
|
|
public class RadialSliderTextValueChangedEvent : UnityEvent<string> { }
|
|
|
|
public Image RadialImage
|
|
{
|
|
get
|
|
{
|
|
if (m_image == null)
|
|
{
|
|
m_image = GetComponent<Image>();
|
|
m_image.type = Image.Type.Filled;
|
|
m_image.fillMethod = Image.FillMethod.Radial360;
|
|
m_image.fillOrigin = 3;
|
|
m_image.fillAmount = 0;
|
|
}
|
|
return m_image;
|
|
}
|
|
}
|
|
|
|
public RadialSliderValueChangedEvent onValueChanged
|
|
{
|
|
get { return _onValueChanged; }
|
|
set { _onValueChanged = value; }
|
|
}
|
|
public RadialSliderTextValueChangedEvent onTextValueChanged
|
|
{
|
|
get { return _onTextValueChanged; }
|
|
set { _onTextValueChanged = value; }
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
if (LerpCurve != null && LerpCurve.length > 0)
|
|
{
|
|
m_lerpTime = LerpCurve[LerpCurve.length - 1].time;
|
|
}
|
|
else
|
|
{
|
|
m_lerpTime = 1;
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (isPointerDown)
|
|
{
|
|
m_targetAngle = GetAngleFromMousePoint();
|
|
if (!lerpInProgress)
|
|
{
|
|
if (!LerpToTarget)
|
|
{
|
|
UpdateRadialImage(m_targetAngle);
|
|
|
|
NotifyValueChanged();
|
|
}
|
|
else
|
|
{
|
|
if (isPointerReleased) StartLerp(m_targetAngle);
|
|
isPointerReleased = false;
|
|
}
|
|
}
|
|
}
|
|
if (lerpInProgress && Value != m_lerpTargetAngle)
|
|
{
|
|
m_currentLerpTime += Time.deltaTime;
|
|
float perc = m_currentLerpTime / m_lerpTime;
|
|
if (LerpCurve != null && LerpCurve.length > 0)
|
|
{
|
|
UpdateRadialImage(Mathf.Lerp(m_startAngle, m_lerpTargetAngle, LerpCurve.Evaluate(perc)));
|
|
}
|
|
else
|
|
{
|
|
UpdateRadialImage(Mathf.Lerp(m_startAngle, m_lerpTargetAngle, perc));
|
|
}
|
|
}
|
|
if (m_currentLerpTime >= m_lerpTime || Value == m_lerpTargetAngle)
|
|
{
|
|
lerpInProgress = false;
|
|
UpdateRadialImage(m_lerpTargetAngle);
|
|
NotifyValueChanged();
|
|
}
|
|
}
|
|
|
|
private void StartLerp(float targetAngle)
|
|
{
|
|
if (!lerpInProgress)
|
|
{
|
|
m_startAngle = Value;
|
|
m_lerpTargetAngle = targetAngle;
|
|
m_currentLerpTime = 0f;
|
|
lerpInProgress = true;
|
|
}
|
|
}
|
|
|
|
private float GetAngleFromMousePoint()
|
|
{
|
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(transform as RectTransform, m_screenPos, m_eventCamera, out m_localPos);
|
|
|
|
// radial pos of the mouse position.
|
|
return (Mathf.Atan2(-m_localPos.y, m_localPos.x) * 180f / Mathf.PI + 180f) / 360f;
|
|
}
|
|
|
|
private void UpdateRadialImage(float targetAngle)
|
|
{
|
|
RadialImage.fillAmount = targetAngle;
|
|
|
|
RadialImage.color = Color.Lerp(m_startColor, m_endColor, targetAngle);
|
|
}
|
|
|
|
private void NotifyValueChanged()
|
|
{
|
|
_onValueChanged.Invoke((int)(m_targetAngle * 360f));
|
|
_onTextValueChanged.Invoke(((int)(m_targetAngle * 360f)).ToString());
|
|
}
|
|
|
|
//#if UNITY_EDITOR
|
|
|
|
// private void OnValidate()
|
|
// {
|
|
// if (LerpToTarget && LerpCurve.length < 2)
|
|
// {
|
|
// LerpToTarget = false;
|
|
// Debug.LogError("You need to define a Lerp Curve to enable 'Lerp To Target'");
|
|
// }
|
|
// }
|
|
//#endif
|
|
|
|
#region Interfaces
|
|
// Called when the pointer enters our GUI component.
|
|
// Start tracking the mouse
|
|
public void OnPointerEnter(PointerEventData eventData)
|
|
{
|
|
m_screenPos = eventData.position;
|
|
m_eventCamera = eventData.enterEventCamera;
|
|
}
|
|
|
|
public void OnPointerDown(PointerEventData eventData)
|
|
{
|
|
m_screenPos = eventData.position;
|
|
m_eventCamera = eventData.enterEventCamera;
|
|
isPointerDown = true;
|
|
}
|
|
|
|
public void OnPointerUp(PointerEventData eventData)
|
|
{
|
|
m_screenPos = Vector2.zero;
|
|
isPointerDown = false;
|
|
isPointerReleased = true;
|
|
}
|
|
|
|
public void OnDrag(PointerEventData eventData)
|
|
{
|
|
m_screenPos = eventData.position;
|
|
}
|
|
#endregion
|
|
}
|
|
} |