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);}
}