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 }