0312 优化所有界面用到模型的地方做延迟加载处理, 避免一次性加载过多卡顿
1个文件已修改
296 ■■■■■ 已修改文件
Main/System/Hero/UIHeroController.cs 296 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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;
    }
}