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;暂停当…

linux批量查杀进程

linux批量查杀进程 方案1&#xff1a;killall killall 命令来杀掉所有指定名称的进程。 killall -9 uwsgi这将会杀掉所有名称为 uwsgi 的进程&#xff0c;包括在后台运行的进程。 注意&#xff0c;使用 killall 命令要小心&#xff0c;因为它可能会误杀其他不相关的进程。在…

WiFi7: MLO操作之AP MLD的发现—AP的行为

原文:如果AP是AP MLD的transmitted BSSID,那么Beacon帧和Probe Response 帧必须在Reduced Neighbor Report element中包含对应各AP的TBTT Information域,并将TBTT Information Length域设置为16或者更高(见9.4.2.169.2(Neighbor AP Information field))。FILS Discovery帧…

华为HCIE课堂笔记第十五章 IPv6过渡技术

第十五章 IPv6过渡技术 15.1 简介 1、隧道技术 2、双栈技术 3、地址转换技术 15.2 隧道技术 15.2.1 ipv6 over ipv4 隧道 手工隧道&#xff1a;IPv6 Over IPv4隧道 Ipv6 Over IPv4&#xff1a;IPv6孤岛通过IPv4网络之间进行通信&#xff0c;IPv6的报文封装IPv4报文之上…

测试人员必备基本功(3)

容易被忽视的bug 第三章 查询列表容易被忽视的bug 文章目录 容易被忽视的bug第三章 查询列表容易被忽视的bug 前言1.查询角色2.接口设计 三、测试设计1.测试点2.容易发现bug的测试点如下&#xff1a; 总结 前言 一个WEB系统的所有功能模块&#xff0c;其实都是围绕“增、删、…

Pandas实战100例-专栏介绍

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

Neo4j Cypher (1):使用Cypher删除边

在Neo4j中&#xff0c;删除边&#xff08;即关系&#xff09;可以通过使用Cypher查询语言来实现。关系可以基于其类型、属性或者它连接的节点来指定和删除。以下是一些删除关系的常见方法&#xff1a; 1. 删除特定类型的关系 如果您知道关系的类型&#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的沟通桥梁&…

uniapp导航栏组件如何使用

在uni-app中&#xff0c;可以使用官方提供的uni-navigator组件来实现导航栏的功能。 具体使用步骤如下&#xff1a; 在App.vue文件中&#xff0c;引入uni-navigator组件&#xff1a; <template><view><uni-navigator /><router-view /></view>…

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…

python实现发红包

目录 一: 平均红包实现 二:随机红包 一: 平均红包实现 使用round保留两位小数,让红包大小相差不大,可以拿总钱数/总人数得到人均钱数,然后在人均钱数的一定范围内生成随机数 import random def generate_equal_red_envelope(num_envelopes, total_amount): # 平…

一条命令解决安装torch_scatter torch_sparse torch_cluster torch_spline

在相应环境下输入 pip install pyg_lib torch_scatter torch_sparse torch_cluster torch_spline_conv -f https://data.pyg.org/whl/torch-2.0.0cu118.html该命令安装了pyg_lib包以及一些与PyTorch相关的包&#xff08;torch_scatter、torch_sparse、torch_cluster、torch_sp…

一文带你了解注册信息安全专业人员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…