Açıklama Yok
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SpriteResolver.cs 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. using System;
  2. using UnityEngine.Animations;
  3. using UnityEngine.Scripting.APIUpdating;
  4. using UnityEngine.U2D.Common;
  5. namespace UnityEngine.U2D.Animation
  6. {
  7. /// <summary>
  8. /// Updates a SpriteRenderer's Sprite reference on the Category and Label value it is set.
  9. /// </summary>
  10. /// <Description>
  11. /// By setting the SpriteResolver's Category and Label value, it will request for a Sprite from
  12. /// a SpriteLibrary Component the Sprite that is registered for the Category and Label.
  13. /// If a SpriteRenderer is present in the same GameObject, the SpriteResolver will update the
  14. /// SpriteRenderer's Sprite reference to the corresponding Sprite.
  15. /// </Description>
  16. [ExecuteInEditMode]
  17. [DisallowMultipleComponent]
  18. [AddComponentMenu("2D Animation/Sprite Resolver")]
  19. [IconAttribute(IconUtility.IconPath + "Animation.SpriteResolver.png")]
  20. [DefaultExecutionOrder(UpdateOrder.spriteResolverUpdateOrder)]
  21. [HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.animation@latest/index.html?subfolder=/manual/SL-Resolver.html")]
  22. [MovedFrom("UnityEngine.Experimental.U2D.Animation")]
  23. public partial class SpriteResolver : MonoBehaviour, IPreviewable
  24. {
  25. // SpriteHash is the new animation key.
  26. // We are keeping the old ones so that the animation clip doesn't break
  27. // These are for animation
  28. [SerializeField]
  29. float m_CategoryHash = 0;
  30. [SerializeField]
  31. float m_labelHash = 0;
  32. [SerializeField]
  33. float m_SpriteKey = 0;
  34. [SerializeField, DiscreteEvaluation]
  35. int m_SpriteHash = 0;
  36. // For comparing hash values
  37. int m_CategoryHashInt;
  38. int m_LabelHashInt;
  39. // For OnUpdate during animation playback
  40. int m_PreviousCategoryHash;
  41. int m_PreviousLabelHash;
  42. int m_PreviousSpriteKeyInt;
  43. int m_PreviousSpriteHash;
  44. /// <summary>
  45. /// Raised when resolved to a new value.
  46. /// </summary>
  47. internal event Action<SpriteResolver> onResolvedSprite;
  48. void Reset()
  49. {
  50. // If the Sprite referred to by the SpriteRenderer exist in the library,
  51. // we select the Sprite
  52. if(spriteRenderer)
  53. SetSprite(spriteRenderer.sprite);
  54. }
  55. void SetSprite(Sprite sprite)
  56. {
  57. var sl = spriteLibrary;
  58. if (sl != null && sprite != null)
  59. {
  60. foreach (var cat in sl.categoryNames)
  61. {
  62. var entries = sl.GetEntryNames(cat);
  63. foreach (var ent in entries)
  64. {
  65. if (sl.GetSprite(cat, ent) == sprite)
  66. {
  67. m_SpriteHash = SpriteLibrary.GetHashForCategoryAndEntry(cat, ent);
  68. return;
  69. }
  70. }
  71. }
  72. }
  73. }
  74. void OnEnable()
  75. {
  76. InitializeSerializedData();
  77. ResolveSpriteToSpriteRenderer();
  78. }
  79. void InitializeSerializedData()
  80. {
  81. m_CategoryHashInt = InternalEngineBridge.ConvertFloatToInt(m_CategoryHash);
  82. m_LabelHashInt = InternalEngineBridge.ConvertFloatToInt(m_labelHash);
  83. m_PreviousSpriteKeyInt = SpriteLibraryUtility.Convert32BitTo30BitHash(InternalEngineBridge.ConvertFloatToInt(m_SpriteKey));
  84. m_SpriteKey = InternalEngineBridge.ConvertIntToFloat(m_PreviousSpriteKeyInt);
  85. if (m_SpriteHash == 0)
  86. {
  87. if (m_SpriteKey != 0f)
  88. m_SpriteHash = InternalEngineBridge.ConvertFloatToInt(m_SpriteKey);
  89. else
  90. m_SpriteHash = ConvertCategoryLabelHashToSpriteKey(spriteLibrary, SpriteLibraryUtility.Convert32BitTo30BitHash(m_CategoryHashInt), SpriteLibraryUtility.Convert32BitTo30BitHash(m_LabelHashInt));
  91. }
  92. m_PreviousSpriteHash = m_SpriteHash;
  93. string newCat, newLab;
  94. if (spriteLibrary != null && spriteLibrary.GetCategoryAndEntryNameFromHash(m_SpriteHash, out newCat, out newLab))
  95. {
  96. // Populate back in case user is using animating with old animation clip
  97. m_CategoryHashInt = SpriteLibraryUtility.GetStringHash(newCat);
  98. m_LabelHashInt = SpriteLibraryUtility.GetStringHash(newLab);
  99. m_CategoryHash = InternalEngineBridge.ConvertIntToFloat(m_CategoryHashInt);
  100. m_labelHash = InternalEngineBridge.ConvertIntToFloat(m_LabelHashInt);
  101. }
  102. m_PreviousLabelHash = m_LabelHashInt;
  103. m_PreviousCategoryHash = m_CategoryHashInt;
  104. }
  105. SpriteRenderer spriteRenderer => GetComponent<SpriteRenderer>();
  106. /// <summary>
  107. /// Set the Category and label to use.
  108. /// </summary>
  109. /// <param name="category">Category to use.</param>
  110. /// <param name="label">Label to use.</param>
  111. /// <returns>True if the Category and Label were successfully set.</returns>
  112. public bool SetCategoryAndLabel(string category, string label)
  113. {
  114. m_SpriteHash = SpriteLibrary.GetHashForCategoryAndEntry(category, label);
  115. m_PreviousSpriteHash = m_SpriteHash;
  116. return ResolveSpriteToSpriteRenderer();
  117. }
  118. /// <summary>
  119. /// Get the Category set for the SpriteResolver.
  120. /// </summary>
  121. /// <returns>The Category's name.</returns>
  122. public string GetCategory()
  123. {
  124. var returnString = "";
  125. var sl = spriteLibrary;
  126. if (sl)
  127. {
  128. sl.GetCategoryAndEntryNameFromHash(m_SpriteHash, out returnString, out _);
  129. }
  130. return returnString;
  131. }
  132. /// <summary>
  133. /// Get the Label set for the SpriteResolver.
  134. /// </summary>
  135. /// <returns>The Label's name.</returns>
  136. public string GetLabel()
  137. {
  138. var returnString = "";
  139. var sl = spriteLibrary;
  140. if (sl)
  141. sl.GetCategoryAndEntryNameFromHash(m_SpriteHash, out _, out returnString);
  142. return returnString;
  143. }
  144. /// <summary>
  145. /// Property to get the SpriteLibrary the SpriteResolver is resolving from.
  146. /// </summary>
  147. public SpriteLibrary spriteLibrary => gameObject.GetComponentInParent<SpriteLibrary>(true);
  148. /// <summary>
  149. /// Empty method. Implemented for the IPreviewable interface.
  150. /// </summary>
  151. public void OnPreviewUpdate() { }
  152. static bool IsInGUIUpdateLoop() => Event.current != null;
  153. void LateUpdate()
  154. {
  155. ResolveUpdatedValue();
  156. }
  157. void ResolveUpdatedValue()
  158. {
  159. if (m_SpriteHash != m_PreviousSpriteHash)
  160. {
  161. m_PreviousSpriteHash = m_SpriteHash;
  162. ResolveSpriteToSpriteRenderer();
  163. }
  164. else
  165. {
  166. // Path is still needed in case users are running animation clip from before.
  167. var spriteKeyInt = InternalEngineBridge.ConvertFloatToInt(m_SpriteKey);
  168. if (spriteKeyInt != m_PreviousSpriteKeyInt)
  169. {
  170. m_SpriteHash = SpriteLibraryUtility.Convert32BitTo30BitHash(spriteKeyInt);
  171. m_PreviousSpriteKeyInt = spriteKeyInt;
  172. ResolveSpriteToSpriteRenderer();
  173. }
  174. else
  175. {
  176. m_CategoryHashInt = InternalEngineBridge.ConvertFloatToInt(m_CategoryHash);
  177. m_LabelHashInt = InternalEngineBridge.ConvertFloatToInt(m_labelHash);
  178. if (m_LabelHashInt != m_PreviousLabelHash || m_CategoryHashInt != m_PreviousCategoryHash)
  179. {
  180. if (spriteLibrary != null)
  181. {
  182. m_PreviousCategoryHash = m_CategoryHashInt;
  183. m_PreviousLabelHash = m_LabelHashInt;
  184. m_SpriteHash = ConvertCategoryLabelHashToSpriteKey(spriteLibrary, SpriteLibraryUtility.Convert32BitTo30BitHash(m_CategoryHashInt), SpriteLibraryUtility.Convert32BitTo30BitHash(m_LabelHashInt));
  185. m_PreviousSpriteHash = m_SpriteHash;
  186. ResolveSpriteToSpriteRenderer();
  187. }
  188. }
  189. }
  190. }
  191. }
  192. internal static int ConvertCategoryLabelHashToSpriteKey(SpriteLibrary library, int categoryHash, int labelHash)
  193. {
  194. if (library != null)
  195. {
  196. foreach(var category in library.categoryNames)
  197. {
  198. if (categoryHash == SpriteLibraryUtility.GetStringHash(category))
  199. {
  200. var entries = library.GetEntryNames(category);
  201. if (entries != null)
  202. {
  203. foreach (var entry in entries)
  204. {
  205. if (labelHash == SpriteLibraryUtility.GetStringHash(entry))
  206. {
  207. return SpriteLibrary.GetHashForCategoryAndEntry(category, entry);
  208. }
  209. }
  210. }
  211. }
  212. }
  213. }
  214. return 0;
  215. }
  216. internal Sprite GetSprite(out bool validEntry)
  217. {
  218. var lib = spriteLibrary;
  219. if (lib != null)
  220. {
  221. return lib.GetSpriteFromCategoryAndEntryHash(m_SpriteHash, out validEntry);
  222. }
  223. validEntry = false;
  224. return null;
  225. }
  226. /// <summary>
  227. /// Set the Sprite in SpriteResolver to the SpriteRenderer component that is in the same GameObject.
  228. /// </summary>
  229. /// <returns>True if it successfully resolved the Sprite.</returns>
  230. public bool ResolveSpriteToSpriteRenderer()
  231. {
  232. m_PreviousSpriteHash = m_SpriteHash;
  233. var sprite = GetSprite(out var validEntry);
  234. var sr = spriteRenderer;
  235. if (sr != null && (sprite != null || validEntry))
  236. sr.sprite = sprite;
  237. onResolvedSprite?.Invoke(this);
  238. return validEntry;
  239. }
  240. void OnTransformParentChanged()
  241. {
  242. ResolveSpriteToSpriteRenderer();
  243. #if UNITY_EDITOR
  244. spriteLibChanged = true;
  245. #endif
  246. }
  247. }
  248. }