StateMachine2.WithDefault.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2022 Kybernetik //
  2. using System;
  3. using UnityEngine;
  4. namespace Animancer.FSM
  5. {
  6. /// https://kybernetik.com.au/animancer/api/Animancer.FSM/StateMachine_2
  7. partial class StateMachine<TKey, TState>
  8. {
  9. /// <summary>A <see cref="StateMachine{TKey, TState}"/> with a <see cref="DefaultKey"/>.</summary>
  10. /// <remarks>
  11. /// See <see cref="InitializeAfterDeserialize"/> if using this class in a serialized field.
  12. /// <para></para>
  13. /// Documentation: <see href="https://kybernetik.com.au/animancer/docs/manual/fsm/changing-states#default-states">Default States</see>
  14. /// </remarks>
  15. /// https://kybernetik.com.au/animancer/api/Animancer.FSM/WithDefault
  16. ///
  17. [Serializable]
  18. public new class WithDefault : StateMachine<TKey, TState>
  19. {
  20. /************************************************************************************************************************/
  21. [SerializeField]
  22. private TKey _DefaultKey;
  23. /// <summary>The starting state and main state to return to when nothing else is active.</summary>
  24. /// <remarks>
  25. /// If the <see cref="CurrentState"/> is <c>null</c> when setting this value, it calls
  26. /// <see cref="ForceSetState(TKey)"/> to enter the specified state immediately.
  27. /// <para></para>
  28. /// For a character, this would typically be their <em>Idle</em> state.
  29. /// </remarks>
  30. public TKey DefaultKey
  31. {
  32. get => _DefaultKey;
  33. set
  34. {
  35. _DefaultKey = value;
  36. if (CurrentState == null && value != null)
  37. ForceSetState(value);
  38. }
  39. }
  40. /************************************************************************************************************************/
  41. /// <summary>Calls <see cref="ForceSetState(TKey)"/> with the <see cref="DefaultKey"/>.</summary>
  42. /// <remarks>This delegate is cached to avoid allocating garbage when used in Animancer Events.</remarks>
  43. public readonly Action ForceSetDefaultState;
  44. /************************************************************************************************************************/
  45. /// <summary>Creates a new <see cref="WithDefault"/>.</summary>
  46. public WithDefault()
  47. {
  48. // Silly C# doesn't allow instance delegates to be assigned using field initializers.
  49. ForceSetDefaultState = () => ForceSetState(_DefaultKey);
  50. }
  51. /************************************************************************************************************************/
  52. /// <summary>Creates a new <see cref="WithDefault"/> and sets the <see cref="DefaultKey"/>.</summary>
  53. public WithDefault(TKey defaultKey)
  54. : this()
  55. {
  56. _DefaultKey = defaultKey;
  57. ForceSetState(defaultKey);
  58. }
  59. /************************************************************************************************************************/
  60. /// <inheritdoc/>
  61. public override void InitializeAfterDeserialize()
  62. {
  63. if (CurrentState != null)
  64. {
  65. using (new KeyChange<TKey>(this, default, _DefaultKey))
  66. using (new StateChange<TState>(this, null, CurrentState))
  67. CurrentState.OnEnterState();
  68. }
  69. else
  70. {
  71. ForceSetState(_DefaultKey);
  72. }
  73. // Don't call the base method.
  74. }
  75. /************************************************************************************************************************/
  76. /// <summary>Attempts to enter the <see cref="DefaultKey"/> and returns true if successful.</summary>
  77. /// <remarks>
  78. /// This method returns true immediately if the specified <see cref="DefaultKey"/> is already the
  79. /// <see cref="CurrentKey"/>. To allow directly re-entering the same state, use
  80. /// <see cref="TryResetDefaultState"/> instead.
  81. /// </remarks>
  82. public TState TrySetDefaultState() => TrySetState(_DefaultKey);
  83. /************************************************************************************************************************/
  84. /// <summary>Attempts to enter the <see cref="DefaultKey"/> and returns true if successful.</summary>
  85. /// <remarks>
  86. /// This method does not check if the <see cref="DefaultKey"/> is already the <see cref="CurrentKey"/>.
  87. /// To do so, use <see cref="TrySetDefaultState"/> instead.
  88. /// </remarks>
  89. public TState TryResetDefaultState() => TryResetState(_DefaultKey);
  90. /************************************************************************************************************************/
  91. #if UNITY_EDITOR
  92. /************************************************************************************************************************/
  93. /// <inheritdoc/>
  94. public override int GUILineCount => 2;
  95. /************************************************************************************************************************/
  96. /// <inheritdoc/>
  97. public override void DoGUI(ref Rect area)
  98. {
  99. area.height = UnityEditor.EditorGUIUtility.singleLineHeight;
  100. UnityEditor.EditorGUI.BeginChangeCheck();
  101. var state = StateMachineUtilities.DoGenericField(area, "Default Key", DefaultKey);
  102. if (UnityEditor.EditorGUI.EndChangeCheck())
  103. DefaultKey = state;
  104. StateMachineUtilities.NextVerticalArea(ref area);
  105. base.DoGUI(ref area);
  106. }
  107. /************************************************************************************************************************/
  108. #endif
  109. /************************************************************************************************************************/
  110. }
  111. }
  112. }