Homebound / Scripts / InteractionsAndObstacles / Oscillator.cs
Oscillator.cs
Raw
using UnityEditor;
using UnityEngine;

/// <summary>
/// Movement in a wave or circular motion using Trig functionalities 
/// </summary>
[System.Serializable]
public class Oscillator : MonoBehaviour
{
    public enum OscillatorType
    {
        Normal,                 // Normal wave motion going from the origin position to the position indicated by the Movement Vector
        Wave,                   // Wave motion that takes the origin position and splits the Movement Vector to oscillate at half the distance in both directions
        Circle,                 // Circular motion that uses the special Circle Values to spin around the point of origin
        TreePivot               // Special oscillator for trees that bends the trunks in the direction of the Movement Vector
    }

    const float Tau = Mathf.PI * 2;

    [SerializeField] OscillatorType oscillatorType = OscillatorType.Normal;     // Reference to which type of Oscillator this object is, initialized to normal wave functionality

    [Header("Normal and Wave Values")]
    [SerializeField] Vector3 movementVector;                // The vectors at which to move
    [SerializeField] float period = 2f;                     // The rate at which the sine wave will oscillate 
    float movementRange;                                    // The range at which the values in the movement vector will reach before cycling back

    [Header("Circle Values")]
    [SerializeField][Tooltip("Used for the gizmo and the path rotation by transforming the vector forward direction")] 
    Vector3 vectorRotation;              // The vector value for the forward vector for the gizmo
    [SerializeField] Vector3 origin;     // Reference to the origin of the circle
    [SerializeField] float speed;        // The rate at which the circle will revolve around the origin
    [SerializeField] float radius;       // The half diameter of the circle path
    float angle;                         // Reference for the angleParam of the 0 degree arc path and the current arc path degree

    Vector3 startingPos;                 // Starting Position of the object attached to this script
    Vector3 startingRot;                 // Starting rotation of the object attached to this scripts

    void Start()
    {
        if (oscillatorType == OscillatorType.TreePivot)
            startingRot = new Vector3(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y, transform.rotation.eulerAngles.z);

        startingPos = transform.position; // Initialize the starting position 
    }

    void Update()
    {
        // When the game is not paused will move in the indicated functionality based on the Enum parameter set
        if (!MainMenu.IsPaused)
            if (oscillatorType == OscillatorType.Circle)
                CircleMovement();
            else if (oscillatorType == OscillatorType.TreePivot)
                RotateAroundPivot();
            else
                Oscillate();
    }

    /// <summary>
    /// Circular movement set by a radius and origin in the inspector
    /// </summary>
    void CircleMovement()
    {
        angle += Time.deltaTime * speed;
        Vector3 direction = Quaternion.AngleAxis(angle, vectorRotation) * new Vector3(1f, 0f, 1f);
        transform.position = origin + direction * radius;
    }

    /// <summary>
    /// Rotates the object around a pivot point set in the inspector
    /// </summary>
    void RotateAroundPivot()
    {
        float cycles = Time.time / Mathf.Clamp(Mathf.Abs(period), Mathf.Epsilon, float.MaxValue);

        float rawSinWave = Mathf.Sin(cycles * Tau);
        movementRange = (rawSinWave + 1f) / 2f;

        Vector3 offset = movementVector * movementRange;
        transform.rotation = Quaternion.Euler(offset + startingRot);
    }

    /// <summary>
    /// Calculates and produces both the normal and wave motions for the Oscillator by using Sin waves to move the 
    /// object up and down based on the point of origin and Movement Vector
    /// </summary>
    void Oscillate()
    {
        float cycles = Time.time / Mathf.Clamp(Mathf.Abs(period), Mathf.Epsilon, float.MaxValue);

        float rawSinWave = Mathf.Sin(cycles * Tau);

        if (oscillatorType == OscillatorType.Normal)        // Normal
            movementRange = (rawSinWave + 1f) / 2f;
        else                                                // Wave
            movementRange = rawSinWave / 2f;

        Vector3 offset = movementVector * movementRange;
        transform.position = startingPos + offset;
    }

#if UNITY_EDITOR
    // Simple gizmo primarily for the circle oscillation type
    void OnDrawGizmosSelected()
    {
        if (oscillatorType == OscillatorType.Circle)
        {
            Gizmos.color = Color.cyan;

            Handles.DrawWireDisc(origin, vectorRotation, radius);
        }
    }
#endif
}