3DTD/Assets/Scripts/Utilities/EditableArc.cs

109 lines
3.6 KiB
C#
Raw Normal View History

using System;
using UnityEngine;
using UnityEngine.Assertions;
public enum ArcOrientation
{
HORIZONTAL,
VERTICAL,
}
[RequireComponent(typeof(LineRenderer))]
public class EditableArc : MonoBehaviour
{
[SerializeField] private ArcOrientation orientation = ArcOrientation.HORIZONTAL;
[SerializeField, Range(5, 50)] private int samples = 15;
[SerializeField] private float visualRadius = 1f;
[SerializeField] private SliderKnob knob;
[SerializeField] private float knobSensitiviy = 1f;
[SerializeField] private string moveKnobAxisName = "Mouse X";
[SerializeField] private Vector2 rotationMinMax = new Vector2(-30f, 30f);
private LineRenderer lineRenderer;
public Observer<float> Value { get; private set; } = new(0);
public Vector2 RotationMinMax => rotationMinMax;
public Vector3 normal => orientation == ArcOrientation.HORIZONTAL ? transform.up : transform.right;
public Vector3 tangent => orientation == ArcOrientation.HORIZONTAL ? transform.right : transform.up;
private void Awake()
{
lineRenderer = GetComponent<LineRenderer>();
Value.AddListener(UpdateArc);
Value.AddListener(UpdateKnobPosition);
Value.Value = (rotationMinMax.x + rotationMinMax.y) / 2f;
Assert.IsNotNull(knob, $"No knob on {this}");
knob.OnDrag += PointerDraggedOnKnob;
// Initial
UpdateKnobPosition(Value);
}
// Moves the knob to the right position based on the angle on the arc
private void UpdateKnobPosition(float angle)
{
Vector3 dir = Quaternion.AngleAxis(angle, normal) * tangent;
Vector3 knobPos = transform.position + dir;
knob.transform.position = knobPos;
}
private void OnDestroy()
{
Value.RemoveListener(UpdateArc);
Value.RemoveListener(UpdateKnobPosition);
knob.OnDrag -= PointerDraggedOnKnob;
}
private void PointerDraggedOnKnob(SliderKnob knob)
{
// Amount mouse have moved since last frame - ie. mouse velocity
float mouseMovement = Input.GetAxis(moveKnobAxisName);
// TODO: figure out this based on camera orientation
float sign = -1f;
float delta = mouseMovement * knobSensitiviy * sign;
float newAngle = Mathf.Clamp(Value.Value + delta, rotationMinMax.x, rotationMinMax.y);
Value.Value = newAngle;
}
private void Update()
{
UpdateArc(Value.Value);
}
private void UpdateArc(float rotation)
{
float angle = rotationMinMax.y - rotationMinMax.x;
float v = (Mathf.PI - Value * Mathf.Deg2Rad) / 2f;
Vector3 start = Quaternion.AngleAxis(rotationMinMax.x, normal) * tangent;
Vector3 end = Quaternion.AngleAxis(rotationMinMax.y, normal) * tangent;
// Sample LineRenderer points
lineRenderer.positionCount = samples + 1;
Vector3[] positions = new Vector3[samples + 1];
float stepSize = 1f / samples;
float t = 0;
for (int i = 0; i <= samples; i++)
{
positions[i] = SamplePointOnArc(start, end, visualRadius, t);
// Debug.Log($"t: = {t}, pos: {positions[i]}");
t += stepSize;
}
lineRenderer.SetPositions(positions);
}
public Vector3 SamplePointOnArc(Vector3 startPoint, Vector3 endPoint, float radius, float t)
{
float angle = Mathf.LerpAngle(rotationMinMax.x, rotationMinMax.y, t);
Vector3 dir = Quaternion.AngleAxis(angle, normal) * tangent;
return transform.position + dir.normalized * radius;
}
}