123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- using System;
- using UnityEngine.Animations;
- using UnityEngine.Scripting.APIUpdating;
- using UnityEngine.U2D.Common;
-
- namespace UnityEngine.U2D.Animation
- {
- /// <summary>
- /// Updates a SpriteRenderer's Sprite reference on the Category and Label value it is set.
- /// </summary>
- /// <Description>
- /// By setting the SpriteResolver's Category and Label value, it will request for a Sprite from
- /// a SpriteLibrary Component the Sprite that is registered for the Category and Label.
- /// If a SpriteRenderer is present in the same GameObject, the SpriteResolver will update the
- /// SpriteRenderer's Sprite reference to the corresponding Sprite.
- /// </Description>
- [ExecuteInEditMode]
- [DisallowMultipleComponent]
- [AddComponentMenu("2D Animation/Sprite Resolver")]
- [IconAttribute(IconUtility.IconPath + "Animation.SpriteResolver.png")]
- [DefaultExecutionOrder(UpdateOrder.spriteResolverUpdateOrder)]
- [HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.animation@latest/index.html?subfolder=/manual/SL-Resolver.html")]
- [MovedFrom("UnityEngine.Experimental.U2D.Animation")]
- public partial class SpriteResolver : MonoBehaviour, IPreviewable
- {
- // SpriteHash is the new animation key.
- // We are keeping the old ones so that the animation clip doesn't break
-
- // These are for animation
- [SerializeField]
- float m_CategoryHash = 0;
- [SerializeField]
- float m_labelHash = 0;
-
- [SerializeField]
- float m_SpriteKey = 0;
-
- [SerializeField, DiscreteEvaluation]
- int m_SpriteHash = 0;
-
- // For comparing hash values
- int m_CategoryHashInt;
- int m_LabelHashInt;
-
- // For OnUpdate during animation playback
- int m_PreviousCategoryHash;
- int m_PreviousLabelHash;
- int m_PreviousSpriteKeyInt;
- int m_PreviousSpriteHash;
-
- /// <summary>
- /// Raised when resolved to a new value.
- /// </summary>
- internal event Action<SpriteResolver> onResolvedSprite;
-
- void Reset()
- {
- // If the Sprite referred to by the SpriteRenderer exist in the library,
- // we select the Sprite
- if(spriteRenderer)
- SetSprite(spriteRenderer.sprite);
- }
-
- void SetSprite(Sprite sprite)
- {
- var sl = spriteLibrary;
- if (sl != null && sprite != null)
- {
- foreach (var cat in sl.categoryNames)
- {
- var entries = sl.GetEntryNames(cat);
- foreach (var ent in entries)
- {
- if (sl.GetSprite(cat, ent) == sprite)
- {
- m_SpriteHash = SpriteLibrary.GetHashForCategoryAndEntry(cat, ent);
- return;
- }
- }
- }
- }
- }
-
- void OnEnable()
- {
- InitializeSerializedData();
- ResolveSpriteToSpriteRenderer();
- }
-
- void InitializeSerializedData()
- {
- m_CategoryHashInt = InternalEngineBridge.ConvertFloatToInt(m_CategoryHash);
- m_LabelHashInt = InternalEngineBridge.ConvertFloatToInt(m_labelHash);
- m_PreviousSpriteKeyInt = SpriteLibraryUtility.Convert32BitTo30BitHash(InternalEngineBridge.ConvertFloatToInt(m_SpriteKey));
- m_SpriteKey = InternalEngineBridge.ConvertIntToFloat(m_PreviousSpriteKeyInt);
-
- if (m_SpriteHash == 0)
- {
- if (m_SpriteKey != 0f)
- m_SpriteHash = InternalEngineBridge.ConvertFloatToInt(m_SpriteKey);
- else
- m_SpriteHash = ConvertCategoryLabelHashToSpriteKey(spriteLibrary, SpriteLibraryUtility.Convert32BitTo30BitHash(m_CategoryHashInt), SpriteLibraryUtility.Convert32BitTo30BitHash(m_LabelHashInt));
- }
- m_PreviousSpriteHash = m_SpriteHash;
-
- string newCat, newLab;
- if (spriteLibrary != null && spriteLibrary.GetCategoryAndEntryNameFromHash(m_SpriteHash, out newCat, out newLab))
- {
- // Populate back in case user is using animating with old animation clip
- m_CategoryHashInt = SpriteLibraryUtility.GetStringHash(newCat);
- m_LabelHashInt = SpriteLibraryUtility.GetStringHash(newLab);
- m_CategoryHash = InternalEngineBridge.ConvertIntToFloat(m_CategoryHashInt);
- m_labelHash = InternalEngineBridge.ConvertIntToFloat(m_LabelHashInt);
- }
-
- m_PreviousLabelHash = m_LabelHashInt;
- m_PreviousCategoryHash = m_CategoryHashInt;
- }
-
- SpriteRenderer spriteRenderer => GetComponent<SpriteRenderer>();
-
- /// <summary>
- /// Set the Category and label to use.
- /// </summary>
- /// <param name="category">Category to use.</param>
- /// <param name="label">Label to use.</param>
- /// <returns>True if the Category and Label were successfully set.</returns>
- public bool SetCategoryAndLabel(string category, string label)
- {
- m_SpriteHash = SpriteLibrary.GetHashForCategoryAndEntry(category, label);
- m_PreviousSpriteHash = m_SpriteHash;
- return ResolveSpriteToSpriteRenderer();
- }
-
- /// <summary>
- /// Get the Category set for the SpriteResolver.
- /// </summary>
- /// <returns>The Category's name.</returns>
- public string GetCategory()
- {
- var returnString = "";
- var sl = spriteLibrary;
- if (sl)
- {
- sl.GetCategoryAndEntryNameFromHash(m_SpriteHash, out returnString, out _);
- }
-
- return returnString;
- }
-
- /// <summary>
- /// Get the Label set for the SpriteResolver.
- /// </summary>
- /// <returns>The Label's name.</returns>
- public string GetLabel()
- {
- var returnString = "";
- var sl = spriteLibrary;
- if (sl)
- sl.GetCategoryAndEntryNameFromHash(m_SpriteHash, out _, out returnString);
-
- return returnString;
- }
-
- /// <summary>
- /// Property to get the SpriteLibrary the SpriteResolver is resolving from.
- /// </summary>
- public SpriteLibrary spriteLibrary => gameObject.GetComponentInParent<SpriteLibrary>(true);
-
- /// <summary>
- /// Empty method. Implemented for the IPreviewable interface.
- /// </summary>
- public void OnPreviewUpdate() { }
-
- static bool IsInGUIUpdateLoop() => Event.current != null;
-
- void LateUpdate()
- {
- ResolveUpdatedValue();
- }
-
- void ResolveUpdatedValue()
- {
- if (m_SpriteHash != m_PreviousSpriteHash)
- {
- m_PreviousSpriteHash = m_SpriteHash;
- ResolveSpriteToSpriteRenderer();
- }
- else
- {
- // Path is still needed in case users are running animation clip from before.
- var spriteKeyInt = InternalEngineBridge.ConvertFloatToInt(m_SpriteKey);
- if (spriteKeyInt != m_PreviousSpriteKeyInt)
- {
- m_SpriteHash = SpriteLibraryUtility.Convert32BitTo30BitHash(spriteKeyInt);
- m_PreviousSpriteKeyInt = spriteKeyInt;
- ResolveSpriteToSpriteRenderer();
- }
- else
- {
- m_CategoryHashInt = InternalEngineBridge.ConvertFloatToInt(m_CategoryHash);
- m_LabelHashInt = InternalEngineBridge.ConvertFloatToInt(m_labelHash);
- if (m_LabelHashInt != m_PreviousLabelHash || m_CategoryHashInt != m_PreviousCategoryHash)
- {
- if (spriteLibrary != null)
- {
- m_PreviousCategoryHash = m_CategoryHashInt;
- m_PreviousLabelHash = m_LabelHashInt;
- m_SpriteHash = ConvertCategoryLabelHashToSpriteKey(spriteLibrary, SpriteLibraryUtility.Convert32BitTo30BitHash(m_CategoryHashInt), SpriteLibraryUtility.Convert32BitTo30BitHash(m_LabelHashInt));
- m_PreviousSpriteHash = m_SpriteHash;
- ResolveSpriteToSpriteRenderer();
- }
- }
- }
- }
- }
-
- internal static int ConvertCategoryLabelHashToSpriteKey(SpriteLibrary library, int categoryHash, int labelHash)
- {
- if (library != null)
- {
- foreach(var category in library.categoryNames)
- {
- if (categoryHash == SpriteLibraryUtility.GetStringHash(category))
- {
- var entries = library.GetEntryNames(category);
- if (entries != null)
- {
- foreach (var entry in entries)
- {
- if (labelHash == SpriteLibraryUtility.GetStringHash(entry))
- {
- return SpriteLibrary.GetHashForCategoryAndEntry(category, entry);
- }
- }
- }
- }
- }
- }
-
- return 0;
- }
-
- internal Sprite GetSprite(out bool validEntry)
- {
- var lib = spriteLibrary;
- if (lib != null)
- {
- return lib.GetSpriteFromCategoryAndEntryHash(m_SpriteHash, out validEntry);
- }
- validEntry = false;
- return null;
- }
-
- /// <summary>
- /// Set the Sprite in SpriteResolver to the SpriteRenderer component that is in the same GameObject.
- /// </summary>
- /// <returns>True if it successfully resolved the Sprite.</returns>
- public bool ResolveSpriteToSpriteRenderer()
- {
- m_PreviousSpriteHash = m_SpriteHash;
- var sprite = GetSprite(out var validEntry);
- var sr = spriteRenderer;
- if (sr != null && (sprite != null || validEntry))
- sr.sprite = sprite;
-
- onResolvedSprite?.Invoke(this);
-
- return validEntry;
- }
-
- void OnTransformParentChanged()
- {
- ResolveSpriteToSpriteRenderer();
- #if UNITY_EDITOR
- spriteLibChanged = true;
- #endif
- }
- }
- }
|