The last article introduced the extended recursive lookup of subobjects, singleton base classes, and a simple version of the framework’s common messaging mechanism (which will be used in the loading interface, but will be covered later). This article first put a simple AB package manager introduced, as for the specific how to play AB package, their own search engine on the line.
Unity’s PackManger provides the AB package, which can be found on the website.
AB management is actually the most important dependency processing, avoid this pit actually nothing to say.
A, AB package management code;
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ABManager : MonoBehaviour { private static ABManager instance; public static ABManager Instance { get { if (instance == null) { GameObject go = new GameObject(typeof(ABManager).ToString()); instance= go.AddComponent<ABManager>(); } return instance; } } private AssetBundle single; // Single master package; private AssetBundleManifest mainfest; Public string SingleName {get {#if UNITY_STANDALONE mdebug. Log(" This is the name of the AB package on the current platform: STANDALONE"); return "STANDALONE"; #else return "ELSE"; #endif } } private string abPath = ""; public string ABPath { get { if (abPath == "") { #if UNITY_STANDALONE abPath = Application.streamingAssetsPath + "/"; Mdebug. Log(" Current platform AB package path: "+ abPath); #else abPath = Application.persistentDataPath + "/"; #endif } return abPath; }} /// <summary> private Dictionary<string, AssetBundle> loadDic = new Dictionary<string, AssetBundle>(); public T LoadAssets<T>(string assetName,string abName) where T : Object { AssetBundle ab = LoadAssetBundle(assetName); if (ab ! = null) { T asset = ab.LoadAsset<T>(abName); return asset; } return default(T); } public AssetBundle LoadAssetBundle(string abName) { AssetBundle ab = null; if (single == null) { single = AssetBundle.LoadFromFile(ABPath + SingleName); } if (mainfest == null) { mainfest = single.LoadAsset<AssetBundleManifest>("AssetBundleManifest"); } / / all the dependencies of the string [] deps = mainfest. GetAllDependencies (abName); for (int i = 0; i < deps.Length; i++) { string depABName = deps[i]; // If (! loadDic.ContainsKey(depABName)) { AssetBundle depAB = AssetBundle.LoadFromFile(ABPath + depABName); loadDic.Add(depABName, depAB); } } if(! loadDic.TryGetValue(abName,out ab)) { ab = AssetBundle.LoadFromFile(ABPath + abName); loadDic.Add(abName, ab); } return ab; } public void UnLoadAB(string abName,bool unloadAllObjects = false) {AssetBundle ab = null; if(loadDic.TryGetValue(abName,out ab)) { ab.Unload(unloadAllObjects); loadDic.Remove(abName); Debug.Log(" uninstalled "+ abName); } } public void UnLoadAllAB(bool unloadAllObjects = false) { foreach (var item in loadDic.Values) { item.Unload(unloadAllObjects); } loadDic.Clear(); }}Copy the code
The only thing to notice is that when you Unload AB, pass AB.Unload(true); And ab. Unload (false); The difference between; Then there is the problem of loading a resource that may have dependencies, so you need to load recursively until all the dependencies of a resource are loaded. Otherwise, some resources will be lost. I won’t go into the details of the APi, just check out the unity official website manual. And there are too many people introducing these things…
Now it’s time to show how to load state, which is part of the logic of the scene;
Second, some state processing of loading scene;
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using System; public delegate void LoadSceneComplete(params object[] args); public class LoadSceneMsg : AutoSingleton<LoadSceneMsg> { AsyncOperation async = null; IEnumerator loadScene = null; public void LoadScene(string sceneName,LoadSceneComplete loadComp,params object[] args) { loadScene = IELoadScene(sceneName, loadComp, args); StartCoroutine(loadScene); } IEnumerator IELoadScene(string sceneName,LoadSceneComplete callBack,params object[] args) { async = SceneManager.LoadSceneAsync(sceneName); async.allowSceneActivation = false; // Progress bar loaded values: The value of progress cannot be dynamically passed in without passing in a while loop; While (async.progress < 0.9f) {mdebug.log ("async.progress" + async.progress); // This execution method is registered in the Loadingpanel code. I'll post the Loading code later; MessageManager.DoFunc("loading", async.progress); yield return null; } async.allowSceneActivation = true; Yield return new WaitForSeconds (0.5 f); yield return async; Mdebug. Log(" Loading scene "+ sceneName); MessageManager.RemoveFunc("loading"); callBack(args); Resources.UnloadUnusedAssets(); StopCoroutine(loadScene); async = null; loadScene = null; GC.Collect(); }}Copy the code
In fact, there is not much that needs to be explained, but a coroutine is used to load a scene. The details of how to invoke the above two classes will be seen in the state management class. The important thing is that if you want to get the load progress dynamically, the async. Progress value, you have to put it in the loop. Otherwise, if you just pass it through, it’s a fixed value. I’ll post more about all the UI loading interfaces later, but I’ll finish up the state management stuff for now;
Third, the most core part, control the whole state (scene) loading process. Here I use reflection, if you have the idea of a friend can put this whole frame in the form of reflection, to achieve complete separation of code and preform.
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Reflection; Public class MySceneManager: AutoSingleton<MySceneManager> {// Manage the loaded state. private Dictionary<string, BaseScene> sceneDic = new Dictionary<string, BaseScene>(); Private BaseScene m_currentScene = null; Private void Start() {private void Start() {private void Start(); LoadScene("LoginStateScene"); } // Core logic processing; Public void LoadScene(string sceneName) {// LoadScene; BaseScene target = null; // If it is not in the dictionary, it is not loaded or unloaded. if (! SceneDic.TryGetValue(sceneName, out target)) {// reflection, get the class name of the scene, get the class name; target = Assembly.GetExecutingAssembly().CreateInstance(sceneName) as BaseScene; sceneDic.Add(sceneName, target); } if (target == null) {mdebug. Log(" Scene does not exist: "+ sceneName); } target = sceneDic[sceneName]; // Change the scene from m_currentScene -- > to the scene you want to switch; ChangeScene(target); // Notice that one of the functions in the scenario, LoadComplete, is inserted as an argument. A detailed look at F12 jumps to the implementation logic of this function. LoadSceneMsg.Instance.LoadScene(sceneName, target.LoadComplete); } public void ChangeScene(BaseScene scene) {// There is no scene, so null. For example, as soon as you enter the game, loginScene, m_currentScene will not exist. If m_currentScene is LogiScene, go to m_currentScene.stop (); If (m_currentScene! = null) { m_currentScene.Stop(); } m_currentScene = scene; m_currentScene.Start(); }}Copy the code
Some may wonder where MDebug came from. I forgot to mention that earlier. This is a class written by myself, is to package Debug, is convenient to turn off Debug. The disadvantage is that clicking on the display text on the Console does not directly jump to the current line of code (you can view it on the stack), and the advantage is that you do not have to delete the Debug information line by line. Directly control the value of isDebug, you can control whether to display all Log information, mobile game development.
using System.Collections; using System.Collections.Generic; using UnityEngine; public class MDebug { static bool isDebug = true; public static void Log(object content) { if (isDebug) { Debug.Log(content); } } public static void LogError(object content) { if (isDebug) { Debug.LogError(content); } } public static void LogWranning(object centent) { if (isDebug) { Debug.LogWarning(centent); }}}Copy the code
Five, summary: by this point, all control state classes, if not down, should be short said. In fact, the difficulty is not high, also very simple. There are some small holes that people who understand the code can easily solve themselves, but the impact is not significant.
Generally speaking, the core content is in this article. Be sure to understand the logic of how it calls each method to switch scenarios (states). It’s easy to see. The following is the UI treatment, which is essentially the same as it is, not much different.