补充关卡加载部分的逻辑,在这里的逻辑设计中,每次加载Scene都需要主动打开 Loading界面。由Loading界面驱动场景加载逻辑。
Loading界面 Loading界面的Prefab包括一个背景和一个Slider和一个Progress(Text)。我们使用Slider作为进度条,因为其中的Fill图片可以使用Sliced模式。这样我们可以使用九宫格切割过(一般是个圆形图片,只切两边)的更好看的图片当作加载进度条了。
Pathes
中的Prefab路径
1 public const string LOADING_VIEW = PREFAB_FOLDER + "LoadingView" ;
添加Key DataKeys
里面添加存档中已经通过的关卡部分的Key
1 public const string LEVEL_PASSED = "levelPassed" ;
SceneMgr 在Enums
中添加Scene名的枚举
1 2 3 4 5 6 public enum SceneName{ NULL, StartScene, Game }
SceneMgr
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 using System.Collections;using UnityEngine;using UnityEngine.SceneManagement;public class SceneMgr : NormalSingleton <SceneMgr >{ private AsyncOperation _async; public void LoadSceneAsync (SceneName name ) { CoroutineMgr.Instance.ExecuteOnce(LoadAsync(name.ToString())); } private IEnumerator LoadAsync (string name ) { _async = SceneManager.LoadSceneAsync(name); _async.allowSceneActivation = false ; yield return _async; } public float Process () { if (_async == null ) return 0f ; if (_async.progress >= 0.9f ) return 1f ; else return _async.progress; } public void SceneActivation () { if (_async == null ) return ; _async.allowSceneActivation = true ; _async = null ; } }
LifeCycleMgr 当我们的脚本有需要Unity提供的生命周期的地方,就需要集中在LifeCycleMgr
当中管理。
Unity的生命周期函数在底层是基于反射进行调用的。所以我们要集中处理。在LifeCycleMgr
中添加Add
、Remove
、RemoveAll
方法,用于在后期添加生命周期逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class LifeCycleMgr : LazyMonoSing <LifeCycleMgr >, IInit { public void Add (LifeName lifeName, object obj ) { LifeCycleConfig.LifeCycles[lifeName].Add(obj); } public void Remove (LifeName lifeName, object obj ) { LifeCycleConfig.LifeCycles[lifeName].Remove(obj); } public void RemoveAll (object obj ) { foreach (var life in LifeCycleConfig.LifeCycles) { life.Value.Remove(obj); } } }
RemoveAll(object obj)
方法用于将当前对象所有的用到Unity生命周期的地方全部移除。
Loading界面需要在LifeCycleMgr
中Update
每帧更新,及时读取加载进度。
LoadingView 修改UIUtil
文件,在UIUtilData
中添加GetComponent
和AddComponent
的快捷方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class UIUtilData { public T GetCo <T >() where T : UnityEngine.Component { if (Go != null ) return Go.GetComponent<T>(); else { Debug.LogError("当前Go为空" ); return null ; } } public void AddCo <T >() where T : UnityEngine.Component { if (Go != null ) Go.AddComponent<T>(); else { Debug.LogError("当前Go为空" ); } } }
LoadingView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 using UnityEngine.UI;[BindPrefab(Pathes.LOADING_VIEW, Consts.BIND_PREFAB_PRIORITY_VIEW) ] public class LoadingView : ViewBase { private Slider _slider; protected override void InitChild () { _slider = UIUtil.Get("Slider" ).GetCo<Slider>(); } public override void Show () { base .Show(); LifeCycleMgr.Instance.Add(LifeName.UPDATE, this ); } public override void UpdateFun () { base .UpdateFun(); UpdateProgress(); UpdateSlider(); } private void UpdateProgress () { float progress = SceneMgr.Instance.Process(); progress *= 100 ; UIUtil.Get("Progress" ).SetText(string .Format("{0}%" , progress)); } private void UpdateSlider () { _slider.value = SceneMgr.Instance.Process(); } public override void Hide () { base .Hide(); LifeCycleMgr.Instance.Remove(LifeName.UPDATE, this ); } private void OnDestroy () { Hide(); } }
LoadingController GameStateModel
中添加CurrentScene
和TargetScene
属性
1 2 public SceneName CurrentScene { get ; set ; }public SceneName TargetScene { get ; set ; }
LoadingController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 [BindPrefab(Pathes.LOADING_VIEW, Consts.BIND_PREFAB_PRIORITY_CONTROLLER) ] public class LoadingController : ControllerBase { protected override void InitChild () { } public override void Show () { base .Show(); if (GameStateModel.Instance.TargetScene != GameStateModel.Instance.CurrentScene && GameStateModel.Instance.TargetScene != SceneName.NULL) { SceneMgr.Instance.LoadSceneAsync(GameStateModel.Instance.TargetScene); LifeCycleMgr.Instance.Add(LifeName.UPDATE, this ); } } public override void UpdateFun () { base .UpdateFun(); if (SceneMgr.Instance.Process() == 1f ) { SceneMgr.Instance.SceneActivation(); } } public override void Hide () { base .Hide(); if (GameStateModel.Instance.TargetScene != SceneName.NULL ) { GameStateModel.Instance.CurrentScene = GameStateModel.Instance.TargetScene; GameStateModel.Instance.TargetScene = SceneName.NULL; } LifeCycleMgr.Instance.Remove(LifeName.UPDATE, this ); } private void OnDestroy () { Hide(); } }
启用加载界面 LevelItemController 修改LevelItemController
,添加选关进入的逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class LevelItemController : ControllerBase { private int _id; protected override void InitChild () { _id = transform.GetSiblingIndex(); transform.ButtonAction("Enter" , () => { GameStateModel.Instance.TargetScene = SceneName.Game; UIMgr.Instance.Show(Pathes.LOADING_VIEW); }); transform.ButtonAction("Mask" , () => { UIMgr.Instance.ShowDialog("当前关卡未开放" ); }); } }
注意在Build Setting里面添加场景。
GameRoot 修改GameRoot
,初始化GameStateModel
的开始场景
1 2 3 4 5 private void Start (){ GameStateModel.Instance.CurrentScene = SceneName.StartScene; }
注意事项 到目前为止的设计中,只有CoroutineMgr
和LifeCycleMgr
使用过DontDestroyOnLoad
这个API。在切换场景后,所有的UI都不会保留