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_EDITOR
AppConst.UseAssetBundle = true;
#endif
mPanelPool.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_EDITOR
var 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_EDITOR
AppConst.UseAssetBundle = true;
#endif
if (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_EDITOR
if (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);
}
}
#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}");
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);
}
#endif
loadedAssetBundles.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_EDITOR
if (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);
}
}
#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);
}
#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_EDITOR
var 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_EDITOR
var 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);
}
}