From f4a702e212d1853735f8dae399da69d23bfa510e Mon Sep 17 00:00:00 2001
From: yyl <yyl>
Date: 星期四, 26 三月 2026 18:16:16 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into h5version
---
Main/System/Hero/UIHeroController.cs | 410 +++++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 348 insertions(+), 62 deletions(-)
diff --git a/Main/System/Hero/UIHeroController.cs b/Main/System/Hero/UIHeroController.cs
index 3c89fe5..687b490 100644
--- a/Main/System/Hero/UIHeroController.cs
+++ b/Main/System/Hero/UIHeroController.cs
@@ -1,10 +1,10 @@
using System;
-using Cysharp.Threading.Tasks;
using Spine;
using Spine.Unity;
using UnityEngine;
using UnityEngine.UI;
+using Cysharp.Threading.Tasks;
public class UIHeroController : MonoBehaviour
{
@@ -14,6 +14,16 @@
public Spine.AnimationState spineAnimationState;
private GameObject instanceGO;
+ private bool isInitializing = false;
+ private bool isInitialized = false;
+ private System.Threading.CancellationTokenSource loadCancellationToken; // 鐢ㄤ簬鍙栨秷涔嬪墠鐨勫姞杞戒换鍔�
+
+ // 浣跨敤 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 initializationOrder = 0; // 鐢ㄤ簬鍒嗗抚寤惰繜鐨勫簭鍙�
public Action onComplete;
public async UniTask Create(int _skinID, float scale = 0.8f, Action _onComplete = null, string motionName = "idle", bool isLh = false)
@@ -39,6 +49,11 @@
}
}
return;
+ }
+
+ if (skeletonGraphic != null)
+ {
+ skeletonGraphic.enabled = false;
}
skinID = _skinID;
@@ -90,66 +105,26 @@
}
onComplete = _onComplete;
- pool = GameObjectPoolManager.Instance.GetPool(await UILoader.LoadPrefabAsync("UIHero"));
- if (!transform.gameObject.activeSelf)
+
+ // 鍙栨秷涔嬪墠鐨勫紓姝ヤ换鍔★紝閬垮厤澶氭璋冪敤瀵艰嚧閿欎贡
+ CancelLoadTask();
+ // 鍒涘缓鏂扮殑鍙栨秷浠ょ墝
+ loadCancellationToken = new System.Threading.CancellationTokenSource();
+ // 浣跨敤 UniTask 杩涜寮傛鍒濆鍖栵紝灏唅nstanceGO鍒涘缓鍜岃祫婧愬姞杞介兘绉诲埌寮傛澶勭悊
+ DelayedInitializeAsync(skinConfig, motionName, isLh, loadCancellationToken.Token).Forget();
+ }
+
+ /// <summary>
+ /// 鍙栨秷涔嬪墠鐨勫姞杞戒换鍔�
+ /// </summary>
+ private void CancelLoadTask()
+ {
+ if (loadCancellationToken != null && !loadCancellationToken.IsCancellationRequested)
{
- transform.SetActive(true);
+ loadCancellationToken.Cancel();
+ loadCancellationToken.Dispose();
}
- 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);
- 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;
- SetMaterialNone();
-
- spineAnimationState = skeletonGraphic.AnimationState;
- spineAnimationState.Data.DefaultMix = 0f;
- if (motionName == "")
- motionName = GetFistSpineAnim();
-
- PlayAnimation(motionName, true);
- spineAnimationState.Complete -= OnAnimationComplete;
- spineAnimationState.Complete += OnAnimationComplete;
}
public async UniTask CreateAsync(int _skinID, float scale = 0.8f, Action _onComplete = null, string motionName = "idle", bool isLh = false)
@@ -299,12 +274,20 @@
public bool HasAnimation(string motionName)
{
- return skeletonGraphic != null && skeletonGraphic.Skeleton != null && skeletonGraphic.Skeleton.ContainsMotion(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()
{
+ // 鍙栨秷姝e湪杩涜鐨勫姞杞戒换鍔�
+ CancelLoadTask();
+
if (spineAnimationState != null)
{
spineAnimationState.Complete -= OnAnimationComplete;
@@ -315,6 +298,13 @@
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锛岃〃绀烘槸鍚﹂渶瑕佽缃伆搴�
+
/// <summary>
/// 鎾斁 Spine 鍔ㄧ敾
/// </summary>
@@ -323,18 +313,45 @@
/// <param name="replay">濡傛灉鐩稿悓鍔ㄤ綔鏄惁鍐嶆閲嶆挱锛屾瘮濡傝窇姝ラ噸鎾氨浼氳烦甯т笉椤烘粦</param>
public virtual TrackEntry PlayAnimation(string motionName, bool loop = false, bool replay = true)
{
- if (spineAnimationState == null) return null;
+ // 濡傛灉姝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
- return 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)
{
@@ -344,7 +361,7 @@
{
Debug.LogError("Spine 鏁版嵁涓病鏈夋壘鍒颁换浣曞姩鐢伙紒姝﹀皢鐨偆锛�" + skinID);
}
- return "";
+ return "idle"; // 杩斿洖榛樿鍔ㄧ敾鍚嶇О
}
/// <summary>
@@ -373,13 +390,33 @@
//瓒婂ぇ瓒婂揩
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;
@@ -387,10 +424,259 @@
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 = 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);
+
+ // 鑾峰彇褰撳墠搴忓彿鐢ㄤ簬鍒嗗抚寤惰繜
+ int myOrder;
+ lock (loadLock)
+ {
+ myOrder = initializationOrder++;
+ }
+
+ // 鍐嶆妫�鏌ユ槸鍚﹀凡琚彇娑�
+ cancellationToken.ThrowIfCancellationRequested();
+
+ // 鍦� skeletonGraphic.Initialize() 鍓嶈繘琛屽垎甯у欢杩�
+ // 鏍规嵁 MAX_CONCURRENT_LOADS 璋冩暣寤惰繜锛岄伩鍏嶆墍鏈夊璞″悓鏃舵墽琛� Initialize
+ int delayFrames = (myOrder % MAX_CONCURRENT_LOADS);
+ if (delayFrames > 0)
+ {
+ for (int i = 0; i < delayFrames; i++)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ await UniTask.NextFrame(cancellationToken);
+ }
+ }
+
+ // 鍐嶆妫�鏌ユ槸鍚﹀凡琚彇娑堬紙鍙兘鍦ㄥ欢杩熸湡闂磋鍙栨秷锛�
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (skeletonGraphic == null || skeletonGraphic.skeletonDataAsset == null)
+ {
+ Debug.LogError("璧勬簮鍔犺浇澶辫触锛屾棤娉曞垵濮嬪寲妯″瀷");
+ 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);
+ }
+
+ spineAnimationState = skeletonGraphic.AnimationState;
+ spineAnimationState.Data.DefaultMix = 0f;
+
+ // 鍒濆鍖栧畬鎴愬悗鎵嶆樉绀烘ā鍨�
+ skeletonGraphic.enabled = pendingEnabled;
+
+ if (pendingGray)
+ {
+ skeletonGraphic.material = MaterialUtility.GetDefaultSpriteGrayMaterial();
+ }
+ else
+ {
+ skeletonGraphic.material = null;
+ }
+
+ // 妫�鏌ユ槸鍚︽湁寰呰缃殑閫熷害锛屽鏋滄湁鍒欒缃�
+ 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}");
+ 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
+ pool = GameObjectPoolManager.Instance.GetPool(UILoader.LoadPrefab("UIHero"));
+
+ 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.localScale = Vector3.one;
+ instanceGO.transform.localRotation = Quaternion.identity;
+ }
+
+ skeletonGraphic = instanceGO.GetComponentInChildren<SkeletonGraphic>(true);
+
+ // 鐪熸鐨勫紓姝ュ姞杞借祫婧� - 涓嶉樆濉炰富绾跨▼
+ string assetName = isLh ? skinConfig.Tachie : skinConfig.SpineRes;
+ SkeletonDataAsset loadedAsset = await ResManager.Instance.LoadAssetAsync<SkeletonDataAsset>("Hero/SpineRes/", assetName);
+
+ // 鍐嶆妫�鏌ユ槸鍚﹀凡琚彇娑�
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (loadedAsset != null)
+ {
+ skeletonGraphic.skeletonDataAsset = loadedAsset;
+ }
+ 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