// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik // using System; using UnityEngine; namespace Animancer { /// A set of up/right/down/left animations with diagonals as well. /// /// Documentation: /// /// Directional Animation Sets /// /// https://kybernetik.com.au/animancer/api/Animancer/DirectionalAnimationSet8 /// [CreateAssetMenu( menuName = Strings.MenuPrefix + "Directional Animation Set/8 Directions", order = Strings.AssetMenuOrder + 4)] [AnimancerHelpUrl(typeof(DirectionalAnimationSet8))] public class DirectionalAnimationSet8 : DirectionalAnimationSet { /************************************************************************************************************************/ [SerializeField] private AnimationClip _UpRight; /// [] The animation facing diagonally up-right ~(0.7, 0.7). /// was not called before setting this value. public AnimationClip UpRight { get => _UpRight; set { AssertCanSetClips(); _UpRight = value; AnimancerUtilities.SetDirty(this); } } /************************************************************************************************************************/ [SerializeField] private AnimationClip _DownRight; /// [] The animation facing diagonally down-right ~(0.7, -0.7). /// was not called before setting this value. public AnimationClip DownRight { get => _DownRight; set { AssertCanSetClips(); _DownRight = value; AnimancerUtilities.SetDirty(this); } } /************************************************************************************************************************/ [SerializeField] private AnimationClip _DownLeft; /// [] The animation facing diagonally down-left ~(-0.7, -0.7). /// was not called before setting this value. public AnimationClip DownLeft { get => _DownLeft; set { AssertCanSetClips(); _DownLeft = value; AnimancerUtilities.SetDirty(this); } } /************************************************************************************************************************/ [SerializeField] private AnimationClip _UpLeft; /// [] The animation facing diagonally up-left ~(-0.7, 0.7). /// was not called before setting this value. public AnimationClip UpLeft { get => _UpLeft; set { AssertCanSetClips(); _UpLeft = value; AnimancerUtilities.SetDirty(this); } } /************************************************************************************************************************/ /// Returns the animation closest to the specified `direction`. public override AnimationClip GetClip(Vector2 direction) { var angle = Mathf.Atan2(direction.y, direction.x); var octant = Mathf.RoundToInt(8 * angle / (2 * Mathf.PI) + 8) % 8; return octant switch { 0 => Right, 1 => _UpRight, 2 => Up, 3 => _UpLeft, 4 => Left, 5 => _DownLeft, 6 => Down, 7 => _DownRight, _ => throw new ArgumentOutOfRangeException("Invalid octant"), }; } /************************************************************************************************************************/ #region Directions /************************************************************************************************************************/ /// Constants for each of the diagonal directions. /// /// Documentation: /// /// Directional Animation Sets /// /// https://kybernetik.com.au/animancer/api/Animancer/Diagonals /// public static class Diagonals { /************************************************************************************************************************/ /// 1 / (Square Root of 2). public const float OneOverSqrt2 = 0.70710678118f; /// A vector with a magnitude of 1 pointing up to the right. /// The value is approximately (0.7, 0.7). public static Vector2 UpRight => new(OneOverSqrt2, OneOverSqrt2); /// A vector with a magnitude of 1 pointing down to the right. /// The value is approximately (0.7, -0.7). public static Vector2 DownRight => new(OneOverSqrt2, -OneOverSqrt2); /// A vector with a magnitude of 1 pointing down to the left. /// The value is approximately (-0.7, -0.7). public static Vector2 DownLeft => new(-OneOverSqrt2, -OneOverSqrt2); /// A vector with a magnitude of 1 pointing up to the left. /// The value is approximately (-0.707, 0.707). public static Vector2 UpLeft => new(-OneOverSqrt2, OneOverSqrt2); /************************************************************************************************************************/ } /************************************************************************************************************************/ /// public override int ClipCount => 8; /************************************************************************************************************************/ /// Up, Right, Down, Left, or their diagonals. /// /// Documentation: /// /// Directional Animation Sets /// /// https://kybernetik.com.au/animancer/api/Animancer/Direction /// public new enum Direction { /// . Up, /// . Right, /// . Down, /// . Left, /// (0.7..., 0.7...). UpRight, /// (0.7..., -0.7...). DownRight, /// (-0.7..., -0.7...). DownLeft, /// (-0.7..., 0.7...). UpLeft, } /************************************************************************************************************************/ protected override string GetDirectionName(int direction) => ((Direction)direction).ToString(); /************************************************************************************************************************/ /// Returns the animation associated with the specified `direction`. public AnimationClip GetClip(Direction direction) => direction switch { Direction.Up => Up, Direction.Right => Right, Direction.Down => Down, Direction.Left => Left, Direction.UpRight => _UpRight, Direction.DownRight => _DownRight, Direction.DownLeft => _DownLeft, Direction.UpLeft => _UpLeft, _ => throw AnimancerUtilities.CreateUnsupportedArgumentException(direction), }; public override AnimationClip GetClip(int direction) => GetClip((Direction)direction); /************************************************************************************************************************/ /// Sets the animation associated with the specified `direction`. public void SetClip(Direction direction, AnimationClip clip) { switch (direction) { case Direction.Up: Up = clip; break; case Direction.Right: Right = clip; break; case Direction.Down: Down = clip; break; case Direction.Left: Left = clip; break; case Direction.UpRight: UpRight = clip; break; case Direction.DownRight: DownRight = clip; break; case Direction.DownLeft: DownLeft = clip; break; case Direction.UpLeft: UpLeft = clip; break; default: throw AnimancerUtilities.CreateUnsupportedArgumentException(direction); } } public override void SetClip(int direction, AnimationClip clip) => SetClip((Direction)direction, clip); /************************************************************************************************************************/ /// Returns a vector representing the specified `direction`. public static Vector2 DirectionToVector(Direction direction) => direction switch { Direction.Up => Vector2.up, Direction.Right => Vector2.right, Direction.Down => Vector2.down, Direction.Left => Vector2.left, Direction.UpRight => Diagonals.UpRight, Direction.DownRight => Diagonals.DownRight, Direction.DownLeft => Diagonals.DownLeft, Direction.UpLeft => Diagonals.UpLeft, _ => throw AnimancerUtilities.CreateUnsupportedArgumentException(direction), }; public override Vector2 GetDirection(int direction) => DirectionToVector((Direction)direction); /************************************************************************************************************************/ /// Returns the direction closest to the specified `vector`. public new static Direction VectorToDirection(Vector2 vector) { var angle = Mathf.Atan2(vector.y, vector.x); var octant = Mathf.RoundToInt(8 * angle / (2 * Mathf.PI) + 8) % 8; return octant switch { 0 => Direction.Right, 1 => Direction.UpRight, 2 => Direction.Up, 3 => Direction.UpLeft, 4 => Direction.Left, 5 => Direction.DownLeft, 6 => Direction.Down, 7 => Direction.DownRight, _ => throw new ArgumentOutOfRangeException("Invalid octant"), }; } /************************************************************************************************************************/ /// /// Returns a copy of the `vector` pointing in the closest direction /// which this set type has an animation for. /// public new static Vector2 SnapVectorToDirection(Vector2 vector) { var magnitude = vector.magnitude; var direction = VectorToDirection(vector); vector = DirectionToVector(direction) * magnitude; return vector; } public override Vector2 Snap(Vector2 vector) => SnapVectorToDirection(vector); /************************************************************************************************************************/ /// public override int SetClipByName(AnimationClip clip) { var name = clip.name; var directionCount = ClipCount; for (int i = directionCount - 1; i >= 0; i--) { if (name.Contains(GetDirectionName(i))) { SetClip(i, clip); return i; } } return -1; } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ } }