using System; using System.Collections; using System.Collections.Generic; using UnityEngine; namespace MoreMountains.Tools { /// /// Use this script to have a Transform automatically face a certain direction, whether its own movement direction, or a specific target Transform /// public class MMFaceDirection : MonoBehaviour { /// the possible Updates this script should run at public enum UpdateModes { Update, LateUpdate, FixedUpdate } /// the vector to point towards the direction public enum ForwardVectors { Forward, Up, Right } /// whether to point at this transform's movement direction, or at a target public enum FacingModes { MovementDirection, Target } [Header("Facing Mode")] /// whether to point at this transform's movement direction, or at a target public FacingModes FacingMode = FacingModes.MovementDirection; /// the target to face [MMEnumCondition("FacingMode", (int) FacingModes.Target)] public Transform FacingTarget; /// the minimum distance to consider when computing the movement direction [MMEnumCondition("FacingMode", (int) FacingModes.MovementDirection)] public float MinimumMovementThreshold = 0.2f; [Header("Directions")] /// the vector to point towards the direction public ForwardVectors ForwardVector = ForwardVectors.Forward; /// the angles by which to rotate the direction (in degrees) public Vector3 DirectionRotationAngles = Vector3.zero; [Header("Timing")] /// the possible Updates this script should run at public UpdateModes UpdateMode = UpdateModes.LateUpdate; /// the speed at which to interpolate the rotation public float InterpolationSpeed = 0.15f; protected Vector3 _direction; protected Vector3 _positionLastFrame; protected Transform _transform; protected Vector3 _upwards; /// /// On Awake we initialize our behaviour /// protected void Awake() { Initialization(); } /// /// Caches upwards vector and transform /// protected virtual void Initialization() { _transform = this.transform; _positionLastFrame = _transform.position; switch (ForwardVector) { case ForwardVectors.Forward: _upwards = Vector3.forward; break; case ForwardVectors.Up: _upwards = Vector3.up; break; case ForwardVectors.Right: _upwards = Vector3.right; break; } } /// /// Computes the direction to face /// protected virtual void FaceDirection() { if (FacingMode == FacingModes.Target) { _direction = FacingTarget.position - _transform.position; _direction = Quaternion.Euler(DirectionRotationAngles.x, DirectionRotationAngles.y, DirectionRotationAngles.z) * _direction; ApplyRotation(); } if (FacingMode == FacingModes.MovementDirection) { _direction = (_transform.position - _positionLastFrame).normalized; _direction = Quaternion.Euler(DirectionRotationAngles.x, DirectionRotationAngles.y, DirectionRotationAngles.z) * _direction; if (Vector3.Distance(_transform.position, _positionLastFrame) > MinimumMovementThreshold) { ApplyRotation(); _positionLastFrame = _transform.position; } } } /// /// Rotates the transform /// protected virtual void ApplyRotation() { transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(_upwards, _direction), InterpolationSpeed * Time.time); } /// /// On Update we compute our direction if needed /// protected virtual void Update() { if (UpdateMode == UpdateModes.Update) { FaceDirection(); } } /// /// On LateUpdate we compute our direction if needed /// protected virtual void LateUpdate() { if (UpdateMode == UpdateModes.LateUpdate) { FaceDirection(); } } /// /// On FixedUpdate we compute our direction if needed /// protected virtual void FixedUpdate() { if (UpdateMode == UpdateModes.FixedUpdate) { FaceDirection(); } } } }