DirectionalCharacter.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2022 Kybernetik //
  2. #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value.
  3. using Animancer.Units;
  4. using UnityEngine;
  5. namespace Animancer.Examples.DirectionalSprites
  6. {
  7. /// <summary>
  8. /// A more complex version of the <see cref="DirectionalBasics"/> which adds running and pushing animations
  9. /// as well as the ability to actually move around.
  10. /// </summary>
  11. /// <example><see href="https://kybernetik.com.au/animancer/docs/examples/directional-sprites/character">Directional Character</see></example>
  12. /// https://kybernetik.com.au/animancer/api/Animancer.Examples.DirectionalSprites/DirectionalCharacter
  13. ///
  14. [AddComponentMenu(Strings.ExamplesMenuPrefix + "Directional Sprites - Directional Character")]
  15. [HelpURL(Strings.DocsURLs.ExampleAPIDocumentation + nameof(DirectionalSprites) + "/" + nameof(DirectionalCharacter))]
  16. public sealed class DirectionalCharacter : MonoBehaviour
  17. {
  18. /************************************************************************************************************************/
  19. [Header("Physics")]
  20. [SerializeField] private CapsuleCollider2D _Collider;
  21. [SerializeField] private Rigidbody2D _Rigidbody;
  22. [SerializeField, MetersPerSecond] private float _WalkSpeed = 1;
  23. [SerializeField, MetersPerSecond] private float _RunSpeed = 2;
  24. [Header("Animations")]
  25. [SerializeField] private AnimancerComponent _Animancer;
  26. [SerializeField] private DirectionalAnimationSet _Idle;
  27. [SerializeField] private DirectionalAnimationSet _Walk;
  28. [SerializeField] private DirectionalAnimationSet _Run;
  29. [SerializeField] private DirectionalAnimationSet _Push;
  30. [SerializeField] private Vector2 _Facing = Vector2.down;
  31. private Vector2 _Movement;
  32. private DirectionalAnimationSet _CurrentAnimationSet;
  33. private TimeSynchronizationGroup _MovementSynchronization;
  34. /************************************************************************************************************************/
  35. private void Awake()
  36. {
  37. _MovementSynchronization = new TimeSynchronizationGroup(_Animancer) { _Walk, _Run, _Push };
  38. }
  39. /************************************************************************************************************************/
  40. private void Update()
  41. {
  42. _Movement = ExampleInput.WASD;
  43. if (_Movement != default)
  44. {
  45. _Facing = _Movement;
  46. UpdateMovementState();
  47. // Snap the movement to the exact directions we have animations for.
  48. // When using DirectionalAnimationSets this means the character will only move up/right/down/left.
  49. // But DirectionalAnimationSet8s will allow diagonal movement as well.
  50. _Movement = _CurrentAnimationSet.Snap(_Movement);
  51. _Movement = Vector2.ClampMagnitude(_Movement, 1);
  52. }
  53. else
  54. {
  55. Play(_Idle);
  56. }
  57. }
  58. /************************************************************************************************************************/
  59. private void Play(DirectionalAnimationSet animations)
  60. {
  61. // Store the current time.
  62. _MovementSynchronization.StoreTime(_CurrentAnimationSet);
  63. _CurrentAnimationSet = animations;
  64. _Animancer.Play(animations.GetClip(_Facing));
  65. // If the new animation is in the synchronization group, give it the same time the previous animation had.
  66. _MovementSynchronization.SyncTime(_CurrentAnimationSet);
  67. }
  68. /************************************************************************************************************************/
  69. // Pre-allocate an array of contact points so Unity doesn't need to allocate a new one every time we call
  70. // _Collider.GetContacts. This example will never have more than 4 contact points, but you might consider a
  71. // higher number in a real game. Even a large number like 64 would be better than making new ones every time.
  72. private static readonly ContactPoint2D[] Contacts = new ContactPoint2D[4];
  73. private void UpdateMovementState()
  74. {
  75. var contactCount = _Collider.GetContacts(Contacts);
  76. for (int i = 0; i < contactCount; i++)
  77. {
  78. // If we are moving directly towards an object (or within 30 degrees of it), we are pushing it.
  79. if (Vector2.Angle(Contacts[i].normal, _Movement) > 180 - 30)
  80. {
  81. Play(_Push);
  82. return;
  83. }
  84. }
  85. var isRunning = ExampleInput.LeftShiftHold;
  86. Play(isRunning ? _Run : _Walk);
  87. }
  88. /************************************************************************************************************************/
  89. private void FixedUpdate()
  90. {
  91. // Determine the desired speed based on the current animation.
  92. var speed = _CurrentAnimationSet == _Run ? _RunSpeed : _WalkSpeed;
  93. _Rigidbody.velocity = _Movement * speed;
  94. }
  95. /************************************************************************************************************************/
  96. #if UNITY_EDITOR
  97. /************************************************************************************************************************/
  98. /// <summary>[Editor-Only]
  99. /// Sets the character's starting sprite in Edit Mode so you can see it while working in the scene.
  100. /// </summary>
  101. /// <remarks>Called in Edit Mode whenever this script is loaded or a value is changed in the Inspector.</remarks>
  102. private void OnValidate()
  103. {
  104. if (_Idle != null)
  105. _Idle.GetClip(_Facing).EditModePlay(_Animancer);
  106. }
  107. /************************************************************************************************************************/
  108. #endif
  109. /************************************************************************************************************************/
  110. }
  111. }