IdleState.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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 System;
  5. using UnityEngine;
  6. namespace Animancer.Examples.AnimatorControllers.GameKit
  7. {
  8. /// <summary>
  9. /// A <see cref="CharacterState"/> which keeps the character standing still and occasionally plays alternate
  10. /// animations if it remains active for long enough.
  11. /// </summary>
  12. /// <example><see href="https://kybernetik.com.au/animancer/docs/examples/animator-controllers/3d-game-kit/idle">3D Game Kit/Idle</see></example>
  13. /// https://kybernetik.com.au/animancer/api/Animancer.Examples.AnimatorControllers.GameKit/IdleState
  14. ///
  15. [AddComponentMenu(Strings.ExamplesMenuPrefix + "Game Kit - Idle State")]
  16. [HelpURL(Strings.DocsURLs.ExampleAPIDocumentation + nameof(AnimatorControllers) + "." + nameof(GameKit) + "/" + nameof(IdleState))]
  17. public sealed class IdleState : CharacterState
  18. {
  19. /************************************************************************************************************************/
  20. [SerializeField] private ClipTransition _MainAnimation;
  21. [SerializeField, Seconds] private float _FirstRandomizeDelay = 5;
  22. [SerializeField, Seconds] private float _MinRandomizeInterval = 0;
  23. [SerializeField, Seconds] private float _MaxRandomizeInterval = 20;
  24. [SerializeField] private ClipTransition[] _RandomAnimations;
  25. private float _RandomizeTime;
  26. // _RandomizeDelay was originally handled by the PlayerController (Idle Timeout).
  27. // The min and max interval were handled by the RandomStateSMB on the Idle state in IdleSM.
  28. /************************************************************************************************************************/
  29. private void Awake()
  30. {
  31. Action onEnd = PlayMainAnimation;
  32. for (int i = 0; i < _RandomAnimations.Length; i++)
  33. {
  34. _RandomAnimations[i].Events.OnEnd = onEnd;
  35. // We could just do `...OnEnd = PlayMainAnimation` instead of declaring the delegate first, but that
  36. // assignment is actually shorthand for `new Action(PlayMainAnimation)` which would create a new
  37. // delegate object for each animation. This way all animations just share the same object.
  38. }
  39. }
  40. /************************************************************************************************************************/
  41. public override bool CanEnterState => Character.Movement.IsGrounded;
  42. /************************************************************************************************************************/
  43. private void OnEnable()
  44. {
  45. PlayMainAnimation();
  46. _RandomizeTime += _FirstRandomizeDelay;
  47. }
  48. private void PlayMainAnimation()
  49. {
  50. _RandomizeTime = UnityEngine.Random.Range(_MinRandomizeInterval, _MaxRandomizeInterval);
  51. Character.Animancer.Play(_MainAnimation);
  52. }
  53. /************************************************************************************************************************/
  54. private void FixedUpdate()
  55. {
  56. if (Character.CheckMotionState())
  57. return;
  58. Character.Movement.UpdateSpeedControl();
  59. // We use time where Mecanim used normalized time because choosing a number of seconds is much simpler than
  60. // finding out how long the animation is and working with multiples of that value.
  61. var state = Character.Animancer.States.Current;
  62. if (state == _MainAnimation.State &&
  63. state.Time >= _RandomizeTime)
  64. {
  65. PlayRandomAnimation();
  66. }
  67. }
  68. /************************************************************************************************************************/
  69. private void PlayRandomAnimation()
  70. {
  71. var index = UnityEngine.Random.Range(0, _RandomAnimations.Length);
  72. var animation = _RandomAnimations[index];
  73. Character.Animancer.Play(animation);
  74. CustomFade.Apply(Character.Animancer, Easing.Function.SineInOut);
  75. }
  76. /************************************************************************************************************************/
  77. }
  78. }