SpiderBot.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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 UnityEngine;
  4. namespace Animancer.Examples.FineControl
  5. {
  6. /// <summary>
  7. /// Demonstrates how to play a single "Wake Up" animation forwards to wake up and backwards to go back to sleep.
  8. /// </summary>
  9. ///
  10. /// <example><see href="https://kybernetik.com.au/animancer/docs/examples/fine-control/speed-and-time">Speed And Time</see></example>
  11. ///
  12. /// <remarks>
  13. /// This script is also reused in the
  14. /// <see href="https://kybernetik.com.au/animancer/docs/examples/locomotion/directional-blending">
  15. /// Directional Blending</see> example.
  16. /// </remarks>
  17. ///
  18. /// https://kybernetik.com.au/animancer/api/Animancer.Examples.FineControl/SpiderBot
  19. ///
  20. [AddComponentMenu(Strings.ExamplesMenuPrefix + "Fine Control - Spider Bot")]
  21. [HelpURL(Strings.DocsURLs.ExampleAPIDocumentation + nameof(FineControl) + "/" + nameof(SpiderBot))]
  22. public sealed class SpiderBot : MonoBehaviour
  23. {
  24. /************************************************************************************************************************/
  25. [SerializeField] private AnimancerComponent _Animancer;
  26. [SerializeField] private ClipTransition _WakeUp;
  27. /// <summary>
  28. /// The [<see cref="SerializeReference"/>] attribute allows any <see cref="ITransition"/> to be assigned to
  29. /// this field. The <see href="https://kybernetik.com.au/animancer/docs/manual/other/polymorphic">
  30. /// Polymorphic</see> page explains this system in more detail.
  31. /// </summary>
  32. /// <remarks>
  33. /// The <see href="https://kybernetik.com.au/animancer/docs/examples/fine-control/speed-and-time">
  34. /// Speed And Time</see> example uses a <see cref="ClipTransition"/> to play a single animation.
  35. /// <para></para>
  36. /// The <see href="https://kybernetik.com.au/animancer/docs/examples/locomotion/directional-blending">
  37. /// Directional Blending</see> example uses a <see cref="MixerTransition2D"/> to blend between various movement
  38. /// animations.
  39. /// </remarks>
  40. [SerializeReference] private ITransition _Move;
  41. private bool _IsMoving;
  42. /************************************************************************************************************************/
  43. // These properties allow the Directional Blending example to access our private fields but not modify them.
  44. public AnimancerComponent Animancer => _Animancer;
  45. public ITransition Move => _Move;
  46. /************************************************************************************************************************/
  47. private void Awake()
  48. {
  49. _WakeUp.Events.OnEnd = OnWakeUpEnd;
  50. // Start paused at the beginning of the animation.
  51. _Animancer.Play(_WakeUp);
  52. _Animancer.Playable.PauseGraph();
  53. // Normally Unity would evaluate the Playable Graph every frame and apply its output to the model,
  54. // but that won't happen since it is paused so we manually call Evaluate to make it apply the first frame.
  55. _Animancer.Evaluate();
  56. }
  57. /************************************************************************************************************************/
  58. private void OnWakeUpEnd()
  59. {
  60. if (_WakeUp.State.Speed > 0)
  61. _Animancer.Play(_Move);
  62. else
  63. _Animancer.Playable.PauseGraph();
  64. }
  65. /************************************************************************************************************************/
  66. /// <summary>
  67. /// This script won't actually do anything on its own, it simply exposes this public property for others.
  68. /// </summary>
  69. /// <remarks>
  70. /// The <see href="https://kybernetik.com.au/animancer/docs/examples/fine-control/speed-and-time">
  71. /// Speed And Time</see> example controls it with a <see cref="UnityEngine.UI.Toggle"/>.
  72. /// <para></para>
  73. /// The <see href="https://kybernetik.com.au/animancer/docs/examples/locomotion/directional-blending">
  74. /// Directional Blending</see> example controls it with a <see cref="Locomotion.SpiderBotAdvanced"/>.
  75. /// </remarks>
  76. public bool IsMoving
  77. {
  78. get => _IsMoving;
  79. set
  80. {
  81. if (value)
  82. WakeUp();
  83. else
  84. GoToSleep();
  85. }
  86. }
  87. /************************************************************************************************************************/
  88. private void WakeUp()
  89. {
  90. if (_IsMoving)
  91. return;
  92. _IsMoving = true;
  93. var state = _Animancer.Play(_WakeUp);
  94. state.Speed = 1;
  95. // Make sure the graph is unpaused (because we pause it when going back to sleep).
  96. _Animancer.Playable.UnpauseGraph();
  97. }
  98. /************************************************************************************************************************/
  99. private void GoToSleep()
  100. {
  101. if (!_IsMoving)
  102. return;
  103. _IsMoving = false;
  104. var state = _Animancer.Play(_WakeUp);
  105. state.Speed = -1;
  106. // If it was past the last frame, skip back to the last frame now that it is playing backwards.
  107. // Otherwise just play backwards from the current time.
  108. if (state.Weight == 0 || state.NormalizedTime > 1)
  109. {
  110. state.NormalizedTime = 1;
  111. }
  112. }
  113. /************************************************************************************************************************/
  114. }
  115. }