From 51b0f6ed9f4e1d3bb6f8144470b46908c7699a96 Mon Sep 17 00:00:00 2001
From: yyl <yyl>
Date: 星期一, 11 五月 2026 16:20:37 +0800
Subject: [PATCH] Merge branch 'master' into h5version

---
 Main/System/Hero/UIHeroController.cs |  681 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 626 insertions(+), 55 deletions(-)

diff --git a/Main/System/Hero/UIHeroController.cs b/Main/System/Hero/UIHeroController.cs
index fb01aa1..8b2c15b 100644
--- a/Main/System/Hero/UIHeroController.cs
+++ b/Main/System/Hero/UIHeroController.cs
@@ -1,7 +1,10 @@
-
+锘�
 using System;
+using Spine;
 using Spine.Unity;
 using UnityEngine;
+using UnityEngine.UI;
+using Cysharp.Threading.Tasks;
 
 public class UIHeroController : MonoBehaviour
 {
@@ -9,62 +12,56 @@
 	private int skinID;
 	protected SkeletonGraphic skeletonGraphic;
 
-	protected Spine.AnimationState spineAnimationState;
+	public Spine.AnimationState spineAnimationState;
 	private GameObject instanceGO;
+	private bool isInitializing = false;
+	private bool isInitialized = false;
+	private System.Threading.CancellationTokenSource loadCancellationToken; // 鐢ㄤ簬鍙栨秷涔嬪墠鐨勫姞杞戒换鍔�
 
-	private Action onComplete;
-	public void Create(int _skinID, float scale = 0.8f, Action _onComplete = null, string motionName = "idle", bool isLh = false)
+	// 浣跨敤 UniTask 鎻愪緵鐨勫苟鍙戞帶鍒� - 鏀寔 WebGL
+	// 闄愬埗鍚屾椂鍔犺浇鐨勮祫婧愭暟閲忥紙榛樿涓�4锛屽彲鏍规嵁璁惧鎬ц兘璋冩暣锛�
+	private const int MAX_CONCURRENT_LOADS = 4;
+	private static int currentLoadingCount = 0;
+	private static readonly object loadLock = new object();
+	private static int lastInitFrame = -1; // 涓婁竴娆℃墽琛孖nitialize鐨勫抚鍙凤紝鐢ㄤ簬纭繚姣忓抚鏈�澶�1娆�
+	private static GameObjectPoolManager.GameObjectPool cachedUIHeroPool; // 缂撳瓨UIHero棰勫埗浣撴睜
+	private RectTransform _instanceRect; // 缂撳瓨RectTransform閬垮厤閲嶅GetComponent
+	public Action onComplete;
+#pragma warning disable CS1998 // 寮傛鏂规硶鍐呴儴閫氳繃 DelayedInitializeAsync 寮傛鎵ц锛屾棤闇�鐩存帴 await
+	public async UniTask Create(int _skinID, float scale = 0.8f, Action _onComplete = null, string motionName = "idle", bool isLh = false)
 	{
 		if (skinID == _skinID)
-		{ 
+		{
 			//閬垮厤閲嶅鍒涘缓
+			if (skeletonGraphic != null)
+			{
+				SetMaterialNone();
+				if (isLh)
+				{
+					var skinConfigTmp = HeroSkinConfig.Get(skinID);
+					if (skinConfigTmp != null && skinConfigTmp.Tachie.IsSpine())
+					{
+						skeletonGraphic.enabled = true;
+					}
+				}
+				else
+				{
+					skeletonGraphic.enabled = true;
+				}
+			}
 			return;
+		}
+
+		if (skeletonGraphic != null)
+		{
+			skeletonGraphic.enabled = false;
 		}
 
 		skinID = _skinID;
-		onComplete = _onComplete;
-		pool = GameObjectPoolManager.Instance.RequestPool(UILoader.LoadPrefab("UIHero"));
-		
-		if (!transform.gameObject.activeSelf)
-		{
-			transform.SetActive(true);
-		}
-		if (instanceGO == null)
-		{ 
-			instanceGO = pool.Request();
-			instanceGO.transform.SetParent(transform);
-			//transform 鐨凱ivot Y鏄�0锛岃instanceGO 灞呬腑
-			instanceGO.transform.localPosition = new Vector3(0, instanceGO.GetComponent<RectTransform>().sizeDelta.y * 0.5f);
-
-			//instanceGO.transform.localPosition = Vector3.zero;
-			instanceGO.transform.localScale = Vector3.one;
-			instanceGO.transform.localRotation = Quaternion.identity;
-		}
-
-		skeletonGraphic = instanceGO.GetComponentInChildren<SkeletonGraphic>(true);
 		var skinConfig = HeroSkinConfig.Get(skinID);
 		if (isLh)
 		{
-			skeletonGraphic.skeletonDataAsset = ResManager.Instance.LoadAsset<SkeletonDataAsset>("Hero/SpineRes/", skinConfig.Tachie);
-		}
-		else
-		{ 
-			skeletonGraphic.skeletonDataAsset = ResManager.Instance.LoadAsset<SkeletonDataAsset>("Hero/SpineRes/", skinConfig.SpineRes);
-		}
-		if (skeletonGraphic.skeletonDataAsset == null)
-		{
 
-			transform.SetActive(false);
-			if (pool != null)
-				pool.Release(instanceGO);
-			skeletonGraphic = null;
-			Destroy(instanceGO);
-			Debug.LogError("鏈厤缃畇pine");
-			return;
-		}
-		skeletonGraphic.Initialize(true);
-		if (isLh)
-		{
 			//X杞村亸绉伙紝Y杞村亸绉伙紝缂╂斁锛屾槸鍚︽按骞崇炕杞紙0鍚�1鏄級
 			if (skinConfig.TachieParam.Length == 4)
 			{
@@ -79,47 +76,292 @@
 				this.transform.localRotation = Quaternion.identity;
 			}
 
+			//绔嬬粯鐗规畩澶勭悊锛屾病鏈塻pine鍔ㄧ敾鐨勬敼鐢ㄥ浘鐗�
+			var lhImg = this.AddMissingComponent<RawImage>();
+			if (!skinConfig.Tachie.IsSpine())
+			{
+				//鍥剧墖鏇挎崲
+				lhImg.SetTexture2DPNG(skinConfig.Tachie);
+				if (skeletonGraphic != null)
+				{
+					skeletonGraphic.enabled = false;
+				}
+				lhImg.raycastTarget = false;
+				return;
+			}
+			else
+			{
+				if (skeletonGraphic != null)
+				{
+					skeletonGraphic.enabled = true;
+				}
+				lhImg.enabled = false;
+			}
 		}
 		else
 		{
 			this.transform.localScale = Vector3.one * scale;
 		}
+
+		onComplete = _onComplete;
+
+
+		// 鍙栨秷涔嬪墠鐨勫紓姝ヤ换鍔★紝閬垮厤澶氭璋冪敤瀵艰嚧閿欎贡
+		CancelLoadTask();
+		// 鍒涘缓鏂扮殑鍙栨秷浠ょ墝
+		loadCancellationToken = new System.Threading.CancellationTokenSource();
+		// 浣跨敤 UniTask 杩涜寮傛鍒濆鍖栵紝灏唅nstanceGO鍒涘缓鍜岃祫婧愬姞杞介兘绉诲埌寮傛澶勭悊
+		DelayedInitializeAsync(skinConfig, motionName, isLh, loadCancellationToken.Token).Forget();
+	}
+#pragma warning restore CS1998
+
+	/// <summary>
+	/// 鍙栨秷涔嬪墠鐨勫姞杞戒换鍔�
+	/// </summary>
+	private void CancelLoadTask()
+	{
+		if (loadCancellationToken != null && !loadCancellationToken.IsCancellationRequested)
+		{
+			loadCancellationToken.Cancel();
+			loadCancellationToken.Dispose();
+		}
+	}
+
+	public async UniTask CreateAsync(int _skinID, float scale = 0.8f, Action _onComplete = null, string motionName = "idle", bool isLh = false)
+	{
+		if (skinID == _skinID)
+		{
+			//閬垮厤閲嶅鍒涘缓
+
+			if (skeletonGraphic != null)
+			{
+				SetMaterialNone();
+				if (isLh)
+				{
+					var skinConfigTmp = HeroSkinConfig.Get(skinID);
+					if (skinConfigTmp != null && skinConfigTmp.Tachie.Contains("SkeletonData"))
+					{
+						skeletonGraphic.enabled = true;
+					}
+				}
+				else
+				{
+					skeletonGraphic.enabled = true;
+				}
+			}
+			return;
+		}
+
+		skinID = _skinID;
+		var skinConfig = HeroSkinConfig.Get(skinID);
+		if (isLh)
+		{
+
+			//X杞村亸绉伙紝Y杞村亸绉伙紝缂╂斁锛屾槸鍚︽按骞崇炕杞紙0鍚�1鏄級
+			if (skinConfig.TachieParam.Length == 4)
+			{
+				this.transform.localPosition = new Vector3(skinConfig.TachieParam[0], skinConfig.TachieParam[1], 0);
+				this.transform.localScale = Vector3.one * skinConfig.TachieParam[2];
+				this.transform.localRotation = Quaternion.Euler(0, skinConfig.TachieParam[3] == 0 ? 0 : 180, 0);
+			}
+			else
+			{
+				this.transform.localPosition = Vector3.zero;
+				this.transform.localScale = Vector3.one;
+				this.transform.localRotation = Quaternion.identity;
+			}
+
+			//绔嬬粯鐗规畩澶勭悊锛屾病鏈塻pine鍔ㄧ敾鐨勬敼鐢ㄥ浘鐗�
+			var lhImg = this.AddMissingComponent<RawImage>();
+			if (!skinConfig.Tachie.Contains("SkeletonData"))
+			{
+				//鍥剧墖鏇挎崲
+				lhImg.SetTexture2DPNG(skinConfig.Tachie);
+				lhImg.SetNativeSize();
+				if (skeletonGraphic != null)
+				{
+					skeletonGraphic.enabled = false;
+				}
+				lhImg.enabled = true;
+				lhImg.raycastTarget = false;
+				return;
+			}
+			else
+			{
+				if (skeletonGraphic != null)
+				{
+					skeletonGraphic.enabled = true;
+				}
+				lhImg.enabled = false;
+			}
+		}
+		else
+		{
+			this.transform.localScale = Vector3.one * scale;
+		}
+
+		onComplete = _onComplete;
+		if (cachedUIHeroPool == null)
+			cachedUIHeroPool = GameObjectPoolManager.Instance.GetPool(await UILoader.LoadPrefabAsync("UIHero"));
+		pool = cachedUIHeroPool;
+		if (this == null) return;
+
+		if (!transform.gameObject.activeSelf)
+		{
+			transform.SetActive(true);
+		}
+		if (instanceGO == null)
+		{
+			instanceGO = pool.Request();
+			instanceGO.transform.SetParent(transform);
+			_instanceRect = instanceGO.GetComponent<RectTransform>();
+			//transform 鐨凱ivot Y鏄�0锛岃instanceGO 灞呬腑
+			instanceGO.transform.localPosition = new Vector3(0, _instanceRect.sizeDelta.y * 0.5f);
+
+			//instanceGO.transform.localPosition = Vector3.zero;
+			instanceGO.transform.localScale = Vector3.one;
+			instanceGO.transform.localRotation = Quaternion.identity;
+		}
+
+		skeletonGraphic = instanceGO.GetComponentInChildren<SkeletonGraphic>(true);
+		if (isLh)
+		{
+			skeletonGraphic.skeletonDataAsset = await ResManager.Instance.LoadAssetAsync<SkeletonDataAsset>("Hero/SpineRes/", skinConfig.Tachie);
+		}
+		else
+		{
+			skeletonGraphic.skeletonDataAsset = await ResManager.Instance.LoadAssetAsync<SkeletonDataAsset>("Hero/SpineRes/", skinConfig.SpineRes);
+		}
+		if (skeletonGraphic.skeletonDataAsset == null)
+		{
+			transform.SetActive(false);
+			if (pool != null)
+				pool.Release(instanceGO);
+			skeletonGraphic = null;
+			Destroy(instanceGO);
+			Debug.LogError("鏈厤缃畇pine");
+			return;
+		}
+		skeletonGraphic.initialSkinName = skinConfig.InitialSkinName;
+		skeletonGraphic.Initialize(true);
+		// 鍒濆鍖栧畬鎴愬悗璁剧疆鐨偆
+		if (!string.IsNullOrEmpty(skinConfig.InitialSkinName))
+		{
+			var skeleton = skeletonGraphic.Skeleton;
+			skeleton.SetSkin(skinConfig.InitialSkinName);
+			skeleton.SetSlotsToSetupPose();
+			skeletonGraphic.Update(0);
+		}
+
+		skeletonGraphic.enabled = true;
+		// 娉ㄥ唽鍒癝pineUpdateManager锛屾壒閲忔洿鏂板噺灏戣法璇█璋冪敤寮�閿�
+		SpineUpdateManager.Instance.Register(skeletonGraphic);
+		// 涓嶅彲瑙佹椂瀹屽叏鍋滄鏇存柊锛屾粴鍔ㄥ垪琛ㄥ満鏅敹鐩婂緢澶�
+		skeletonGraphic.updateWhenInvisible = Spine.Unity.UpdateMode.Nothing;
+		SetMaterialNone();
+
 		spineAnimationState = skeletonGraphic.AnimationState;
 		spineAnimationState.Data.DefaultMix = 0f;
 		if (motionName == "")
 			motionName = GetFistSpineAnim();
+
 		PlayAnimation(motionName, true);
 		spineAnimationState.Complete -= OnAnimationComplete;
 		spineAnimationState.Complete += OnAnimationComplete;
+
+#if UNITY_EDITOR
+		await UniTask.Delay(100);
+		if (skeletonGraphic != null && skeletonGraphic.material != null)
+		{
+			skeletonGraphic.material.shader = Shader.Find(skeletonGraphic.material.shader.name);
+		}
+#endif
 	}
 
 
+	public bool HasAnimation(string motionName)
+	{
+		if (skeletonGraphic == null || skeletonGraphic.Skeleton == null)
+		{
+			Debug.LogWarning("skeletonGraphic or Skeleton is null, cannot check animation: " + motionName);
+			return false;
+		}
+		return skeletonGraphic.Skeleton.ContainsMotion(motionName);
+	}
 
 
 	protected void OnDestroy()
 	{
-        if (spineAnimationState != null)
-        {
-            spineAnimationState.Complete -= OnAnimationComplete;
-        }
+		// 鍙栨秷姝e湪杩涜鐨勫姞杞戒换鍔�
+		CancelLoadTask();
+
+		if (spineAnimationState != null)
+		{
+			spineAnimationState.Complete -= OnAnimationComplete;
+		}
+		// 浠嶴pineUpdateManager涓Щ闄�
+		if (skeletonGraphic != null)
+			SpineUpdateManager.Instance.Unregister(skeletonGraphic);
 		if (pool != null)
 			pool.Release(instanceGO);
 		skeletonGraphic = null;
 		pool = null;
 	}
 
+	private string pendingAnimationName = null;
+	private bool pendingAnimationLoop = false;
+	private bool pendingAnimationReplay = true;
+	private float? pendingSpeed = null;
+	private bool pendingEnabled = true; // 鏀逛负鏅�歜ool锛宖alse琛ㄧず鏈缃紝true琛ㄧず闇�瑕佸惎鐢�
+	private bool pendingGray = false; // 鏀逛负鏅�歜ool锛岃〃绀烘槸鍚﹂渶瑕佽缃伆搴�
 
-    public virtual void PlayAnimation(string motionName, bool loop = false)
-    {
-        if (spineAnimationState == null) return;
+	/// <summary>
+	/// 鎾斁 Spine 鍔ㄧ敾
+	/// </summary>
+	/// <param name="motionName">鍔ㄤ綔鍚�</param>
+	/// <param name="loop">寰幆</param>
+	/// <param name="replay">濡傛灉鐩稿悓鍔ㄤ綔鏄惁鍐嶆閲嶆挱锛屾瘮濡傝窇姝ラ噸鎾氨浼氳烦甯т笉椤烘粦</param>
+	public virtual TrackEntry PlayAnimation(string motionName, bool loop = false, bool replay = true)
+	{
+		// 濡傛灉姝e湪鍒濆鍖栦腑锛屼繚瀛樺姩鐢诲弬鏁帮紝绛夊緟鍒濆鍖栧畬鎴愬悗鍐嶆挱鏀�
+		if (isInitializing)
+		{
+			pendingAnimationName = motionName;
+			pendingAnimationLoop = loop;
+			pendingAnimationReplay = replay;
+			return null;
+		}
+		
+		if (spineAnimationState == null) 
+		{
+			Debug.LogWarning("spineAnimationState is null, cannot play animation: " + motionName);
+			return null;
+		}
+
+		if (GetCurrentAnimationName() == motionName && !replay)
+			return null;
 
 		// 鐩存帴浣跨敤 ToString() 鑰屼笉鏄皟鐢� GetAnimationName
-        spineAnimationState.SetAnimation(0, motionName.ToString(), loop);
-    }
+		try
+		{
+			return spineAnimationState.SetAnimation(0, motionName.ToString(), loop);
+		}
+		catch (System.Exception e)
+		{
+			Debug.LogError("鎾斁鍔ㄧ敾澶辫触: " + motionName + ", 閿欒: " + e.Message);
+			return null;
+		}
+	}
 
 	// 鎾斁绗竴涓姩鐢伙紙浣滀负榛樿鍔ㄧ敾锛�
 	string GetFistSpineAnim()
 	{
+		if (skeletonGraphic == null || skeletonGraphic.Skeleton == null)
+		{
+			Debug.LogWarning("skeletonGraphic or Skeleton is null, cannot get first animation");
+			return "idle"; // 杩斿洖榛樿鍔ㄧ敾鍚嶇О
+		}
+		
 		var skeletonData = skeletonGraphic.Skeleton.Data;
 		if (skeletonData.Animations.Count > 0)
 		{
@@ -129,8 +371,23 @@
 		{
 			Debug.LogError("Spine 鏁版嵁涓病鏈夋壘鍒颁换浣曞姩鐢伙紒姝﹀皢鐨偆锛�" + skinID);
 		}
-		return "";
-    }
+		return "idle"; // 杩斿洖榛樿鍔ㄧ敾鍚嶇О
+	}
+
+	/// <summary>
+	/// 鑾峰彇褰撳墠姝e湪鎾斁鐨� Spine 鍔ㄧ敾鍚嶇О
+	/// </summary>
+	/// <returns>褰撳墠鍔ㄧ敾鍚嶇О锛屽鏋滄病鏈夊姩鐢诲垯杩斿洖绌哄瓧绗︿覆</returns>
+	public string GetCurrentAnimationName()
+	{
+		if (spineAnimationState == null || spineAnimationState.GetCurrent(0) == null)
+		{
+			return string.Empty;
+		}
+		return spineAnimationState.GetCurrent(0).Animation.Name;
+	}
+
+
 
 	/// <summary>
 	/// 鍔ㄧ敾瀹屾垚浜嬩欢澶勭悊
@@ -140,4 +397,318 @@
 		onComplete?.Invoke();
 	}
 
+	//瓒婂ぇ瓒婂揩
+	public void SetSpeed(float speed)
+	{
+		// 濡傛灉姝e湪鍒濆鍖栦腑锛屼繚瀛橀�熷害鍙傛暟锛岀瓑寰呭垵濮嬪寲瀹屾垚鍚庡啀璁剧疆
+		if (isInitializing)
+		{
+			pendingSpeed = speed;
+			return;
+		}
+		
+		if (spineAnimationState == null)
+		{
+			Debug.LogWarning("spineAnimationState is null, cannot set speed");
+			return;
+		}
+		spineAnimationState.TimeScale = speed;
+	}
+
+	public void SetEnabled(bool isEnable)
+	{
+		// 濡傛灉姝e湪鍒濆鍖栦腑锛屼繚瀛樺惎鐢ㄧ姸鎬侊紝绛夊緟鍒濆鍖栧畬鎴愬悗鍐嶈缃�
+		if (isInitializing)
+		{
+			pendingEnabled = isEnable;
+			return;
+		}
+		
+		if (skeletonGraphic == null)
+		{
+			Debug.LogWarning("skeletonGraphic is null, cannot set enabled state");
+			return;
+		}
+		skeletonGraphic.enabled = isEnable;
+	}
+
+	public void SetGray()
+	{
+		// 濡傛灉姝e湪鍒濆鍖栦腑锛屾爣璁伴渶瑕佽缃伆搴︼紝绛夊緟鍒濆鍖栧畬鎴愬悗鍐嶈缃�
+		if (isInitializing)
+		{
+			pendingGray = true;
+			return;
+		}
+		
+		if (skeletonGraphic == null)
+		{
+			Debug.LogWarning("skeletonGraphic is null, cannot set gray material");
+			return;
+		}
+		skeletonGraphic.material = MaterialUtility.GetDefaultSpriteGrayMaterial();
+	}
+	public void SetMaterialNone()
+	{
+		// 濡傛灉姝e湪鍒濆鍖栦腑锛屾爣璁伴渶瑕佽缃棤鏉愯川锛岀瓑寰呭垵濮嬪寲瀹屾垚鍚庡啀璁剧疆
+		if (isInitializing)
+		{
+			pendingGray = false;
+			return;
+		}
+		
+		if (skeletonGraphic == null)
+		{
+			Debug.LogWarning("skeletonGraphic is null, cannot set material to none");
+			return;
+		}
+		skeletonGraphic.material = GetDefaultSpineMaterial();
+	}
+
+	/// <summary>
+	/// 鑾峰彇榛樿鐨� Spine 娓叉煋鏉愯川銆�
+	/// 瀵逛簬鍖呭惈闈� Normal 娣峰悎妯″紡锛圓dditive/Multiply/Screen锛夋彃妲界殑瑙掕壊锛�
+	/// 杩斿洖 atlas 鍘熷鏉愯川锛圔lend One OneMinusSrcAlpha锛夛紝淇濊瘉 PMA 娣峰悎姝g‘锛�
+	/// 瀵逛簬鏅�氳鑹诧紝杩斿洖 null锛堜娇鐢� Canvas 榛樿鏉愯川锛岃涓轰笉鍙橈級銆�
+	/// </summary>
+	private Material GetDefaultSpineMaterial()
+	{
+		if (skeletonGraphic == null || skeletonGraphic.Skeleton == null)
+			return null;
+
+		var slotsData = skeletonGraphic.Skeleton.Data.Slots;
+		for (int i = 0; i < slotsData.Count; i++)
+		{
+			if (slotsData.Items[i].BlendMode != Spine.BlendMode.Normal)
+			{
+				// 瀛樺湪闈� Normal 娣峰悎妯″紡鐨勬彃妲斤紝蹇呴』浣跨敤 Spine 鏉愯川
+				// Canvas 榛樿鏉愯川鐨� Blend SrcAlpha OneMinusSrcAlpha 浼氬鑷�
+				// PMA Additive 鏁堟灉锛坴ertex alpha=0锛夊畬鍏ㄦ秷澶�
+				var dataAsset = skeletonGraphic.skeletonDataAsset;
+				if (dataAsset != null && dataAsset.atlasAssets.Length > 0)
+					return dataAsset.atlasAssets[0].PrimaryMaterial;
+				break;
+			}
+		}
+		return null;
+	}
+
+	/// <summary>
+	/// 寤惰繜鍒濆鍖栵紝缁撳悎骞跺彂鎺у埗鍜屽垎甯у欢杩�
+	/// 1. 璧勬簮鍔犺浇浣跨敤鐪熸鐨勫紓姝ワ紙LoadAssetAsync锛�
+	/// 2. skeletonGraphic.Initialize() 鍓嶈繘琛屽垎甯у欢杩燂紝閬垮厤涓荤嚎绋嬪崱椤�
+	/// </summary>
+	private async UniTaskVoid DelayedInitializeAsync(HeroSkinConfig skinConfig, string motionName, bool isLh, System.Threading.CancellationToken cancellationToken)
+	{
+		isInitializing = true;
+		try
+		{
+			// 妫�鏌ユ槸鍚﹀凡琚彇娑�
+			cancellationToken.ThrowIfCancellationRequested();
+
+			// 鑾峰彇鍔犺浇淇″彿閲� - 闄愬埗骞跺彂鏁帮紝閬垮厤璧勬簮绔炰簤
+			await AcquireLoadSlotAsync(cancellationToken);
+			// 寮傛鍒涘缓instanceGO鍜屽姞杞借祫婧愶紙鐪熸鐨勫紓姝ワ紝涓嶉樆濉烇級
+			await CreateInstanceAndLoadAssetsAsync(skinConfig, isLh, cancellationToken);
+			// 鍐嶆妫�鏌ユ槸鍚﹀凡琚彇娑�
+			cancellationToken.ThrowIfCancellationRequested();
+
+			// 纭繚姣忓抚鏈�澶氭墽琛�1娆nitialize(true)锛岄伩鍏嶅悓甯уぇ閲忛楠艰В鏋愬鑷村崱椤�
+			while (Time.frameCount == lastInitFrame)
+			{
+				cancellationToken.ThrowIfCancellationRequested();
+				await UniTask.NextFrame(cancellationToken);
+			}
+			lastInitFrame = Time.frameCount;
+
+			if (skeletonGraphic == null || skeletonGraphic.skeletonDataAsset == null)
+			{
+				Debug.LogError("璧勬簮鍔犺浇澶辫触锛屾棤娉曞垵濮嬪寲妯″瀷");
+				return;
+			}
+
+			skeletonGraphic.initialSkinName = skinConfig.InitialSkinName;
+			skeletonGraphic.Initialize(true);
+			Debug.Log($"[UIHeroController] Spine Initialize瀹屾垚, skeleton valid: {skeletonGraphic.IsValid}, enabled: {skeletonGraphic.enabled}");
+
+			// 鍒濆鍖栧畬鎴愬悗璁剧疆鐨偆
+			if (!string.IsNullOrEmpty(skinConfig.InitialSkinName))
+			{
+				var skeleton = skeletonGraphic.Skeleton;
+				skeleton.SetSkin(skinConfig.InitialSkinName);
+				skeleton.SetSlotsToSetupPose();
+				skeletonGraphic.Update(0);
+			}
+
+			spineAnimationState = skeletonGraphic.AnimationState;
+			spineAnimationState.Data.DefaultMix = 0f;
+
+			// 鍒濆鍖栧畬鎴愬悗鎵嶆樉绀烘ā鍨�
+			skeletonGraphic.enabled = pendingEnabled;
+
+			// 娉ㄥ唽鍒癝pineUpdateManager锛屾壒閲忔洿鏂板噺灏戣法璇█璋冪敤寮�閿�
+			SpineUpdateManager.Instance.Register(skeletonGraphic);
+			// 涓嶅彲瑙佹椂瀹屽叏鍋滄鏇存柊锛屾粴鍔ㄥ垪琛ㄥ満鏅敹鐩婂緢澶�
+			skeletonGraphic.updateWhenInvisible = Spine.Unity.UpdateMode.Nothing;
+
+			if (pendingGray)
+			{
+				skeletonGraphic.material = MaterialUtility.GetDefaultSpriteGrayMaterial();
+			}
+			else
+			{
+				skeletonGraphic.material = GetDefaultSpineMaterial();
+			}
+
+			// 妫�鏌ユ槸鍚︽湁寰呰缃殑閫熷害锛屽鏋滄湁鍒欒缃�
+			if (pendingSpeed.HasValue)
+			{
+				spineAnimationState.TimeScale = pendingSpeed.Value;
+				pendingSpeed = null;
+			}
+
+			// 妫�鏌ユ槸鍚︽湁寰呮挱鏀剧殑鍔ㄧ敾锛屽鏋滄湁鍒欎紭鍏堟挱鏀惧閮ㄨ皟鐢ㄧ殑鍔ㄧ敾
+			if (!string.IsNullOrEmpty(pendingAnimationName))
+			{
+				isInitializing = false;
+				PlayAnimation(pendingAnimationName, pendingAnimationLoop, pendingAnimationReplay);
+				// 娓呴櫎鎵�鏈夊緟鎾斁鍔ㄧ敾鍙傛暟
+				pendingAnimationName = null;
+				pendingAnimationLoop = false;
+				pendingAnimationReplay = true;
+			}
+			else
+			{
+				// 濡傛灉娌℃湁澶栭儴璋冪敤鐨勫姩鐢伙紝鎾斁榛樿鍔ㄧ敾
+				if (motionName == "")
+					motionName = GetFistSpineAnim();
+
+				isInitializing = false;
+				PlayAnimation(motionName, true);
+			}
+
+			spineAnimationState.Complete -= OnAnimationComplete;
+			spineAnimationState.Complete += OnAnimationComplete;
+
+			isInitialized = true;
+			isInitializing = false;
+		}
+		catch (System.OperationCanceledException)
+		{
+			// 浠诲姟琚彇娑堬紝姝e父杩斿洖
+			isInitializing = false;
+		}
+		catch (System.Exception e)
+		{
+			Debug.LogError($"鑻遍泟鍒濆鍖栧紓甯�: {e.Message}\n{e.StackTrace}");
+			isInitializing = false;
+		}
+		finally
+		{
+			// 閲婃斁鍔犺浇妲戒綅
+			ReleaseLoadSlot();
+		}
+	}
+
+	/// <summary>
+	/// 鑾峰彇鍔犺浇妲戒綅锛堟敮鎸� WebGL 鐨勫苟鍙戞帶鍒讹級
+	/// </summary>
+	private async UniTask AcquireLoadSlotAsync(System.Threading.CancellationToken cancellationToken)
+	{
+		while (true)
+		{
+			// 妫�鏌ユ槸鍚﹀凡琚彇娑�
+			cancellationToken.ThrowIfCancellationRequested();
+
+			lock (loadLock)
+			{
+				if (currentLoadingCount < MAX_CONCURRENT_LOADS)
+				{
+					currentLoadingCount++;
+					return;
+				}
+			}
+			// 濡傛灉宸茶揪鍒版渶澶у苟鍙戞暟锛岀瓑寰呬笅涓�甯у啀璇�
+			await UniTask.NextFrame(cancellationToken);
+		}
+	}
+
+	/// <summary>
+	/// 閲婃斁鍔犺浇妲戒綅
+	/// </summary>
+	private void ReleaseLoadSlot()
+	{
+		lock (loadLock)
+		{
+			currentLoadingCount--;
+		}
+	}
+
+
+	/// <summary>
+	/// 寮傛鍒涘缓instanceGO鍜屽姞杞借祫婧愶紙鐢ㄤ簬闈炵珛缁橈級
+	/// 浣跨敤鐪熸鐨勫紓姝ュ姞杞斤紝涓嶉樆濉炰富绾跨▼
+	/// </summary>
+	private async UniTask CreateInstanceAndLoadAssetsAsync(HeroSkinConfig skinConfig, bool isLh, System.Threading.CancellationToken cancellationToken)
+	{
+		// 纭繚transform澶勪簬婵�娲荤姸鎬�
+		if (!transform.gameObject.activeSelf)
+		{
+			transform.SetActive(true);
+		}
+
+		// 妫�鏌ユ槸鍚﹀凡琚彇娑�
+		cancellationToken.ThrowIfCancellationRequested();
+
+		// 鍒涘缓pool鍜宨nstanceGO锛堜娇鐢ㄧ紦瀛橀伩鍏嶉噸澶嶅姞杞介鍒朵綋锛�
+		if (cachedUIHeroPool == null)
+			cachedUIHeroPool = GameObjectPoolManager.Instance.GetPool(await UILoader.LoadPrefabAsync("UIHero"));
+		pool = cachedUIHeroPool;
+
+		if (instanceGO == null)
+		{
+			instanceGO = pool.Request();
+			instanceGO.transform.SetParent(transform);
+			_instanceRect = instanceGO.GetComponent<RectTransform>();
+			//transform 鐨凱ivot Y鏄�0锛岃instanceGO 灞呬腑
+			instanceGO.transform.localPosition = new Vector3(0, _instanceRect.sizeDelta.y * 0.5f);
+			instanceGO.transform.localScale = Vector3.one;
+			instanceGO.transform.localRotation = Quaternion.identity;
+		}
+
+		skeletonGraphic = instanceGO.GetComponentInChildren<SkeletonGraphic>(true);
+
+		// 鐪熸鐨勫紓姝ュ姞杞借祫婧� - 涓嶉樆濉炰富绾跨▼
+		string assetName = isLh ? skinConfig.Tachie : skinConfig.SpineRes;
+		Debug.Log($"[UIHeroController] 寮�濮嬪姞杞絪pine 璧勬簮: {assetName}");
+		SkeletonDataAsset loadedAsset = await ResManager.Instance.LoadAssetAsync<SkeletonDataAsset>("Hero/SpineRes/", assetName);
+
+		// 鍐嶆妫�鏌ユ槸鍚﹀凡琚彇娑�
+		cancellationToken.ThrowIfCancellationRequested();
+
+		if (loadedAsset != null)
+		{
+			skeletonGraphic.skeletonDataAsset = loadedAsset;
+			Debug.Log($"[UIHeroController] Spine璧勬簮鍔犺浇鎴愬姛: {assetName}, atlas count: {loadedAsset.atlasAssets?.Length}");
+		}
+		else
+		{
+			transform.SetActive(false);
+			if (pool != null)
+				pool.Release(instanceGO);
+			skeletonGraphic = null;
+			Destroy(instanceGO);
+			Debug.LogError("鏈厤缃畇pine");
+		}
+	}
+
+
+
+	/// <summary>
+	/// 妫�鏌ユ槸鍚﹀凡瀹屾垚鍒濆鍖�
+	/// </summary>
+	public bool IsInitialized()
+	{
+		return isInitialized && !isInitializing;
+	}
 }
\ No newline at end of file

--
Gitblit v1.8.0