DirectionalAnimationSet8.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2022 Kybernetik //
  2. using System;
  3. using UnityEngine;
  4. namespace Animancer
  5. {
  6. /// <summary>A set of up/right/down/left animations with diagonals as well.</summary>
  7. /// <remarks>
  8. /// Documentation: <see href="https://kybernetik.com.au/animancer/docs/manual/playing/directional-sets">Directional Animation Sets</see>
  9. /// </remarks>
  10. /// https://kybernetik.com.au/animancer/api/Animancer/DirectionalAnimationSet8
  11. ///
  12. [CreateAssetMenu(menuName = Strings.MenuPrefix + "Directional Animation Set/8 Directions", order = Strings.AssetMenuOrder + 11)]
  13. [HelpURL(Strings.DocsURLs.APIDocumentation + "/" + nameof(DirectionalAnimationSet8))]
  14. public class DirectionalAnimationSet8 : DirectionalAnimationSet
  15. {
  16. /************************************************************************************************************************/
  17. [SerializeField]
  18. private AnimationClip _UpRight;
  19. /// <summary>[<see cref="SerializeField"/>] The animation facing diagonally up-right ~(0.7, 0.7).</summary>
  20. /// <exception cref="ArgumentException"><see cref="AllowSetClips"/> was not called before setting this value.</exception>
  21. public AnimationClip UpRight
  22. {
  23. get => _UpRight;
  24. set
  25. {
  26. AssertCanSetClips();
  27. _UpRight = value;
  28. AnimancerUtilities.SetDirty(this);
  29. }
  30. }
  31. /************************************************************************************************************************/
  32. [SerializeField]
  33. private AnimationClip _DownRight;
  34. /// <summary>[<see cref="SerializeField"/>] The animation facing diagonally down-right ~(0.7, -0.7).</summary>
  35. /// <exception cref="ArgumentException"><see cref="AllowSetClips"/> was not called before setting this value.</exception>
  36. public AnimationClip DownRight
  37. {
  38. get => _DownRight;
  39. set
  40. {
  41. AssertCanSetClips();
  42. _DownRight = value;
  43. AnimancerUtilities.SetDirty(this);
  44. }
  45. }
  46. /************************************************************************************************************************/
  47. [SerializeField]
  48. private AnimationClip _DownLeft;
  49. /// <summary>[<see cref="SerializeField"/>] The animation facing diagonally down-left ~(-0.7, -0.7).</summary>
  50. /// <exception cref="ArgumentException"><see cref="AllowSetClips"/> was not called before setting this value.</exception>
  51. public AnimationClip DownLeft
  52. {
  53. get => _DownLeft;
  54. set
  55. {
  56. AssertCanSetClips();
  57. _DownLeft = value;
  58. AnimancerUtilities.SetDirty(this);
  59. }
  60. }
  61. /************************************************************************************************************************/
  62. [SerializeField]
  63. private AnimationClip _UpLeft;
  64. /// <summary>[<see cref="SerializeField"/>] The animation facing diagonally up-left ~(-0.7, 0.7).</summary>
  65. /// <exception cref="ArgumentException"><see cref="AllowSetClips"/> was not called before setting this value.</exception>
  66. public AnimationClip UpLeft
  67. {
  68. get => _UpLeft;
  69. set
  70. {
  71. AssertCanSetClips();
  72. _UpLeft = value;
  73. AnimancerUtilities.SetDirty(this);
  74. }
  75. }
  76. /************************************************************************************************************************/
  77. /// <summary>Returns the animation closest to the specified `direction`.</summary>
  78. public override AnimationClip GetClip(Vector2 direction)
  79. {
  80. var angle = Mathf.Atan2(direction.y, direction.x);
  81. var octant = Mathf.RoundToInt(8 * angle / (2 * Mathf.PI) + 8) % 8;
  82. switch (octant)
  83. {
  84. case 0: return Right;
  85. case 1: return _UpRight;
  86. case 2: return Up;
  87. case 3: return _UpLeft;
  88. case 4: return Left;
  89. case 5: return _DownLeft;
  90. case 6: return Down;
  91. case 7: return _DownRight;
  92. default: throw new ArgumentOutOfRangeException("Invalid octant");
  93. }
  94. }
  95. /************************************************************************************************************************/
  96. #region Directions
  97. /************************************************************************************************************************/
  98. /// <summary>Constants for each of the diagonal directions.</summary>
  99. /// <remarks>
  100. /// Documentation: <see href="https://kybernetik.com.au/animancer/docs/manual/playing/directional-sets">Directional Animation Sets</see>
  101. /// </remarks>
  102. /// https://kybernetik.com.au/animancer/api/Animancer/Diagonals
  103. ///
  104. public static class Diagonals
  105. {
  106. /************************************************************************************************************************/
  107. /// <summary>1 / (Square Root of 2).</summary>
  108. public const float OneOverSqrt2 = 0.70710678118f;
  109. /// <summary>A vector with a magnitude of 1 pointing up to the right.</summary>
  110. /// <remarks>The value is approximately (0.7, 0.7).</remarks>
  111. public static Vector2 UpRight => new Vector2(OneOverSqrt2, OneOverSqrt2);
  112. /// <summary>A vector with a magnitude of 1 pointing down to the right.</summary>
  113. /// <remarks>The value is approximately (0.7, -0.7).</remarks>
  114. public static Vector2 DownRight => new Vector2(OneOverSqrt2, -OneOverSqrt2);
  115. /// <summary>A vector with a magnitude of 1 pointing down to the left.</summary>
  116. /// <remarks>The value is approximately (-0.7, -0.7).</remarks>
  117. public static Vector2 DownLeft => new Vector2(-OneOverSqrt2, -OneOverSqrt2);
  118. /// <summary>A vector with a magnitude of 1 pointing up to the left.</summary>
  119. /// <remarks>The value is approximately (-0.707, 0.707).</remarks>
  120. public static Vector2 UpLeft => new Vector2(-OneOverSqrt2, OneOverSqrt2);
  121. /************************************************************************************************************************/
  122. }
  123. /************************************************************************************************************************/
  124. public override int ClipCount => 8;
  125. /************************************************************************************************************************/
  126. /// <summary>Up, Right, Down, Left, or their diagonals.</summary>
  127. /// <remarks>
  128. /// Documentation: <see href="https://kybernetik.com.au/animancer/docs/manual/playing/directional-sets">Directional Animation Sets</see>
  129. /// </remarks>
  130. /// https://kybernetik.com.au/animancer/api/Animancer/Direction
  131. ///
  132. public new enum Direction
  133. {
  134. /// <summary><see cref="Vector2.up"/>.</summary>
  135. Up,
  136. /// <summary><see cref="Vector2.right"/>.</summary>
  137. Right,
  138. /// <summary><see cref="Vector2.down"/>.</summary>
  139. Down,
  140. /// <summary><see cref="Vector2.left"/>.</summary>
  141. Left,
  142. /// <summary><see cref="Vector2"/>(0.7..., 0.7...).</summary>
  143. UpRight,
  144. /// <summary><see cref="Vector2"/>(0.7..., -0.7...).</summary>
  145. DownRight,
  146. /// <summary><see cref="Vector2"/>(-0.7..., -0.7...).</summary>
  147. DownLeft,
  148. /// <summary><see cref="Vector2"/>(-0.7..., 0.7...).</summary>
  149. UpLeft,
  150. }
  151. /************************************************************************************************************************/
  152. protected override string GetDirectionName(int direction) => ((Direction)direction).ToString();
  153. /************************************************************************************************************************/
  154. /// <summary>Returns the animation associated with the specified `direction`.</summary>
  155. public AnimationClip GetClip(Direction direction)
  156. {
  157. switch (direction)
  158. {
  159. case Direction.Up: return Up;
  160. case Direction.Right: return Right;
  161. case Direction.Down: return Down;
  162. case Direction.Left: return Left;
  163. case Direction.UpRight: return _UpRight;
  164. case Direction.DownRight: return _DownRight;
  165. case Direction.DownLeft: return _DownLeft;
  166. case Direction.UpLeft: return _UpLeft;
  167. default: throw AnimancerUtilities.CreateUnsupportedArgumentException(direction);
  168. }
  169. }
  170. public override AnimationClip GetClip(int direction) => GetClip((Direction)direction);
  171. /************************************************************************************************************************/
  172. /// <summary>Sets the animation associated with the specified `direction`.</summary>
  173. public void SetClip(Direction direction, AnimationClip clip)
  174. {
  175. switch (direction)
  176. {
  177. case Direction.Up: Up = clip; break;
  178. case Direction.Right: Right = clip; break;
  179. case Direction.Down: Down = clip; break;
  180. case Direction.Left: Left = clip; break;
  181. case Direction.UpRight: UpRight = clip; break;
  182. case Direction.DownRight: DownRight = clip; break;
  183. case Direction.DownLeft: DownLeft = clip; break;
  184. case Direction.UpLeft: UpLeft = clip; break;
  185. default: throw AnimancerUtilities.CreateUnsupportedArgumentException(direction);
  186. }
  187. }
  188. public override void SetClip(int direction, AnimationClip clip) => SetClip((Direction)direction, clip);
  189. /************************************************************************************************************************/
  190. /// <summary>Returns a vector representing the specified `direction`.</summary>
  191. public static Vector2 DirectionToVector(Direction direction)
  192. {
  193. switch (direction)
  194. {
  195. case Direction.Up: return Vector2.up;
  196. case Direction.Right: return Vector2.right;
  197. case Direction.Down: return Vector2.down;
  198. case Direction.Left: return Vector2.left;
  199. case Direction.UpRight: return Diagonals.UpRight;
  200. case Direction.DownRight: return Diagonals.DownRight;
  201. case Direction.DownLeft: return Diagonals.DownLeft;
  202. case Direction.UpLeft: return Diagonals.UpLeft;
  203. default: throw AnimancerUtilities.CreateUnsupportedArgumentException(direction);
  204. }
  205. }
  206. public override Vector2 GetDirection(int direction) => DirectionToVector((Direction)direction);
  207. /************************************************************************************************************************/
  208. /// <summary>Returns the direction closest to the specified `vector`.</summary>
  209. public new static Direction VectorToDirection(Vector2 vector)
  210. {
  211. var angle = Mathf.Atan2(vector.y, vector.x);
  212. var octant = Mathf.RoundToInt(8 * angle / (2 * Mathf.PI) + 8) % 8;
  213. switch (octant)
  214. {
  215. case 0: return Direction.Right;
  216. case 1: return Direction.UpRight;
  217. case 2: return Direction.Up;
  218. case 3: return Direction.UpLeft;
  219. case 4: return Direction.Left;
  220. case 5: return Direction.DownLeft;
  221. case 6: return Direction.Down;
  222. case 7: return Direction.DownRight;
  223. default: throw new ArgumentOutOfRangeException("Invalid octant");
  224. }
  225. }
  226. /************************************************************************************************************************/
  227. /// <summary>Returns a copy of the `vector` pointing in the closest direction this set type has an animation for.</summary>
  228. public new static Vector2 SnapVectorToDirection(Vector2 vector)
  229. {
  230. var magnitude = vector.magnitude;
  231. var direction = VectorToDirection(vector);
  232. vector = DirectionToVector(direction) * magnitude;
  233. return vector;
  234. }
  235. public override Vector2 Snap(Vector2 vector) => SnapVectorToDirection(vector);
  236. /************************************************************************************************************************/
  237. #endregion
  238. /************************************************************************************************************************/
  239. #region Name Based Operations
  240. /************************************************************************************************************************/
  241. #if UNITY_EDITOR
  242. /************************************************************************************************************************/
  243. public override int SetClipByName(AnimationClip clip)
  244. {
  245. var name = clip.name;
  246. var directionCount = ClipCount;
  247. for (int i = directionCount - 1; i >= 0; i--)
  248. {
  249. if (name.Contains(GetDirectionName(i)))
  250. {
  251. SetClip(i, clip);
  252. return i;
  253. }
  254. }
  255. return -1;
  256. }
  257. /************************************************************************************************************************/
  258. #endif
  259. /************************************************************************************************************************/
  260. #endregion
  261. /************************************************************************************************************************/
  262. }
  263. }