场景优化
一、
如果是低配机,石头可以不加载,必须加载出来的
如果是中配机,可以把石头加载出来,
如果是高配机,可以把特效粒子全部加载出来
二、
一般用的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();
}
}
}