using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; namespace BNG { public enum RotationMechanic { Snap, Smooth } public class PlayerRotation : MonoBehaviour { [Header("Input")] [Tooltip("Set to false to skip Update")] public bool AllowInput = true; [Tooltip("Used to determine whether to turn left / right. This can be an X Axis on the thumbstick, for example. -1 to snap left, 1 to snap right.")] public List inputAxis = new List() { InputAxis.RightThumbStickAxis }; [Tooltip("Unity Input Action used to rotate the player")] public InputActionReference RotateAction; [Header("Smooth / Snap Turning")] [Tooltip("Snap rotation will rotate a fixed amount of degrees on turn. Smooth will linearly rotate the player.")] public RotationMechanic RotationType = RotationMechanic.Snap; [Header("Snap Turn Settings")] [Tooltip("How many degrees to rotate if RotationType is set to 'Snap'")] public float SnapRotationAmount = 45f; [Tooltip("Thumbstick X axis must be >= this amount to be considered an input event")] public float SnapInputAmount = 0.75f; [Header("Smooth Turn Settings")] [Tooltip("How fast to rotate the player if RotationType is set to 'Smooth'")] public float SmoothTurnSpeed = 40f; [Tooltip("Thumbstick X axis must be >= this amount to be considered an input event")] public float SmoothTurnMinInput = 0.1f; float recentSnapTurnTime; /// /// How much to rotate this frame /// float rotationAmount = 0; float xAxis; float previousXInput; #region Events public delegate void OnBeforeRotateAction(); public static event OnBeforeRotateAction OnBeforeRotate; public delegate void OnAfterRotateAction(); public static event OnAfterRotateAction OnAfterRotate; #endregion void Update() { if(!AllowInput) { return; } xAxis = GetAxisInput(); if (RotationType == RotationMechanic.Snap) { DoSnapRotation(xAxis); } else if (RotationType == RotationMechanic.Smooth) { DoSmoothRotation(xAxis); } // Store input for future checks previousXInput = xAxis; } /// /// Return a float between -1 and 1 to determine which direction to turn the character /// /// public virtual float GetAxisInput() { // Use the largest, non-zero value we find in our input list float lastVal = 0; // Check Raw Input if(inputAxis != null) { for (int i = 0; i < inputAxis.Count; i++) { float axisVal = InputBridge.Instance.GetInputAxisValue(inputAxis[i]).x; // Always take this value if our last entry was 0. if (lastVal == 0) { lastVal = axisVal; } else if (axisVal != 0 && axisVal > lastVal) { lastVal = axisVal; } } } // Check Unity Input Action if(RotateAction != null) { float axisVal = RotateAction.action.ReadValue().x; // Always take this value if our last entry was 0. if (lastVal == 0) { lastVal = axisVal; } else if (axisVal != 0 && axisVal > lastVal) { lastVal = axisVal; } } return lastVal; } public virtual void DoSnapRotation(float xInput) { // Reset rotation amount before retrieving inputs rotationAmount = 0; // Snap Right if (xInput >= 0.1f && previousXInput < 0.1f) { rotationAmount += SnapRotationAmount; } // Snap Left else if (xInput <= -0.1f && previousXInput > -0.1f) { rotationAmount -= SnapRotationAmount; } if(Math.Abs(rotationAmount) > 0) { // Call any Before Rotation Events OnBeforeRotate?.Invoke(); // Apply rotation transform.rotation = Quaternion.Euler(new Vector3(transform.eulerAngles.x, transform.eulerAngles.y + rotationAmount, transform.eulerAngles.z)); recentSnapTurnTime = Time.time; // Call any After Rotation Events OnAfterRotate?.Invoke(); } } public virtual bool RecentlySnapTurned() { return Time.time - recentSnapTurnTime <= 0.1f; } public virtual void DoSmoothRotation(float xInput) { // Reset rotation amount before retrieving inputs rotationAmount = 0; // Smooth Rotate Right if (xInput >= SmoothTurnMinInput) { rotationAmount += xInput * SmoothTurnSpeed * Time.deltaTime; } // Smooth Rotate Left else if (xInput <= -SmoothTurnMinInput) { rotationAmount += xInput * SmoothTurnSpeed * Time.deltaTime; } // Apply rotation transform.rotation = Quaternion.Euler(new Vector3(transform.eulerAngles.x, transform.eulerAngles.y + rotationAmount, transform.eulerAngles.z)); } } }