Main/System/Hero/UIHeroController.cs
@@ -4,6 +4,7 @@
using Spine.Unity;
using UnityEngine;
using UnityEngine.UI;
using Cysharp.Threading.Tasks;
public class UIHeroController : MonoBehaviour
{
@@ -13,6 +14,10 @@
   public Spine.AnimationState spineAnimationState;
   private GameObject instanceGO;
   private bool isInitializing = false;
   private bool isInitialized = false;
   private static int activeInitializationCount = 0; // 当前正在初始化的卡片数量
   private static readonly object initializationLock = new object();
   public Action onComplete;
   public void Create(int _skinID, float scale = 0.8f, Action _onComplete = null, string motionName = "idle", bool isLh = false)
@@ -127,33 +132,41 @@
         Debug.LogError("未配置spine");
         return;
      }
      skeletonGraphic.initialSkinName = skinConfig.InitialSkinName;
      skeletonGraphic.Initialize(true);
      // 初始化完成后设置皮肤
      if (!string.IsNullOrEmpty(skinConfig.InitialSkinName))
      // 使用 UniTask 进行延迟初始化,避免批量创建时卡顿
      if (isInitializing)
      {
         var skeleton = skeletonGraphic.Skeleton;
         skeleton.SetSkin(skinConfig.InitialSkinName);
         skeleton.SetSlotsToSetupPose();
         skeletonGraphic.Update(0);
         // 如果正在初始化,设置标志位取消之前的任务
         isInitializing = false;
      }
      skeletonGraphic.enabled = true;
      SetMaterialNone();
      spineAnimationState = skeletonGraphic.AnimationState;
      spineAnimationState.Data.DefaultMix = 0f;
      if (motionName == "")
         motionName = GetFistSpineAnim();
      PlayAnimation(motionName, true);
      spineAnimationState.Complete -= OnAnimationComplete;
      spineAnimationState.Complete += OnAnimationComplete;
      // 立绘需要立即显示,其他情况延迟初始化
      if (isLh)
      {
         // 立绘立即初始化
         ForceInitialize(motionName);
      }
      else
      {
         // 在加载新模型前先隐藏当前显示的模型(非立绘情况)
         if (skeletonGraphic != null)
         {
            skeletonGraphic.enabled = false;
         }
         // 使用 UniTask 进行异步初始化
         DelayedInitializeAsync(skinConfig, motionName).Forget();
      }
   }
   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);
   }
@@ -169,6 +182,13 @@
      pool = null;
   }
   private string pendingAnimationName = null;
   private bool pendingAnimationLoop = false;
   private bool pendingAnimationReplay = true;
   private float? pendingSpeed = null;
   private bool pendingEnabled = true; // 改为普通bool,false表示未设置,true表示需要启用
   private bool pendingGray = false; // 改为普通bool,表示是否需要设置灰度
   /// <summary>
   /// 播放 Spine 动画
   /// </summary>
@@ -177,18 +197,45 @@
   /// <param name="replay">如果相同动作是否再次重播,比如跑步重播就会跳帧不顺滑</param>
   public virtual TrackEntry PlayAnimation(string motionName, bool loop = false, bool replay = true)
   {
      if (spineAnimationState == null) return null;
      // 如果正在初始化中,保存动画参数,等待初始化完成后再播放
      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)
      {
@@ -198,7 +245,7 @@
      {
         Debug.LogError("Spine 数据中没有找到任何动画!武将皮肤:" + skinID);
      }
      return "";
      return "idle"; // 返回默认动画名称
   }
   /// <summary>
@@ -227,13 +274,33 @@
   //越大越快
   public void SetSpeed(float speed)
   {
      // 如果正在初始化中,保存速度参数,等待初始化完成后再设置
      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)
   {
      // 如果正在初始化中,保存启用状态,等待初始化完成后再设置
      if (isInitializing)
      {
         pendingEnabled = isEnable;
         return;
      }
      if (skeletonGraphic == null)
      {
         Debug.LogWarning("skeletonGraphic is null, cannot set enabled state");
         return;
      }
      skeletonGraphic.enabled = isEnable;
@@ -241,10 +308,191 @@
   public void SetGray()
   {
      // 如果正在初始化中,标记需要设置灰度,等待初始化完成后再设置
      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()
   {
      // 如果正在初始化中,标记需要设置无材质,等待初始化完成后再设置
      if (isInitializing)
      {
         pendingGray = false;
         return;
      }
      if (skeletonGraphic == null)
      {
         Debug.LogWarning("skeletonGraphic is null, cannot set material to none");
         return;
      }
      skeletonGraphic.material = null;
   }
   /// <summary>
   /// 延迟初始化,避免批量创建时卡顿 - 使用 UniTask
   /// </summary>
   private async UniTaskVoid DelayedInitializeAsync(HeroSkinConfig skinConfig, string motionName)
   {
      isInitializing = true;
      try
      {
         // 增加当前初始化计数器
         int currentIndex;
         lock (initializationLock)
         {
            currentIndex = activeInitializationCount++;
         }
         // 根据当前初始化序号计算延迟时间
         // 第一个卡片延迟1帧,第二个延迟2帧,以此类推,最多延迟10帧
         int delayFrames = Mathf.Min(currentIndex + 2, 80);
         for (int i = 0; i < delayFrames; i++)
         {
            await UniTask.NextFrame();
         }
         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能正常播放
            isInitializing = false;
            PlayAnimation(pendingAnimationName, pendingAnimationLoop, pendingAnimationReplay);
            // 清除所有待播放动画参数
            pendingAnimationName = null;
            pendingAnimationLoop = false;
            pendingAnimationReplay = true;
         }
         else
         {
            // 如果没有外部调用的动画,播放默认动画
            if (motionName == "")
               motionName = GetFistSpineAnim();
            // 临时设置isInitializing为false,以便PlayAnimation能正常播放
            isInitializing = false;
            PlayAnimation(motionName, true);
         }
         spineAnimationState.Complete -= OnAnimationComplete;
         spineAnimationState.Complete += OnAnimationComplete;
         isInitialized = true;
         isInitializing = false;
      }
      catch (System.OperationCanceledException)
      {
         // 任务被取消,正常处理
         isInitializing = false;
      }
      finally
      {
         // 减少当前初始化计数器
         lock (initializationLock)
         {
            activeInitializationCount--;
         }
      }
   }
   /// <summary>
   /// 强制立即初始化(用于特殊情况)
   /// </summary>
   public void ForceInitialize(string motionName = "idle")
   {
      if (isInitializing)
      {
         // 设置标志位取消之前的异步任务
         isInitializing = false;
      }
      var skinConfig = HeroSkinConfig.Get(skinID);
      if (skinConfig != null && skeletonGraphic != null)
      {
         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;
         if (spineAnimationState != null)
         {
            spineAnimationState.Data.DefaultMix = 0f;
            if (string.IsNullOrEmpty(motionName))
               motionName = GetFistSpineAnim();
            PlayAnimation(motionName, true);
            spineAnimationState.Complete -= OnAnimationComplete;
            spineAnimationState.Complete += OnAnimationComplete;
         }
         isInitialized = true;
         isInitializing = false;
      }
   }
   /// <summary>
   /// 检查是否已完成初始化
   /// </summary>
   public bool IsInitialized()
   {
      return isInitialized && !isInitializing;
   }
}