Last active
          April 9, 2025 13:45 
        
      - 
      
- 
        Save hasanbayatme/f7f1d9d0f8470b718fda836f6668c215 to your computer and use it in GitHub Desktop. 
Revisions
- 
        hasanbayatme revised this gist Nov 17, 2023 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -74,11 +74,11 @@ public class GameCharacter : MonoBehaviour { - `HasParameter`: Checks whether the animator has a parameter - `ResetTriggerSafe`: Resets the value of the given trigger parameter safely. - `SetTriggerSafe`: Sets the value of the given trigger parameter safely. - `GetBoolSafe`: Gets the value of the given boolean parameter safely. - `SetBoolSafe`: Sets the value of the given boolean parameter safely. - `GetIntegerSafe`: Gets the value of the given integer parameter safely. - `SetIntegerSafe`: Sets the value of the given integer parameter safely. - `GetFloatSafe`: Gets the value of the given float parameter safely. - `SetFloatSafe`: Sets the value of the given float parameter safely. ## License 
- 
        hasanbayatme created this gist Nov 17, 2023 .There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,414 @@ /** MIT License Copyright (c) 2023 Bayat Games Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. **/ using System.Collections; using System.Collections.Generic; using UnityEngine; namespace Bayat.Games.Animation.Utilities { /// <summary> /// Animator controller utility methods and extensions. /// </summary> public static class AnimatorUtility { #region Fields private static Dictionary<Animator, HashSet<int>> animatorToParameters = new(); private static Dictionary<string, int> parameterNameToHash = new(); private static Dictionary<Animator, int> animatorUsages = new(); #endregion #region Helpers /// <summary> /// Clears all the caches. /// </summary> public static void ClearCaches() { animatorToParameters.Clear(); parameterNameToHash.Clear(); animatorUsages.Clear(); } /// <summary> /// Initializes the animator. /// </summary> /// <remarks> /// 1. Disables logging of the animator. /// 2. Gets the animator parameters and caches them /// </remarks> /// <param name="animator">The animator</param> public static void InitializeAnimator(this Animator animator) { // Uncomment to disable log warnings to save on performance //animator.logWarnings = false; // Add parameters as cached GetParameters(animator); } /// <summary> /// Adds a usage for the animator. /// </summary> /// <remarks> /// Once the usage count becomes greater than 0, it gets the animator's parameters and caches them. /// </remarks> /// <param name="animator">The animator</param> public static void AddAnimatorUsage(this Animator animator) { if (animatorUsages.TryGetValue(animator, out int currentUsages)) { animatorUsages[animator] = currentUsages + 1; } else { animatorUsages[animator] = 1; // Initialize on first usage InitializeAnimator(animator); } } /// <summary> /// Removes the usage from the animator. /// </summary> /// <remarks> /// If the usage count is 0, then the animator parameters will be removed from the cache, call this when the Unity object is being destroyed or removed, or you no longer use the animator. /// </remarks> /// <param name="animator">The animator</param> public static void RemoveAnimatorUsage(this Animator animator) { if (animatorUsages.TryGetValue(animator, out int currentUsages)) { animatorUsages[animator] = currentUsages - 1; } else { animatorUsages.Remove(animator); // Removo cached parameters animatorToParameters.Remove(animator); } } /// <summary> /// Gets the parameter's name hash. /// </summary> /// <remarks> /// It uses <see cref="Animator.StringToHash(string)"/> for the first time and then caches the name in order to be reused later on. /// </remarks> /// <param name="parameterName">The parameter name</param> /// <returns>Returns the parameter's name hash</returns> public static int GetParameterNameHash(string parameterName) { if (parameterNameToHash.TryGetValue(parameterName, out int parameterHash)) { return parameterHash; } return parameterNameToHash[parameterName] = Animator.StringToHash(parameterName); } /// <summary> /// Gets the animator parameters as a <see cref="HashSet{T}"/> of their name hashes. /// </summary> /// <remarks> /// It uses the cached version if the method is called more than once. /// </remarks> /// <param name="animator">The animator</param> /// <param name="parameterName">The parameter name</param> /// <returns>Returns a <see cref="HashSet{T}"/> of animator parameters name hashes</returns> public static HashSet<int> GetParameters(Animator animator) { HashSet<int> parameters; if (animatorToParameters.TryGetValue(animator, out parameters)) { return parameters; } parameters = new HashSet<int>(); for (int i = 0; i < animator.parameterCount; i++) { AnimatorControllerParameter parameter = animator.GetParameter(i); parameters.Add(parameter.nameHash); } return parameters; } /// <summary> /// Checks whether the animator has the parameter or not. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterName">The parameter name</param> /// <returns>Returns true if the animator has the parameter, otherwise false</returns> public static bool HasParameter(this Animator animator, string parameterName) { return HasParameter(animator, GetParameterNameHash(parameterName)); } /// <summary> /// Checks whether the animator has the parameter or not. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterHash">The parameter hash</param> /// <returns>Returns true if the animator has the parameter, otherwise false</returns> public static bool HasParameter(this Animator animator, int parameterHash) { return GetParameters(animator).Contains(parameterHash); } #endregion #region Reset Trigger /// <summary> /// Resets the value of the given trigger parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterName">The parameter name</param> public static void ResetTriggerSafe(this Animator animator, string parameterName) { ResetTriggerSafe(animator, GetParameterNameHash(parameterName)); } /// <summary> /// Resets the value of the given trigger parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterHash">The parameter hash</param> public static void ResetTriggerSafe(this Animator animator, int parameterHash) { if (HasParameter(animator, parameterHash)) { animator.ResetTrigger(parameterHash); } } #endregion #region Set Trigger /// <summary> /// Sets the value of the given trigger parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterName">The parameter name</param> public static void SetTriggerSafe(this Animator animator, string parameterName) { SetTriggerSafe(animator, GetParameterNameHash(parameterName)); } /// <summary> /// Sets the value of the given trigger parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterHash">The parameter hash</param> public static void SetTriggerSafe(this Animator animator, int parameterHash) { if (HasParameter(animator, parameterHash)) { animator.SetTrigger(parameterHash); } } #endregion #region Get Bool /// <summary> /// Gets the value of the given boolean parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterName">The parameter name</param> public static bool GetBoolSafe(this Animator animator, string parameterName, bool defaultValue = false) { return GetBoolSafe(animator, GetParameterNameHash(parameterName), defaultValue); } /// <summary> /// Gets the value of the given boolean parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterHash">The parameter hash</param> public static bool GetBoolSafe(this Animator animator, int parameterHash, bool defaultValue = false) { if (HasParameter(animator, parameterHash)) { return animator.GetBool(parameterHash); } return defaultValue; } #endregion #region Set Bool /// <summary> /// Sets the value of the given boolean parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterName">The parameter name</param> public static void SetBoolSafe(this Animator animator, string parameterName, bool value) { SetBoolSafe(animator, GetParameterNameHash(parameterName), value); } /// <summary> /// Sets the value of the given boolean parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterHash">The parameter hash</param> public static void SetBoolSafe(this Animator animator, int parameterHash, bool value) { if (HasParameter(animator, parameterHash)) { animator.SetBool(parameterHash, value); } } #endregion #region Get Float /// <summary> /// Gets the value of the given float parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterName">The parameter name</param> public static float GetFloatSafe(this Animator animator, string parameterName, float defaultValue = 0f) { return GetFloatSafe(animator, GetParameterNameHash(parameterName), defaultValue); } /// <summary> /// Gets the value of the given float parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterHash">The parameter hash</param> public static float GetFloatSafe(this Animator animator, int parameterHash, float defaultValue = 0f) { if (HasParameter(animator, parameterHash)) { return animator.GetFloat(parameterHash); } return defaultValue; } #endregion #region Set Float /// <summary> /// Sets the value of the given integer parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterName">The parameter name</param> public static void SetIntegerSafe(this Animator animator, string parameterName, int value) { SetIntegerSafe(animator, GetParameterNameHash(parameterName), value); } /// <summary> /// Sets the value of the given integer parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterHash">The parameter hash</param> public static void SetIntegerSafe(this Animator animator, int parameterHash, int value) { if (HasParameter(animator, parameterHash)) { animator.SetInteger(parameterHash, value); } } #endregion #region Get Integer /// <summary> /// Gets the value of the given integer parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterName">The parameter name</param> public static int GetIntegerSafe(this Animator animator, string parameterName, int defaultValue = 0) { return GetIntegerSafe(animator, GetParameterNameHash(parameterName), defaultValue); } /// <summary> /// Gets the value of the given integer parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterHash">The parameter hash</param> public static int GetIntegerSafe(this Animator animator, int parameterHash, int defaultValue = 0) { if (HasParameter(animator, parameterHash)) { return animator.GetInteger(parameterHash); } return defaultValue; } #endregion #region Set Integer /// <summary> /// Sets the value of the given float parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterName">The parameter name</param> public static void SetFloatSafe(this Animator animator, string parameterName, float value) { SetFloatSafe(animator, GetParameterNameHash(parameterName), value); } /// <summary> /// Sets the value of the given float parameter safely. /// </summary> /// <param name="animator">The animator</param> /// <param name="parameterHash">The parameter hash</param> public static void SetFloatSafe(this Animator animator, int parameterHash, float value) { if (HasParameter(animator, parameterHash)) { animator.SetFloat(parameterHash, value); } } #endregion } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,95 @@ # AnimatorUtility This is a simple Unity animator utility class that allows you to check if the animator has a certain parameter or safely set parameters. ## Features - Get or Set animator parameter safely (checks whether the animator parameter exists before setting or getting it) - Provide a default value for Get methods in case animator doesn't have them - Check whether the animator has a parameter - Get animator parameters without multiple GC allocs - Uses Parameter's name hash instead of the name to improve performance (the name hashes are cached too) - Caches the animator and their parameters using a Dictionary and HashSet for optimal performance in cases of calling in Update or LateUpdate - Release unused caches and animators by calling `AddAnimatorUsage` when you first initialize and use the animator, then call `RemoveAnimatorUsage` when you no longer use the animator - You can explicitly call `ClearCaches` to remove all caches - Includes code comments for all methods ## Usage ```cs using Bayat.Games.Animation.Utilities; public class GameCharacter : MonoBehaviour { [Header("Animation")] [SerializeField] protected Animator animator; [SerializeField] protected string speedParameter = "Speed"; [Header("Physics")] [SerializeField] protected new Rigidbody2D rigidbody2D; protected void OnEnable() { // Allocate caches and resources for this animator (only the first usage allocates the caches, the rest use the same caches for this animator) animator.AddAnimatorUsage(); } protected void OnDisable() { // Release caches and unused resources animator.RemoveAnimatorUsage(); } proteved void LateUpdate() { float speed = Mathf.Abs(this.rigidbody2D.velocity.magnitude); // Set a parameter safely (it won't log warnings) animator.SetFloatSafe(this.speedParameter, speed); // Or manually check if the parameter exists if (animator.HasParameter(this.speedParameter)) { animator.SetFloat(this.speedParameter, speed); } // Get a parameter's value safely with a default value // The "Height" parameter here is missing in the animator and the default height value is returned instead float defaultHeight = 10f; float height = animator.GetFloatSafe("Height", defaultHeight); } } ``` ## API - `AddAnimatorUsage`: Adds an animator usage and allocates caches and resources for it - `RemoveAnimatorUsage`: Removes an animator usage and releases caches and unused resources - `GetParameterNameHash`: Gets the parameter's name hash. It's cached for consecutive calls. - `GetParameters`: Gets the animator parameters as a HashSet of their name hashes. - `ClearCaches`: Clears all caches - `HasParameter`: Checks whether the animator has a parameter - `ResetTriggerSafe`: Resets the value of the given trigger parameter safely. - `SetTriggerSafe`: Sets the value of the given trigger parameter safely. - `GetBoolSafe`: Resets the value of the given boolean parameter safely. - `SetBoolSafe`: Sets the value of the given boolean parameter safely. - `GetIntegerSafe`: Resets the value of the given integer parameter safely. - `SetIntegerSafe`: Sets the value of the given integer parameter safely. - `GetFloatSafe`: Resets the value of the given float parameter safely. - `SetFloatSafe`: Sets the value of the given float parameter safely. ## License MIT License ## Credits - Developed and maintained by [Hasan Bayat][hasanbayat] Made with ❤️ by [Bayat][bayat] [hasanbayat]: https://github.com/hasanbayatme [bayat]: https://bayat.io