资源管理(23)场景优化分级加载

场景优化

一、

如果是低配机,石头可以不加载,必须加载出来的

如果是中配机,可以把石头加载出来,

如果是高配机,可以把特效粒子全部加载出来

二、

一般用的4分法

场景表,逻辑上的场景

场景表Sys_Scene

一个逻辑场景对应一个或者多个scene

Sys_SceneDetail,场景配置表

低配机加载0,中配机加载01,高配机加载012

场景的加载和卸载全部依赖SceneLoaderRoutine,没有专门处理的场景加载

加载三个场景就要启动三个场景加载器,所以在场景管理器中场景加载器是以链表的形式存在的

场景的明细编号对应的,Sys_SceneDetail中的Id

 

从场景a去场景b,首先要把场景a卸载掉,然后再加载新场景

把虎跑村分成了三个场景

下面是代码部分

 

 

获取场景名称

GameEntry.Resource.GetSceneAssetBundlePath(sceneName)

打成bundle包所有的路径都是小写的,所以要转化成小写

 

/// <summary>
    /// 场景加载和卸载器
    /// </summary>
    public class SceneLoadRoutine
    {
        private AsyncOperation m_CurrAsync = null;

        /// <summary>
        /// 进度更新
        /// </summary>
        private BaseAction<int, float> m_OnProgressUpdate;

        /// <summary>
        /// 场景加载完毕
        /// </summary>
        private BaseAction<SceneLoadRoutine> m_OnLoadSceneComplete;

        /// <summary>
        /// 卸载场景完毕
        /// </summary>
        private BaseAction<SceneLoadRoutine> m_OnUnLoadSceneComplete;

        /// <summary>
        /// 场景明细编号(用于场景分级加载)
        /// </summary>
        private int m_SceneDetailId;


        /// <summary>
        /// 加载场景
        /// </summary>
        /// <param name="sceneDetailId"></param>
        /// <param name="sceneName"></param>
        /// <param name="onProgressUpdate"></param>
        /// <param name="onLoadSceneComplete"></param>
        public void LoadScene(int sceneDetailId, string sceneName, BaseAction<int, float> onProgressUpdate, BaseAction<SceneLoadRoutine> onLoadSceneComplete)
        {
            Reset();

            m_SceneDetailId = sceneDetailId;
            m_OnProgressUpdate = onProgressUpdate;
            m_OnLoadSceneComplete = onLoadSceneComplete;


#if ASSETBUNDLE
            //加载场景的资源包
            GameEntry.Resource.ResourceLoaderManager.LoadAssetBundle(GameEntry.Resource.GetSceneAssetBundlePath(sceneName), onComplete: (AssetBundle bundle) =>
            {
                m_CurrAsync = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
                if (m_CurrAsync == null) if (m_OnLoadSceneComplete != null) m_OnLoadSceneComplete(this);
            });
#else
            m_CurrAsync = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
            m_CurrAsync.allowSceneActivation = false;
            if (m_CurrAsync == null)
            {
                if (m_OnLoadSceneComplete != null) m_OnLoadSceneComplete(this);
            }
#endif
        }

        /// <summary>
        /// 卸载场景
        /// </summary>
        /// <param name="sceneName"></param>
        /// <param name="onUnLoadSceneComplete"></param>
        public void UnLoadScene(string sceneName, BaseAction<SceneLoadRoutine> onUnLoadSceneComplete)
        {
            Reset();
            m_OnUnLoadSceneComplete = onUnLoadSceneComplete;
            m_CurrAsync = SceneManager.UnloadSceneAsync(sceneName);
            if (m_CurrAsync == null)
            {
                if (m_OnUnLoadSceneComplete != null) m_OnUnLoadSceneComplete(this);
            }
        }

        /// <summary>
        /// 重置
        /// </summary>
        private void Reset()
        {
            m_CurrAsync = null;
            m_OnProgressUpdate = null;
            m_OnLoadSceneComplete = null;
            m_OnUnLoadSceneComplete = null;
        }

        /// <summary>
        /// 更新
        /// </summary>
        public void OnUpdate()
        {
            if (m_CurrAsync == null) return;

            if (!m_CurrAsync.isDone)
            {
                //大于0.9说明加载已经完成
                if (m_CurrAsync.progress >= 0.9f)
                {
                    //加载完成,最后一次更新
                    if (m_OnProgressUpdate != null) m_OnProgressUpdate(m_SceneDetailId, m_CurrAsync.progress);

                    m_CurrAsync.allowSceneActivation = true;
                    m_CurrAsync = null;

                    if (m_OnLoadSceneComplete != null) m_OnLoadSceneComplete(this);
                }
                else
                {
                    //小于0.9一直把进度通过委托传回去
                    if (m_OnProgressUpdate != null) m_OnProgressUpdate(m_SceneDetailId, m_CurrAsync.progress);
                }
            }
            else
            {
                m_CurrAsync = null;
                if (m_OnUnLoadSceneComplete != null) m_OnUnLoadSceneComplete(this);
            }
        }
    }

测试

 

 /// <summary>
    /// 场景管理器
    /// </summary>
    public class YouYouSceneManager : ManagerBase
    {
        /// <summary>
        /// 场景加载器链表
        /// </summary>
        private LinkedList<SceneLoadRoutine> m_SceneLoaderList;

        /// <summary>
        /// 当前加载的场景编号
        /// </summary>
        private int m_CurrLoadSceneId;

        /// <summary>
        /// 当前场景数据实体
        /// </summary>
        private Sys_SceneEntity m_CurrSceneEntity;

        /// <summary>
        /// 当前场景明细
        /// </summary>
        private List<Sys_SceneDetailEntity> m_CurrSceneDetailList;

        /// <summary>
        /// 需要加载或者卸载的明细数量
        /// </summary>
        private int m_NeedLoadOrUnloadSceneDetailCount = 0;

        /// <summary>
        /// 当前已经 加载或者卸载的明细数量
        /// </summary>
        private int m_CurrLoadOrUnloadSceneDetailCount = 0;

        /// <summary>
        /// 场景是否加载中
        /// </summary>
        private bool m_CurrSceneIsLoading;

        /// <summary>
        /// 当前加载进度(多个分级场景的总加载进度)
        /// </summary>
        private float m_CurrProgress = 0;

        /// <summary>
        /// 分级场景加载进度
        /// </summary>
        private Dictionary<int, float> m_TargetProgressDic;

        /// <summary>
        /// 需要外传的参数
        /// </summary>
        private BaseParams m_CurrLoadingParam;

        /// <summary>
        /// 场景全部加载完毕
        /// </summary>
        private BaseAction m_Complete;


        public YouYouSceneManager()
        {
            m_SceneLoaderList = new LinkedList<SceneLoadRoutine>();
            m_TargetProgressDic = new Dictionary<int, float>();
        }


        /// <summary>
        /// 更新
        /// </summary>
        internal void OnUpdate()
        {
            //加载过程中,执行链表的update
            if (m_CurrSceneIsLoading)
            {
                //更新加载器
                var curr = m_SceneLoaderList.First;
                while (curr != null)
                {
                    curr.Value.OnUpdate();
                    curr = curr.Next;
                }

                float currTarget = GetCurrTotalProgress();//当前加载的总进度
                float finelTarget = 0.9f * m_NeedLoadOrUnloadSceneDetailCount;//目标加载的总进度
                if (currTarget >= finelTarget)
                {
                    currTarget = m_NeedLoadOrUnloadSceneDetailCount;
                }

                //模拟进度 按时间递增,等达到了90%先停下, 等待真正场景加载完毕直接改成100%
                if (m_CurrProgress < m_NeedLoadOrUnloadSceneDetailCount && m_CurrProgress <= currTarget)
                {
                    //总的加载进度=当前进度+累加一帧的时间*加载的明细数目
                    m_CurrProgress = m_CurrProgress + Time.deltaTime * m_NeedLoadOrUnloadSceneDetailCount;
                    m_CurrLoadingParam.IntParam1 = (int)LoadingType.ChangeScene;
                    m_CurrLoadingParam.FloatParam1 = (m_CurrProgress / m_NeedLoadOrUnloadSceneDetailCount);
                    GameEntry.Event.CommonEvent.Dispatch(SysEventId.LoadingProgressChange, m_CurrLoadingParam);
                }
                else if (m_CurrProgress >= m_NeedLoadOrUnloadSceneDetailCount)//这里疑似有BUG,如果后续出现问题的话 TODO
                {
                    GameEntry.Log(LogCategory.Normal, "场景=>{0}  加载完毕", m_CurrSceneEntity.SceneName);

                    //播放BGM
                    GameEntry.Auido.PlayBGM(m_CurrSceneEntity.BGMId);

                    m_NeedLoadOrUnloadSceneDetailCount = 0;
                    m_CurrLoadOrUnloadSceneDetailCount = 0;
                    m_CurrSceneIsLoading = false;
                    GameEntry.UI.CloseUIForm(UIFormId.UI_Loading);

                    m_CurrLoadingParam.Reset();
                    GameEntry.Pool.EnqueueClassObject(m_CurrLoadingParam);

                    if (m_Complete != null) m_Complete();
                }
            }
        }
        /// <summary>
        /// 获取当前加载总场景的进度
        /// </summary>
        /// <returns></returns>
        private float GetCurrTotalProgress()
        {
            float progress = 0;
            var lst = m_TargetProgressDic.GetEnumerator();
            while (lst.MoveNext())
            {
                progress += lst.Current.Value;
            }
            return progress;
        }

        /// <summary>
        /// 加载总场景
        /// </summary>
        /// <param name="sceneId"></param>
        internal void LoadScene(int sceneId, bool showLoadingForm, BaseAction onComplete)
        {
            //加载中
            if (m_CurrSceneIsLoading)
            {
                GameEntry.LogError("总场景{0}正在加载中", m_CurrLoadSceneId);
                return;
            }
            if (m_CurrLoadSceneId == sceneId)
            {
                GameEntry.LogError("正在重复加载总场景{0}", sceneId);
                return;
            }

            //停止BGM
            GameEntry.Auido.StopBGM();

            m_CurrLoadingParam = GameEntry.Pool.DequeueClassObject<BaseParams>();
            m_Complete = onComplete;

            if (showLoadingForm)
            {
                //加载Loading
                GameEntry.UI.OpenUIForm(UIFormId.UI_Loading, onOpen: (UIFormBase form) =>
                {
                    DoLoadScene(sceneId);
                });
            }
            else
            {
                DoLoadScene(sceneId);
            }
        }
        /// <summary>
        /// 执行加载场景
        /// </summary>
        /// <param name="sceneId"></param>
        private void DoLoadScene(int sceneId)
        {
            m_CurrProgress = 0;
            m_TargetProgressDic.Clear();

            m_CurrSceneIsLoading = true;
            m_CurrLoadSceneId = sceneId;
            //先卸载当前的总场景
            UnLoadCurrScene();
        }

        /// <summary>
        /// 卸载当前的总场景
        /// </summary>
        private void UnLoadCurrScene()
        {
            //当前的场景实体不为nil
            if (m_CurrSceneEntity != null)
            {
                m_NeedLoadOrUnloadSceneDetailCount = m_CurrSceneDetailList.Count;
                for (int i = 0; i < m_NeedLoadOrUnloadSceneDetailCount; i++)
                {
                    SceneLoadRoutine routine = GameEntry.Pool.DequeueClassObject<SceneLoadRoutine>();
                    m_SceneLoaderList.AddLast(routine);
                    routine.UnLoadScene(m_CurrSceneDetailList[i].ScenePath, OnUnLoadSceneComplete);
                }
            }
            else
            {
                //刚进游戏当前场景为nil,直接加载新场景
                LoadNewScene();
            }
        }

        /// <summary>
        /// 加载新场景
        /// </summary>
        private void LoadNewScene()
        {
            //根据当前场景id,获取当前场景实体
            m_CurrSceneEntity = GameEntry.DataTable.DataTableManager.Sys_SceneDBModel.GetDic(m_CurrLoadSceneId);
            //当前场景的明细
            m_CurrSceneDetailList = GameEntry.DataTable.DataTableManager.Sys_SceneDetailDBModel.GetListBySceneId(m_CurrSceneEntity.Id, 2);
            m_NeedLoadOrUnloadSceneDetailCount = m_CurrSceneDetailList.Count;

            for (int i = 0; i < m_NeedLoadOrUnloadSceneDetailCount; i++)
            {
                SceneLoadRoutine routine = GameEntry.Pool.DequeueClassObject<SceneLoadRoutine>();
                m_SceneLoaderList.AddLast(routine);

                Sys_SceneDetailEntity entity = m_CurrSceneDetailList[i];
                //加载场景明细
                routine.LoadScene(entity.Id, entity.ScenePath, OnLoadSceneProgressUpdate, OnLoadSceneComplete);
            }
        }
        /// <summary>
        /// 场景加载完毕回调
        /// </summary>
        /// <param name="routine"></param>
        private void OnLoadSceneComplete(SceneLoadRoutine routine)
        {
            //从链表中移除掉
            m_SceneLoaderList.Remove(routine);
            //加载器回池
            GameEntry.Pool.EnqueueClassObject(routine);
        }
        /// <summary>
        /// 场景加载进行中 回调,会更新目标进度
        /// </summary>
        /// <param name="sceneDetailId"></param>
        /// <param name="progress"></param>
        private void OnLoadSceneProgressUpdate(int sceneDetailId, float progress)
        {
            //记录每个分级场景 当前的进度
            m_TargetProgressDic[sceneDetailId] = progress;
        }


        /// <summary>
        /// 场景卸载完毕回调
        /// </summary>
        /// <param name="routine"></param>
        private void OnUnLoadSceneComplete(SceneLoadRoutine routine)
        {
            m_SceneLoaderList.Remove(routine);
            GameEntry.Pool.EnqueueClassObject(routine);

            m_CurrLoadOrUnloadSceneDetailCount++;
            if (m_CurrLoadOrUnloadSceneDetailCount == m_NeedLoadOrUnloadSceneDetailCount)
            {
                Resources.UnloadUnusedAssets();
                m_NeedLoadOrUnloadSceneDetailCount = 0;
                m_CurrLoadOrUnloadSceneDetailCount = 0;
                //卸载完毕,直接load新场景
                LoadNewScene();
            }
        }
    }

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值