Unity组件开发--UI管理器

1.Canvas组件:

注意属性:

(1)渲染模式是:屏幕空间相机

(2)创建一个UICamera节点,管理相机

(3)屏幕画布缩放模式

(4)画布下挂载两个脚本:UIRoot和UIManager

(5)事件系统管理节点必须有:

2.画布下其他节点类型:用于不同界面类型的管理归类window类型

3.先看UIRoot脚本:

using UnityEngine;/// <summary>
/// 这个脚本用来定位UIROOT,因为GameObject.Find在浏览器上会踩坑
/// </summary>
public class UIRoot : MonoBehaviour {private void Awake() {DontDestroyOnLoad(gameObject);}void Start () {}}

4.所有的UI界面预设体都用一个json文本管理起来:UIPanelType

{
"infoList":
[{"panelTypeString":"HOME_PANEL",
"path":"HomePanel"},{"panelTypeString":"WELCOME_PANEL",
"path":"WelcomePanel"},{"panelTypeString":"MAIN_PANEL",
"path":"MainPanel"}]
}

5.上面这个json文件中的path,对应的就是UI预设体的名字:由于我们的UI预制体都是用AB包的方式加载的,就都放在BundleAsset文件夹中

6.C#代码中也有有一个对应UI预设体名字的枚举类:

public enum UIPanelType {ALERT_PANEL,CONNECT_PANEL,HOME_PANEL,WELCOME_PANEL,MAIN_PANEL,
}

7.然后所有UI类脚本必须继承的基类:BasePanel

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;[RequireComponent(typeof(CanvasGroup))]
public class BasePanel : MonoBehaviour {public enum PanelLayer {Normal,Hud,Addition,Windows,Wanring,ModelView,}[HideInInspector]public UIPanelType panelTpe;public PanelLayer Layer;protected CanvasGroup canvasGroup;protected virtual void Awake() {子类会继承这个函数,所以这里不应该写任何代码//name = GetType() + ">>";//canvasGroup = gameObject.GetComponent<CanvasGroup>();}protected new string name;/// <summary>/// 开启交互,页面显示/// </summary>public virtual void OnEnter() {//Debug.Log(name + "Enter");SetPanelActive(true);SetPanelInteractable(true);}/// <summary>/// 界面暂停,关闭交互/// </summary>public virtual void OnPause() {SetPanelInteractable(false);}/// <summary>/// 界面继续,恢复交互/// </summary>public virtual void OnResume() {SetPanelInteractable(true);}/// <summary>/// 界面不显示,退出这个界面,界面被关闭/// </summary>public virtual void OnExit() {SetPanelActive(false);SetPanelInteractable(false);}/// <summary>/// 关闭自身/// </summary>public void CloseSelf() {SetPanelActive(false);UIManager.Instance.CloseWindowMask();UIManager.Instance.ClosePannel(panelTpe);}private void SetPanelActive(bool isActive) {//isActive ^= this.gameObject.activeSelf;bool compare = isActive ^ gameObject.activeSelf;if (compare) {gameObject.SetActive(isActive);}}private void SetPanelInteractable(bool isInteractable) {//canvasGroup = canvasGroup == null ? gameObject.GetComponent<CanvasGroup>() : canvasGroup;//bool compare = isInteractable ^ canvasGroup;//if (compare) //{//    canvasGroup.interactable = isInteractable; //}//canvasGroup = canvasGroup == null ? gameObject.GetComponent<CanvasGroup>() : canvasGroup;//if (isInteractable ^ canvasGroup.interactable) canvasGroup.interactable = isInteractable;}}

8.UI管理器脚本:UIManager

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
using static BasePanel;public class UIManager : MonoBehaviour {private static UIManager sInstanceUiManager;private Dictionary<UIPanelType, string> mPanelPathDictionary;//存储所有面板Prefab的路径private Dictionary<UIPanelType, BasePanel> mPanelPool;//保存所有实例化面板的游戏物体身上的BasePanel组件private Stack<BasePanel> mPanelStack; //TODO:需要拆分成多个堆栈,否则会有各种奇怪的问题private Transform mUIRootTransform;private GameObject windowsMask;public static UIManager Instance{get { return sInstanceUiManager; }}[Serializable]public class UIPanelTypeJson {public List<UIPanelInformation> infoList;}/// <summary>/// 实例化UIManager/// </summary>/// <returns></returns>void Awake() {sInstanceUiManager = this;DontDestroyOnLoad(gameObject);ParseUIPanelTypeJson();mUIRootTransform = GameObject.FindAnyObjectByType<UIRoot>().transform;windowsMask = mUIRootTransform.Find("Windows/Mask").gameObject;windowsMask.GetComponent<Button>().onClick.AddListener(ClickMask);}/// <summary>/// 从json配置文件解析为相对应的object类/// </summary>private void ParseUIPanelTypeJson() {mPanelPathDictionary = new Dictionary<UIPanelType, string>();TextAsset textAsset = Resources.Load<TextAsset>("GameRes/UIPrefabs/UIPanelType");//将json对象转化为UIPanelTypeJson类UIPanelTypeJson jsonObject = JsonUtility.FromJson<UIPanelTypeJson>(textAsset.text);foreach (UIPanelInformation info in jsonObject.infoList) {mPanelPathDictionary.Add(info.panelType, info.path);}}public bool TopPanelIs(UIPanelType panelType) {BasePanel panel;mPanelPool.TryGetValue(panelType, out panel);if (!mPanelStack.Contains(panel)){return false;}else {int indexPanel = UtilsFunc.GetStackIndex(mPanelStack, panel);if (indexPanel!=null) return true;return false;}}public void CloseLastModelViewTypePanel() {//从栈顶开始查找指定面板BasePanel panelToRemove = null;for (int i = mPanelStack.Count - 1; i >= 0; i--){BasePanel panel = mPanelStack.ElementAt(i);if (panel.Layer == PanelLayer.ModelView){//找到则关闭页面panelToRemove = panel;panel.OnExit();break;}}if (panelToRemove != null){//移除要关闭的面板mPanelStack.Pop();//重新压入除要移除的面板外的所有面板Stack<BasePanel> tempStack = new Stack<BasePanel>();while (mPanelStack.Count > 0){BasePanel panel = mPanelStack.Pop();if (panel != panelToRemove){tempStack.Push(panel);}}while (tempStack.Count > 0){BasePanel panel = tempStack.Pop();mPanelStack.Push(panel);}}}public bool IsOpenModelView() {for (int i = mPanelStack.Count - 1; i >= 0; i--){BasePanel panel = mPanelStack.ElementAt(i);if (panel.Layer == PanelLayer.ModelView){return true;}}return false;}/// <summary>/// 获得一个指定页面/// </summary>/// <param name="panelType">指定页面类型</param>/// <returns>返回该页面的BasePanel</returns>private void GetPanel(UIPanelType panelType) {if (mPanelPool == null) {mPanelPool = new Dictionary<UIPanelType, BasePanel>();}BasePanel panel;//从页面池中尝试找到指定页面的示例mPanelPool.TryGetValue(panelType, out panel);if (panel == null) {if (mPanelPool.ContainsKey(panelType)) {//意味着正在加载,不需要重复调用return;}string path;mPanelPathDictionary.TryGetValue(panelType, out path);#if !UNITY_EDITORAppConst.UseAssetBundle = true;
#endifmPanelPool.Add(panelType, null);if (AppConst.UseAssetBundle) {var addressPath = "Prefab/UIPrefabs/" + path;AssetBundleManager.Instance.LoadPrefab(addressPath, (instancePanel) => {if (instancePanel != null) {var targetPanel = instancePanel.GetComponent<BasePanel>();SetPanel(targetPanel, panelType);}else {Debug.LogError($"error {addressPath}");}});}else {StartCoroutine(coEnsureWaitTime(panelType,path));}}else {if (panel.Layer != BasePanel.PanelLayer.Wanring) {panel.transform.SetAsLastSibling();if (mPanelStack.Contains(panel) == false) { //不存在才加入mPanelStack.Push(panel);}else { //存在的话将其移动到栈顶ToStackTop(panel);}}panel.OnEnter(); //OnEnter在 SetAsLastSibling 之后的目的是要置顶其他页面的时候可以生效}}void SetPanel(BasePanel targetPanel, UIPanelType panelType) {targetPanel.panelTpe = panelType;AddLayer(targetPanel);mPanelPool[panelType] = targetPanel;targetPanel.transform.SetAsLastSibling();if (targetPanel.Layer != BasePanel.PanelLayer.Wanring) {mPanelStack.Push(targetPanel);}targetPanel.OnEnter();}private void ToStackTop(BasePanel panel) {var tempStack = new Stack<BasePanel>();var tempPanel = mPanelStack.Pop();while (tempPanel != panel && mPanelStack.Count > 0) {tempStack.Push(tempPanel);tempPanel = mPanelStack.Pop();}if (tempPanel == panel) {mPanelStack.Push(tempPanel);}while (tempStack.Count > 0) {mPanelStack.Push(tempStack.Pop());}}IEnumerator coEnsureWaitTime(UIPanelType panelType, string path) {yield return new WaitForSeconds(0.1f);
#if UNITY_EDITORvar editorPath = "Assets/BundleAsset/Prefab/UIPrefabs/" + path + ".prefab";Debug.Log("load ui :"+editorPath);var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(editorPath);GameObject instancePanel = Instantiate(prefab) as GameObject;if (instancePanel != null) {var targetPanel = instancePanel.GetComponent<BasePanel>();SetPanel(targetPanel, panelType);}
#endif}private void ClickMask() {windowsMask.gameObject.SetActive(false);var topPanel = mPanelStack.Peek();topPanel.CloseSelf();}public void PreLoadUI(UIPanelType panelType) {if (mPanelPool == null){mPanelPool = new Dictionary<UIPanelType, BasePanel>();}BasePanel panel;//从页面池中尝试找到指定页面的示例mPanelPool.TryGetValue(panelType, out panel);if (panel == null){string path;mPanelPathDictionary.TryGetValue(panelType, out path);#if !UNITY_EDITORAppConst.UseAssetBundle = true;
#endifif (AppConst.UseAssetBundle){var addressPath = "Prefab/UIPrefabs/" + path;AssetBundleManager.Instance.PreLoadBundle(addressPath);}}}public void OpenWindowMask() {EventManager.Instance.TriggerEvent(EventName.UIInteraction);windowsMask.SetActive(true);windowsMask.transform.SetAsLastSibling();if (mPanelStack != null) {var topPanel = mPanelStack.Peek();topPanel.transform.SetAsLastSibling();}}public void CloseWindowMask() {EventManager.Instance.TriggerEvent(EventName.ExitUIInteraction);windowsMask.SetActive(false);}/// <summary>/// 显示指定的面板/// </summary>/// <param name="panelType"></param>public void PushPanel(UIPanelType panelType) {if (mPanelStack == null)mPanelStack = new Stack<BasePanel>();//判断一下栈里面是否有页面if (mPanelStack.Count > 0) {var topPanel = mPanelStack.Peek();topPanel.OnPause();}this.CloseLastModelViewTypePanel();GetPanel(panelType);}public void CloseAllPannel() {for (int i = mPanelStack.Count - 1; i >= 0; i--){BasePanel panel = mPanelStack.ElementAt(i);panel.OnExit();mPanelStack.Pop();}}/// <summary>/// 从栈里面找到指定面板将其关闭/// </summary>/// <param name="panelType"></param>public void ClosePannel(UIPanelType panelType) {if (mPanelPool.ContainsKey(panelType) == false) {Debug.LogError($"ClosePannel {panelType} null");return;}if (mPanelStack == null)return;//从栈顶开始查找指定面板BasePanel panelToRemove = null;for (int i = mPanelStack.Count - 1; i >= 0; i--) {BasePanel panel = mPanelStack.ElementAt(i);if (mPanelPool[panelType] == panel) {//找到则关闭页面panelToRemove = panel;panel.OnExit();break;}}if (panelToRemove != null) {//重新压入除要移除的面板外的所有面板Stack<BasePanel> tempStack = new Stack<BasePanel>();while (mPanelStack.Count > 0) {BasePanel panel = mPanelStack.Pop();if (panel != panelToRemove) {tempStack.Push(panel);}}while (tempStack.Count > 0) {BasePanel panel = tempStack.Pop();mPanelStack.Push(panel);}}}/// <summary>/// 关闭页面并显示新的页面/// </summary>/// <param name="panelType"></param>/// <param name="isPopCurrentPanel">true时, 关闭当前页面; false时, 关闭所有页面</param>public void PushPanel(UIPanelType panelType, bool isPopCurrentPanel) {if (isPopCurrentPanel) {PopCurrentPanel();}else {PopAllPanel();}PushPanel(panelType);}/// <summary>/// 返回上一个页面/// </summary>/// <returns></returns>public bool BackToLastPanel() {//判断当前栈是否为空??表示是否可以返回if (mPanelStack == null)mPanelStack = new Stack<BasePanel>();if (mPanelStack.Count <= 1) return false;//关闭栈顶页面的显示var topPanel1 = mPanelStack.Pop();topPanel1.OnExit();//恢复此时栈顶页面的交互BasePanel topPanel2 = mPanelStack.Peek();topPanel2.OnResume();return true;}void AddLayer(BasePanel panel) {Transform dstParent = null;switch (panel.Layer) {case BasePanel.PanelLayer.Normal:dstParent = mUIRootTransform.Find(nameof(BasePanel.PanelLayer.Normal));break;case BasePanel.PanelLayer.Hud:dstParent = mUIRootTransform.Find(nameof(BasePanel.PanelLayer.Hud));break;case BasePanel.PanelLayer.Addition:dstParent = mUIRootTransform.Find(nameof(BasePanel.PanelLayer.Addition));break;case BasePanel.PanelLayer.Windows:dstParent = mUIRootTransform.Find(nameof(BasePanel.PanelLayer.Windows));break;case BasePanel.PanelLayer.Wanring:dstParent = mUIRootTransform.Find(nameof(BasePanel.PanelLayer.Wanring));break;case BasePanel.PanelLayer.ModelView:dstParent = mUIRootTransform.Find(nameof(BasePanel.PanelLayer.ModelView));break;default:break;}panel.transform.SetParent(dstParent,false);}/// <summary>/// 隐藏当前面板/// </summary>private void PopCurrentPanel() {if (mPanelStack == null)mPanelStack = new Stack<BasePanel>();if (mPanelStack.Count <= 0) return;//关闭栈顶页面的显示BasePanel topPanel = mPanelStack.Pop();topPanel.OnExit();}/// <summary>/// 隐藏所有面板/// </summary>public void PopAllPanel() {if (mPanelStack == null)mPanelStack = new Stack<BasePanel>();if (mPanelStack.Count <= 0) return;//关闭栈里面所有页面的显示while (mPanelStack.Count > 0) {BasePanel topPanel = mPanelStack.Pop();topPanel.OnExit();}}/// <summary>/// 切换场景前,调用该方法来清空当前场景的数据/// </summary>public void RefreshDataOnSwitchScene() {mPanelPathDictionary.Clear();mPanelStack.Clear();}
}

9.AB包加载管理器:AssetBundleManager

using Cysharp.Threading.Tasks;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.WebSockets;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;public class AssetBundleManager : MonoBehaviour {private static AssetBundleManager instance;private Dictionary<string, List<Action<GameObject>>> m_loadingActions = new Dictionary<string, List<Action<GameObject>>>(); public static AssetBundleManager Instance {get {if (instance == null) {instance = new GameObject("AssetBundleManager").AddComponent<AssetBundleManager>();}return instance;}}private Dictionary<string, AssetBundle> loadedAssetBundles = new Dictionary<string, AssetBundle>();//public AssetBundle LoadAssetBundle(string bundleName, string sceneName = "") {//    if (loadedAssetBundles.ContainsKey(bundleName)) {//        return null;//    }//    string path = Application.streamingAssetsPath + "/" + bundleName;//    AssetBundle bundle = AssetBundle.LoadFromFile(path);//    if (bundle == null) {//        Debug.LogError($"Failed to load asset bundle: {bundleName}");//        return null;//    }//    loadedAssetBundles.Add(bundleName, bundle);//    if (!string.IsNullOrEmpty(sceneName)) {//        SceneManager.LoadScene(sceneName, LoadSceneMode.Additive);//    }//    return bundle;//}public void UnloadAssetBundle(string bundleName, string sceneName = "") {if (!loadedAssetBundles.ContainsKey(bundleName)) {return;}AssetBundle bundle = loadedAssetBundles[bundleName];bundle.Unload(true);loadedAssetBundles.Remove(bundleName);if (!string.IsNullOrEmpty(sceneName)) {SceneManager.UnloadSceneAsync(sceneName);}}public bool IsAssetBundleLoaded(string bundleName) {return loadedAssetBundles.ContainsKey(bundleName);}/// <summary>/// 示例 Prefab/Com/NpcHello/// </summary>/// <param name="prefabPath"></param>/// <param name="callback"></param>public void LoadPrefab(string prefabPath,System.Action<GameObject> callback) {if (m_loadingActions.TryGetValue(prefabPath,out var list)) {list.Add(callback);return; //这里返回不需要再开启协程}else {m_loadingActions.Add(prefabPath, new List<Action<GameObject>>());m_loadingActions[prefabPath].Add(callback);}StartCoroutine(LoadPrefabCoroutine(prefabPath));}enum Platefrom{PC,Mobile}string GetPrefabName(string prefabPath, Platefrom platefrom){string desPlatform = "";if (platefrom == Platefrom.Mobile){desPlatform = prefabPath + "_Mobile";}else{desPlatform = prefabPath;}var prefabName = UtilsFunc.GetFileNameWithoutExtension(desPlatform) + ".prefab";return prefabName;}private IEnumerator LoadPrefabCoroutine(string prefabPath) {var desPlatform = "";Debug.Log("UI路径LoadPrefabCoroutine......" + prefabPath);if (!PlayerData.Instance.isRunningPC){desPlatform = prefabPath + "_Mobile";}else{desPlatform = prefabPath;}desPlatform = $"{Host.AssetBundleIP}/{desPlatform.ToLower()}.bundle";string prefabName = "";string bundlePath = $"{prefabPath.ToLower()}.bundle";string fullBundlepath = $"{Host.AssetBundleIP}/{bundlePath.ToLower()}";AssetBundle bundle = null;if (loadedAssetBundles.ContainsKey(prefabPath)) {yield return new WaitForEndOfFrame();bundle = loadedAssetBundles[prefabPath];if (bundle.Contains(GetPrefabName(prefabPath,Platefrom.Mobile))){prefabName = GetPrefabName(prefabPath, Platefrom.Mobile);}else{prefabName = GetPrefabName(prefabPath, Platefrom.PC);}}else {
#if UNITY_EDITORif (AppConst.useShowBundlePath) { //打需要演示的包时候需要先读取本地的streamAsset,如果存在侧不执行var showBundlePath = Application.streamingAssetsPath + $"/webgl/{bundlePath.ToLower()}";Debug.Log("showBundlePath:"+ showBundlePath);UnityWebRequest showRequest = UnityWebRequestAssetBundle.GetAssetBundle(showBundlePath);yield return showRequest.SendWebRequest();if (showRequest.result == UnityWebRequest.Result.Success) {Debug.Log($"load bundle ok: {showBundlePath}");bundle = DownloadHandlerAssetBundle.GetContent(showRequest);}else {UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(fullBundlepath);yield return request.SendWebRequest();if (request.result != UnityWebRequest.Result.Success) {Debug.LogError($"Failed to load asset bundle at path: {fullBundlepath}");yield break;}Debug.Log($"load bundle ok: {fullBundlepath}");bundle = DownloadHandlerAssetBundle.GetContent(request);}}else {UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(desPlatform);yield return request.SendWebRequest();if (request.result != UnityWebRequest.Result.Success) {Debug.LogError($"Failed to load asset bundle at path: {desPlatform}");request = UnityWebRequestAssetBundle.GetAssetBundle(fullBundlepath);yield return request.SendWebRequest();if (request.result != UnityWebRequest.Result.Success) {Debug.LogError($"Failed to load asset bundle at path: {fullBundlepath}");yield break;}Debug.Log($"load bundle ok: {fullBundlepath}");prefabName = GetPrefabName(prefabPath,Platefrom.PC);bundle = DownloadHandlerAssetBundle.GetContent(request);}else{Debug.Log($"load bundle ok: {desPlatform}");prefabName =  GetPrefabName(prefabPath, PlayerData.Instance.isRunningPC ? Platefrom.PC : Platefrom.Mobile);bundle = DownloadHandlerAssetBundle.GetContent(request);}}
#elseUnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(desPlatform);yield return request.SendWebRequest();if (request.result != UnityWebRequest.Result.Success){Debug.LogError($"Failed to load asset bundle at path: {desPlatform}");request = UnityWebRequestAssetBundle.GetAssetBundle(fullBundlepath);yield return request.SendWebRequest();if (request.result != UnityWebRequest.Result.Success){Debug.LogError($"Failed to load asset bundle at path: {fullBundlepath}");yield break;}Debug.Log($"load bundle ok: {fullBundlepath}");bundle = DownloadHandlerAssetBundle.GetContent(request);prefabName = GetPrefabName(prefabPath,Platefrom.PC);}else {Debug.Log($"load bundle ok: {desPlatform}");prefabName = GetPrefabName(prefabPath, PlayerData.Instance.isRunningPC ? Platefrom.PC : Platefrom.Mobile);bundle = DownloadHandlerAssetBundle.GetContent(request);}#endifloadedAssetBundles.Add(prefabPath, bundle);}if (bundle == null) {Debug.LogError($"Failed to get asset bundle content at path: {fullBundlepath}");doCallBack(prefabPath);yield break;}else {ResetBundleMaterials(bundle);}Debug.Log($"load bundle ok: {fullBundlepath}");AssetBundleRequest prefabRequest = bundle.LoadAssetAsync<GameObject>(prefabName);yield return prefabRequest;if (prefabRequest.asset == null) {Debug.LogError($"Failed to load prefab {prefabName} from asset bundle at path: {desPlatform}");doCallBack(prefabPath);yield break;}doCallBack(prefabPath, prefabRequest.asset);//bundle.UnloadAsync(true);}public void PreLoadBundle(string prefabPath) {StartCoroutine(PreLoadBundleCoroutine(prefabPath));}private IEnumerator PreLoadBundleCoroutine(string prefabPath) {var desPlatform = "";Debug.Log("UI路径PreLoadBundleCoroutine......" + prefabPath);if (!PlayerData.Instance.isRunningPC){desPlatform = prefabPath + "_Mobile";}else{desPlatform = prefabPath;}desPlatform = $"{Host.AssetBundleIP}/{desPlatform.ToLower()}.bundle";string bundlePath = $"{prefabPath.ToLower()}.bundle";string prefabName = "";string fullBundlepath = $"{Host.AssetBundleIP}/{bundlePath.ToLower()}";AssetBundle bundle = null;if (loadedAssetBundles.ContainsKey(prefabPath)) {yield return null;bundle = loadedAssetBundles[prefabPath];}else {
#if !UNITY_EDITORif (AppConst.useShowBundlePath) { //打需要演示的包时候需要先读取本地的streamAsset,如果存在侧不执行var showBundlePath = Application.streamingAssetsPath + $"/webgl/{bundlePath.ToLower()}";Debug.Log("showBundlePath:"+ showBundlePath);UnityWebRequest showRequest = UnityWebRequestAssetBundle.GetAssetBundle(showBundlePath);yield return showRequest.SendWebRequest();if (showRequest.result == UnityWebRequest.Result.Success) {Debug.Log($"load bundle ok: {showBundlePath}");bundle = DownloadHandlerAssetBundle.GetContent(showRequest);}else {UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(fullBundlepath);yield return request.SendWebRequest();if (request.result != UnityWebRequest.Result.Success) {Debug.LogError($"Failed to load asset bundle at path: {fullBundlepath}");yield break;}Debug.Log($"load bundle ok: {fullBundlepath}");bundle = DownloadHandlerAssetBundle.GetContent(request);}}else {UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(desPlatform);yield return request.SendWebRequest();if (request.result != UnityWebRequest.Result.Success) {Debug.LogError($"Failed to load asset bundle at path: {desPlatform}");request = UnityWebRequestAssetBundle.GetAssetBundle(fullBundlepath);yield return request.SendWebRequest();if (request.result != UnityWebRequest.Result.Success) {Debug.LogError($"Failed to load asset bundle at path: {fullBundlepath}");yield break;}Debug.Log($"load bundle ok: {fullBundlepath}");prefabName = UtilsFunc.GetFileNameWithoutExtension(fullBundlepath) + ".prefab";bundle = DownloadHandlerAssetBundle.GetContent(request);}else{Debug.Log($"load bundle ok: {desPlatform}");prefabName = UtilsFunc.GetFileNameWithoutExtension(desPlatform) + ".prefab";bundle = DownloadHandlerAssetBundle.GetContent(request);}}
#elseUnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(desPlatform);yield return request.SendWebRequest();if (request.result != UnityWebRequest.Result.Success){Debug.LogError($"Failed to load asset bundle at path: {desPlatform}");request = UnityWebRequestAssetBundle.GetAssetBundle(fullBundlepath);yield return request.SendWebRequest();if (request.result != UnityWebRequest.Result.Success){Debug.LogError($"Failed to load asset bundle at path: {fullBundlepath}");yield break;}Debug.Log($"load bundle ok: {fullBundlepath}");prefabName = UtilsFunc.GetFileNameWithoutExtension(fullBundlepath) + ".prefab";bundle = DownloadHandlerAssetBundle.GetContent(request);}else {Debug.Log($"load bundle ok: {desPlatform}");prefabName = UtilsFunc.GetFileNameWithoutExtension(desPlatform) + ".prefab";bundle = DownloadHandlerAssetBundle.GetContent(request);}#endif}if (bundle == null) {Debug.LogError($"Failed to get asset bundle content at path: {fullBundlepath}");yield break;}loadedAssetBundles.Add(prefabPath, bundle);}void doCallBack(string prefabPath, UnityEngine.Object asset = null) {if (asset == null) {m_loadingActions.Remove(prefabPath);return;}m_loadingActions.TryGetValue(prefabPath, out var list);if (list != null) {foreach (var action in list) {GameObject prefab = Instantiate(asset) as GameObject;action(prefab);}m_loadingActions.Remove(prefabPath);}else {Debug.LogError($"doCallBack {prefabPath}");}}public async Task<UnityWebRequest> LoadSceneSync(string sceneName) {string fullBundlepath = $"{Host.AssetBundleIP}/scenes/{sceneName.ToLower()}.bundle";UnityWebRequest www = UnityWebRequestAssetBundle.GetAssetBundle(fullBundlepath);var asyncOp = await www.SendWebRequest();if (asyncOp.result != UnityWebRequest.Result.Success) {Debug.LogError(www.error);}else {Debug.Log("LoadSceneSync");DownloadHandlerAssetBundle.GetContent(www);await SceneManager.LoadSceneAsync(sceneName);ResetSceneAllMaterials();}return asyncOp;}private void ResetSceneAllMaterials() {
#if UNITY_EDITORvar scene = SceneManager.GetActiveScene();GameObject[] roots = scene.GetRootGameObjects();foreach (GameObject root in roots) {var renderers = root.GetComponentsInChildren<Renderer>();foreach (var render in renderers) {ResetMaterials(render.materials);}}if (RenderSettings.skybox != null)RenderSettings.skybox.shader = Shader.Find(RenderSettings.skybox.shader.name);
#endif}private void ResetMaterials(Material[] materials) {foreach (Material m in materials) {var shaderName = m.shader.name;if (shaderName == "Hidden/InternalErrorShader")continue;var newShader = Shader.Find(shaderName);if (newShader != null) {m.shader = newShader;}else {Debug.LogWarning("unable to refresh shader: " + shaderName + " in material " + m.name);}}}private  void ResetBundleMaterials(AssetBundle bundle) {#if UNITY_EDITORvar materials = bundle.LoadAllAssets<Material>();ResetMaterials(materials);
#endif}void OnDestroy() {foreach (var bundle in loadedAssetBundles.Values) {bundle.Unload(true);}loadedAssetBundles.Clear();}
}
public static class Host
{/// <summary>/// 如果StreamAsset CONFIG 里面有配置AssetBundleIP,则使用那边的/// </summary>public static string AssetBundleIP = Application.dataPath.Replace("Assets", "") + "ABundles/webgl";public static string gameServer = "";public static string ApiHost = "";public static string remote = "";
}

10.新建一个UI预设体:

这个界面的业务脚本:WarningPanel

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;public class WarningPanel : BasePanel
{static string showText;public Text text;public GameObject confirmBtn;public GameObject closeBtn;private static Action confirmCallBack;private static Action closeCallBack;public static void Show(string showText,Action confirmBack,Action closeBack){WarningPanel.showText = showText;WarningPanel.confirmCallBack = confirmBack;WarningPanel.closeCallBack = closeBack;UIManager.Instance.PushPanel(UIPanelType.WARNING_PANEL);}public override void OnEnter(){base.OnEnter();text.text = WarningPanel.showText;confirmBtn.GetComponent<Button>().onClick.AddListener(onClickConfirm);if(closeBtn!=null) closeBtn.GetComponent<Button>().onClick.AddListener(onClickClose);}private void onClickClose(){if (WarningPanel.closeCallBack != null) {WarningPanel.closeCallBack();}}IEnumerator WaitHide(){yield return new WaitForSeconds(2f);gameObject.SetActive(false);}private void onClickConfirm(){if (WarningPanel.confirmCallBack != null){WarningPanel.confirmCallBack();//StopAllCoroutines();//StartCoroutine(WaitHide());}gameObject.SetActive(false);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/620966.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android-基础

Activity生命周期 1.启动Activity&#xff1a;系统会先调用onCreate方法&#xff0c;然后调用onStart方法&#xff0c;最后调用onResume&#xff0c;Activity进入运行状态。 2.当前Activity被其他Activity覆盖其上或被锁屏&#xff1a;系统会调用onPause方法&#xff0c;暂停当…

Pandas实战100例-专栏介绍

Pandas&#xff0c;Python数据科学的心脏&#xff0c;是探索和分析数据世界的强大工具。想象一下&#xff0c;用几行代码就能洞察庞大数据集的秘密&#xff0c;无论是金融市场趋势还是社交媒体动态。 通过Pandas&#xff0c;你可以轻松地整理、清洗、转换数据&#xff0c;将杂…

山西电力市场日前价格预测【2024-01-15】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2024-01-15&#xff09;山西电力市场全天平均日前电价为399.10元/MWh。其中&#xff0c;最高日前电价为583.33元/MWh&#xff0c;预计出现在18:15。最低日前电价为275.09元/MWh&#xff0c;预计…

【MySQL】:探秘主流关系型数据库管理系统及SQL语言

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; MySQL从入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. MySQL概述1.1 数据库相关概念1.2 主流数据库1.3 数据模型1.3.1 关系型数据库…

MyBatis第三课

目录 回顾 #和$区别 #&#xff08;预编译SQL&#xff09;和$&#xff08;即时SQL&#xff0c;它是进行的字符串拼接&#xff09;的区别&#xff0c;其中之一就是预编译SQL和即时SQL的区别 原因&#xff1a; 回顾 两者的共同点 MaBits可以看作是Java程序和Mysql的沟通桥梁&…

VMware workstation安装debian-12.1.0虚拟机(最小化安装)并配置网络

VMware workstation安装debian-12.1.0虚拟机&#xff08;最小化安装&#xff09;并配置网络 Debian 是一个完全自由的操作系统&#xff01;Debian 有一个由普罗大众组成的社区&#xff01;该文档适用于在VMware workstation平台安装最小化安装debian-12.1.0虚拟机。 1.安装准…

Linux Ubuntu搭建我的世界Minecraft服务器实现好友远程联机MC游戏

文章目录 前言1. 安装JAVA2. MCSManager安装3.局域网访问MCSM4.创建我的世界服务器5.局域网联机测试6.安装cpolar内网穿透7. 配置公网访问地址8.远程联机测试9. 配置固定远程联机端口地址9.1 保留一个固定tcp地址9.2 配置固定公网TCP地址9.3 使用固定公网地址远程联机 前言 Li…

制造领域 基础概念快速入门介绍

1、基本背景知识 本定义结合国家标准文件有所发挥&#xff0c;仅供参考。 产品&#xff1a;是生产企业向用户或市场以商品形式提供的制成品&#xff1b; 成套设备&#xff1a;在生产企业一般不用装配工序连接&#xff0c;但用于完成相互联系的使用功能的两个或两个以上的产…

【快速解决】保姆级Anaconda安装教程

目录 第一步 ​编辑第二步 ​编辑第三步 第四步 第五步 第六步 ​编辑 第七步 第八步 第九步 第一步 在anaconda清华大学开源软件镜像站下载anaconda。点击这里进入 我这里选的是windows-x86_64。 第二步 下载好以后进行安装 第三步 第四步 第五步 选择…

SpringBoot集成Skywalking实现分布式链路追踪

官方网址&#xff1a; Apache SkyWalking官方文档&#xff1a; SkyWalking 极简入门 | Apache SkyWalking下载地址&#xff1a;Downloads | Apache SkyWalking Agent&#xff1a;以探针的方式进行请求链路的数据采集&#xff0c;并向管理服务上报&#xff1b; OAP-Service&am…

一文带你了解注册信息安全专业人员CISP

CISP即"注册信息安全专业人员"&#xff0c;系国家对信息安全人员资质的最高认可。英文为Certified Information Security Professional (简称CISP)&#xff0c;CISP系经中国信息安全测评中心实施国家认证。 CISP证书涵盖方向&#xff1a; “注册信息安全工程师”&a…

kafka之java客户端实战

1. kafka的客户端 Kafka提供了两套客户端API&#xff0c;HighLevel API和LowLevel API。 HighLevel API封装了kafka的运行细节&#xff0c;使用起来比较简单&#xff0c;是企业开发过程中最常用的客户端API。 而LowLevel API则需要客户端自己管理Kafka的运行细节&#xff0c;Pa…

Manjora 中使用idm,linux通用

说明 在Mnajora中的idm需要在wine中运行&#xff0c;idm是一款很不错的下载工具&#xff0c;但是在linux不能直接使用&#xff0c;借助wine也无法使用浏览器的集成插件&#xff0c;在网上偶然发现一款第三方插件能够在linux的浏览器中将链接捕捉到idm中&#xff0c;虽然使用起…

git安装教程 Windows 附安装包链接

Git是一款分布式源代码管理工具(版本控制工具) 。 git的作用 当你需要做一个大工程的时候&#xff0c;文件的管理无疑是非常庞大的工作&#xff0c;因为你需要不断的修改更新文件内容&#xff0c;同时可能还要保留旧版本保证可以复原&#xff0c;这样就需要备份多个版本的文件…

计网期末复习(一)

计网期末复习&#xff08;一&#xff09; – WhiteNights Site 标签&#xff1a;计算机网络 诶&#xff0c;期末。诶&#xff0c;复习。 TCP/IP参考模型的网络层提供的是&#xff1f; 区别于传输层&#xff0c;网络层提供不可靠无连接的数据报服务 当时看到TCP/IP就选了可靠有…

RT-Thread学习(一)简介及基础环境配置

系列文章目录 文章目录 系列文章目录前言简要介绍配置环境修改工作时钟更改ROM空间添加FinSH串口命令提示 前言 之前学习了FreeRTOS&#xff0c;但是一直想深入学习&#xff0c;但是没有人指导&#xff0c;又不知道该如何学习&#xff0c;于是再学习一个操作系统看看情况。 简…

Docker安装Odoo17

Docker安装Odoo 前言所需环境安装步骤登录Odoo 配置数据库 前言 Odoo是一个开源的ERP框架&#xff0c;它提供了一套完整的、可定制的、模块化的企业管理软件解决方案。以下是Odoo的主要特点&#xff1a; 模块化设计&#xff1a;Odoo的各个功能都以模块的形式提供&#xff0c;包…

机器视觉系统选型-参数—景深

镜头在垂直方向上&#xff0c;能清晰成像的空间距离(清晰成像范围)&#xff0c;称为景深

【现代密码学】笔记 补充7-- CCA安全与认证加密《introduction to modern cryphtography》

【现代密码学】笔记7-- CCA安全与认证加密《introduction to modern cryphtography》 写在最前面7 CCA安全与认证加密 写在最前面 主要在 哈工大密码学课程 张宇老师课件 的基础上学习记录笔记。 内容补充&#xff1a;骆婷老师的PPT 《introduction to modern cryphtography》…

mysql数据库被黑恢复—应用层面delete删除---惜分飞

客户的mysql被人从应用层面攻击,并且删除了一些数据,导致业务无法正常使用,通过底层分析binlog确认类似恢复操作 确认这类的业务破坏是通过delete操作实现的,客户那边不太幸,客户找了多人进行恢复,现场严重破坏,老库被删除,并且还原了历史的备份文件(非故障第一现场),通过底层…