using System; using UnityEngine; #if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER using UnityEngine.InputSystem; #endif namespace MoreMountains.Tools { [Serializable] public class MMAim { /// the list of possible control modes . public enum AimControls { Off, PrimaryMovement, SecondaryMovement, Mouse, Script } /// the list of possible rotation modes public enum RotationModes { Free, Strict4Directions, Strict8Directions } [Header("Control Mode")] [MMInformation("Pick a control mode : mouse (aims towards the pointer), primary movement (you'll aim towards the current input direction), or secondary movement (aims " + "towards a second input axis, think twin stick shooters), and set minimum and maximum angles.", MoreMountains.Tools.MMInformationAttribute.InformationType.Info, false)] /// the aim control mode public AimControls AimControl = AimControls.SecondaryMovement; /// the rotation mode public RotationModes RotationMode = RotationModes.Free; [Header("Limits")] [Range(-180, 180)] /// the minimum angle at which the weapon's rotation will be clamped public float MinimumAngle = -180f; [Range(-180, 180)] /// the maximum angle at which the weapon's rotation will be clamped public float MaximumAngle = 180f; /// the current angle the weapon is aiming at [MMReadOnly] public float CurrentAngle; public Vector3 CurrentPosition { get; set; } public Vector2 PrimaryMovement { get; set; } public Vector2 SecondaryMovement { get; set; } protected float[] _possibleAngleValues; protected Vector3 _currentAim = Vector3.zero; protected Vector3 _direction; protected Vector3 _mousePosition; protected Vector2 _inputSystemMousePosition; protected Camera _mainCamera; /// /// Grabs the weapon component, initializes the angle values /// public virtual void Initialization() { if (RotationMode == RotationModes.Strict4Directions) { _possibleAngleValues = new float[5]; _possibleAngleValues[0] = -180f; _possibleAngleValues[1] = -90f; _possibleAngleValues[2] = 0f; _possibleAngleValues[3] = 90f; _possibleAngleValues[4] = 180f; } if (RotationMode == RotationModes.Strict8Directions) { _possibleAngleValues = new float[9]; _possibleAngleValues[0] = -180f; _possibleAngleValues[1] = -135f; _possibleAngleValues[2] = -90f; _possibleAngleValues[3] = -45f; _possibleAngleValues[4] = 0f; _possibleAngleValues[5] = 45f; _possibleAngleValues[6] = 90f; _possibleAngleValues[7] = 135f; _possibleAngleValues[8] = 180f; } _mainCamera = Camera.main; } /// /// Computes the current aim direction /// public virtual Vector2 GetCurrentAim() { switch (AimControl) { case AimControls.Off: _currentAim = Vector2.zero; break; case AimControls.Script: // in that mode we simply use _currentAim, as set by the SetAim method break; case AimControls.PrimaryMovement: _currentAim = PrimaryMovement; break; case AimControls.SecondaryMovement: _currentAim = SecondaryMovement; break; case AimControls.Mouse: #if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER _mousePosition = Mouse.current.position.ReadValue(); #else _mousePosition = Input.mousePosition; #endif _mousePosition.z = 10; _direction = _mainCamera.ScreenToWorldPoint(_mousePosition); _direction.z = CurrentPosition.z; _currentAim = _direction - CurrentPosition; break; default: _currentAim = Vector2.zero; break; } // we compute our angle in degrees CurrentAngle = Mathf.Atan2(_currentAim.y, _currentAim.x) * Mathf.Rad2Deg; // we clamp our raw angle if needed if ((CurrentAngle < MinimumAngle) || (CurrentAngle > MaximumAngle)) { float minAngleDifference = Mathf.DeltaAngle(CurrentAngle, MinimumAngle); float maxAngleDifference = Mathf.DeltaAngle(CurrentAngle, MaximumAngle); CurrentAngle = (Mathf.Abs(minAngleDifference) < Mathf.Abs(maxAngleDifference)) ? MinimumAngle : MaximumAngle; } // we round to the closest angle if (RotationMode == RotationModes.Strict4Directions || RotationMode == RotationModes.Strict8Directions) { CurrentAngle = MMMaths.RoundToClosest(CurrentAngle, _possibleAngleValues); } // we clamp the final value CurrentAngle = Mathf.Clamp(CurrentAngle, MinimumAngle, MaximumAngle); // we return our aim vector _currentAim = (_currentAim.magnitude == 0f) ? Vector2.zero : MMMaths.RotateVector2(Vector2.right, CurrentAngle); return _currentAim; } /// /// Use this method to set the aim when in AimControl mode : Script /// /// public virtual void SetAim(Vector2 newAim) { _currentAim = newAim; } } }