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.rhkb.cn/news/235028.html

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

相关文章

前端项目构建打包生成Git信息文件

系列文章目录 TypeScript 从入门到进阶专栏 文章目录 系列文章目录前言一、前端项目构建打包生成Git信息文件作用二、步骤1.引入相关的npm包1.1. **fs** 包1.2. **child_process** 包1.3. **os** 包 (非必须 如果你想生成的文件信息中包含当前电脑信息则可用)1.4. **path** 包…

基于宝塔搭建Discuz!论坛

一、安装宝塔 我是在我的虚拟机上安装图的宝塔 虚拟机版本&#xff1a;Ubuntu 18.04 wget -O install.sh https://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh 6dca892c安装完成之后在浏览器输入你的地址 https://你的域名&#xff08;或…

每天刷两道题——第十一天

1.1滑动窗口最大值 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值 。 输入&#xff1a;nums [1,3,-1,-3,5,3,6,7], k 3 输出&…

面试题-DAG 有向无环图

有向无环图用于解决前后依赖问题&#xff0c;在Apollo中用于各个组件的依赖管理。 在算法面试中&#xff0c;有很多相关题目 比如排课问题&#xff0c;有先修课比如启动问题&#xff0c;需要先启动1&#xff0c;才能启动2 概念 顶点&#xff1a; 图中的一个点&#xff0c;比…

k8s 之7大CNI 网络插件

一、介绍 网络架构是Kubernetes中较为复杂、让很多用户头疼的方面之一。Kubernetes网络模型本身对某些特定的网络功能有一定要求&#xff0c;但在实现方面也具有一定的灵活性。因此&#xff0c;业界已有不少不同的网络方案&#xff0c;来满足特定的环境和要求。 CNI意为容器网络…

C# Entity Framework 中不同的数据的加载方式

延迟加载 延迟加载是指在访问导航属性时&#xff0c;Entity Framework 会自动查询数据库并加载相关数据。这种方式在我们需要访问导航属性时比较方便&#xff0c;因为我们无需手动加载相关数据&#xff0c;而且只会在需要时才会进行查询&#xff0c;从而减少了不必要的开销。但…

模仿Activiti工作流自动建表机制,实现Springboot项目启动后自动创建多表关联的数据库与表的方案

文/朱季谦 熬夜写完&#xff0c;尚有不足&#xff0c;但仍在努力学习与总结中&#xff0c;而您的点赞与关注&#xff0c;是对我最大的鼓励&#xff01; 在一些本地化项目开发当中&#xff0c;存在这样一种需求&#xff0c;即开发完成的项目&#xff0c;在第一次部署启动时&…

C++笔记之cout高亮输出以及纯C++实现一个彩色时钟

C笔记之cout高亮输出以及纯C实现一个彩色时钟 code review! 文章目录 C笔记之cout高亮输出以及纯C实现一个彩色时钟一.cout高亮输出1.1.运行1.2.代码一1.3.代码二1.4.重置终端的文本格式到默认设置说明 二.纯C实现一个彩色时钟2.1.运行2.2.main.cc2.3.cout带颜色打印输出技巧…

springCould中的Bus-从小白开始【11】

目录 &#x1f9c2;1.Bus是什么❤️❤️❤️ &#x1f32d;2.什么是总线❤️❤️❤️ &#x1f953;3.rabbitmq❤️❤️❤️ &#x1f95e;4.新建模块3366❤️❤️❤️ &#x1f373;5.设计思想 ❤️❤️❤️ &#x1f37f;6.添加消息总线的支持❤️❤️❤️ &#x1f9…

图解Kubernetes的服务(Service)

pod 准备&#xff1a; 不要直接使用和管理Pods&#xff1a; 当使用ReplicaSet水平扩展scale时&#xff0c;Pods可能被terminated当使用Deployment时&#xff0c;去更新Docker Image Version&#xff0c;旧Pods会被terminated&#xff0c;然后创建新Pods 0 啥是服务&#xf…

OCS2 入门教程(四)- 机器人示例

系列文章目录 前言 OCS2 包含多个机器人示例。我们在此简要讨论每个示例的主要特点。 System State Dim. Input Dim. Constrained Caching Double Integrator 2 1 No No Cartpole 4 1 Yes No Ballbot 10 3 No No Quadrotor 12 4 No No Mobile Manipul…

【java爬虫】首页显示沪深300指数走势图以及前后端整合部署方法

添加首页 本文我们将在首页添加沪深300指数成立以来的整体走势数据展示&#xff0c;最后的效果是这样的 单独贴一张沪深300整体走势图 我感觉从总体上来看指数还是比较稳的&#xff0c;没有特别大的波动&#xff0c;当然&#xff0c;这只是相对而言哈哈。 首先是前端页面 &l…

【python】内存管理和数据类型问题

一、内存管理 Python有一个自动内存管理机制&#xff0c;但它并不总是按照期望的方式工作。例如&#xff0c;如果创建了一个大的列表或字典&#xff0c;并且没有删除它&#xff0c;那么这个对象就会一直占用内存&#xff0c;直到Python的垃圾回收器决定清理它。为了避免这种情…

Android开发基础(一)

Android开发基础&#xff08;一&#xff09; 本篇主要是从Android系统架构理解Android开发。 Android系统架构 Android系统的架构采用了分层的架构&#xff0c;共分为五层&#xff0c;从高到低分别是Android应用层&#xff08;System Apps&#xff09;、Android应用框架层&a…

二线厂商-线上测评-大数据开发

曾经投递过一些中级岗位&#xff0c;在面试之前&#xff0c;会通过邮件的方式把性格测试的题目发给你让你做一下。 一般分为单选题&#xff0c;多选题&#xff0c;性格测试题&#xff0c;认知理解题等等。 大概做了一个小时吧。 单选题&#xff1a; 感觉就是类似于以前高中时候…

前缀和--二维矩阵的前缀和

目录 子矩阵的和思路&#xff1a;代码&#xff1a; 原题链接 子矩阵的和 输入一个 n 行 m 列的整数矩阵&#xff0c;再输入 q 个询问&#xff0c;每个询问包含四个整数 x1,y1,x2,y2 &#xff0c;表示一个子矩阵的左上角坐标和右下角坐标。 对于每个询问输出子矩阵中所有数的和…

C#入门篇(一)

变量 顾名思义就是变化的容器&#xff0c;即可以用来存放各种不同类型数值的一个容器 折叠代码 第一步&#xff1a;#region 第二步&#xff1a;按tab键 14种数据类型 有符号的数据类型 sbyte&#xff1a;-128~127 short&#xff1a;-32768~32767 int&#xff1a;-21亿多~21亿多…

Windows 双网卡链路聚合解决方案

Windows 双网卡链路聚合解决方案 链路聚合方案1&#xff1a;Metric介绍操作 方案2&#xff1a;NetSwitchTeam介绍操作 方案3&#xff1a;NIC介绍操作 方案4&#xff1a;Intel PROSet 链路聚合 指将多个物理端口汇聚在一起&#xff0c;形成一个逻辑端口&#xff0c;以实现出/入…

Java-布隆过滤器的实现

文章目录 前言一、概述二、误差率三、hash 函数的选择四、手写布隆过滤器五、guava 中的布隆过滤器 前言 如果想要判断一个元素是不是在一个集合里&#xff0c;一般想到的是将所有元素保存起来&#xff0c;然后通过比较确定。链表&#xff0c;树等等数据结构都是这种思路&…

Linux权限2

相关命令 chown [用户名] [文件]​ 更改文件拥有者&#xff08;加sudo强制更改&#xff09; chown [拥有者]:[所属组] [文件] 更改文件拥有者和所属组&#xff08;root权限下&#xff09; chgrp [用户名] [文件] 更改文件所属组 文件类型 输入ls或ll显示的文件&#xff…