299 lines
9.0 KiB
C#
299 lines
9.0 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Threading.Tasks;
|
|
using TMPro;
|
|
using UnityEngine;
|
|
using UnityEngine.AddressableAssets;
|
|
using UnityEngine.ResourceManagement.AsyncOperations;
|
|
using UnityEngine.U2D;
|
|
using UnityEngine.UI;
|
|
|
|
/// <summary>
|
|
/// 子 UI 管理器:不继承 MonoBehaviour,适合子场景/模块内局部面板管理
|
|
/// </summary>
|
|
public class SubUIManager
|
|
{
|
|
public UIBase parentUIBase;
|
|
public readonly Transform parent;
|
|
private readonly Dictionary<UIPanel, SubUIBase> panels = new Dictionary<UIPanel, SubUIBase>();
|
|
private readonly Dictionary<UIPanel, string> addressMap = new Dictionary<UIPanel, string>();
|
|
public GameObject boardCast_Boss;
|
|
|
|
// ⭐ prefab 缓存:避免重复 LoadAssetAsync
|
|
private readonly Dictionary<UIPanel, GameObject> prefabCache = new Dictionary<UIPanel, GameObject>();
|
|
// ⭐ handle 缓存:用于 Addressables.Release
|
|
private readonly Dictionary<UIPanel, AsyncOperationHandle<GameObject>> handleCache = new Dictionary<UIPanel, AsyncOperationHandle<GameObject>>();
|
|
|
|
public void ShowBoardBoss(Sprite sprite, string str)
|
|
{
|
|
if (sprite != null && boardCast_Boss != null)
|
|
{
|
|
parentUIBase.StartCoroutine(IEShowBoardGongGao(sprite, str));
|
|
}
|
|
|
|
}
|
|
public float speedGongGao;
|
|
IEnumerator IEShowBoardGongGao(Sprite sprite, string str)
|
|
{
|
|
var obj = GameObject.Instantiate(boardCast_Boss, parent);
|
|
|
|
obj.transform.SetAsLastSibling();
|
|
obj.transform.GetChild(0).GetComponent<TextMeshProUGUI>().text = str+"来了";
|
|
obj.transform.GetChild(1).GetComponent<Image>().sprite = sprite;
|
|
yield return new WaitForSeconds(1);
|
|
float a = 1;
|
|
Color c;
|
|
TextMeshProUGUI t = obj.transform.GetChild(0).GetComponent<TextMeshProUGUI>();
|
|
Image i = obj.GetComponent<Image>();
|
|
while (true)
|
|
{
|
|
a -= Time.deltaTime;
|
|
yield return null;
|
|
c = i.color;
|
|
c.a = a;
|
|
i.color = c;
|
|
|
|
c = t.color;
|
|
c.a = a;
|
|
t.color = c;
|
|
if (a < 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
GameObject.Destroy(obj);
|
|
|
|
}
|
|
public T Get<T>(UIPanel type) where T : UIBase
|
|
{
|
|
return panels.TryGetValue(type, out var panel) ? panel as T : null;
|
|
}
|
|
public SubUIManager(Transform parent, UIPanelAddressConfig uIPanelAddressConfig,UIBase parentUIBase)
|
|
{
|
|
this.parent = parent;
|
|
this.parentUIBase = parentUIBase;
|
|
foreach (var entry in uIPanelAddressConfig.panels)
|
|
{
|
|
if (!addressMap.ContainsKey(entry.type))
|
|
addressMap.Add(entry.type, entry.address);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 这里使用C#的异步所以操作建议在onshown中进行要不然外面的函数要加异步
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
/// <param name="args"></param>
|
|
/// <param name="onShown"></param>
|
|
public async void ShowAsync(UIPanel type, object args = null)
|
|
{
|
|
if (addressMap.ContainsKey(type)) {
|
|
|
|
UIBase uIBase = await LoadAndShowAsync(type, addressMap[type], args);
|
|
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("当前页面不存在");
|
|
}
|
|
|
|
}
|
|
/// <summary>
|
|
/// 这里使用C#的异步所以操作建议在onshown中进行要不然外面的函数要加异步
|
|
/// </summary>
|
|
/// <param name="type"></param>
|
|
/// <param name="args"></param>
|
|
/// <param name="onShown"></param>
|
|
public async void ShowAsync(UIPanel type, System.Action args)
|
|
{
|
|
if (addressMap.ContainsKey(type))
|
|
{
|
|
args?.Invoke();
|
|
UIBase uIBase = await LoadAndShowAsync(type, addressMap[type], null);
|
|
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("当前页面不存在");
|
|
}
|
|
|
|
}
|
|
private async Task<SubUIBase> LoadAndShowAsync(UIPanel type, string address, object args = null)
|
|
{
|
|
if (panels.TryGetValue(type, out var existing) && existing != null)
|
|
{
|
|
existing.Show(args);
|
|
return existing;
|
|
}
|
|
|
|
if (!addressMap.TryGetValue(type, out var obj) || obj == null)
|
|
{
|
|
Debug.LogError($"[SubUI] No prefab for {type}");
|
|
return null;
|
|
}
|
|
|
|
// ⭐ 优先用已缓存的 prefab
|
|
GameObject prefab = null;
|
|
if (prefabCache.TryGetValue(type, out prefab))
|
|
{
|
|
var instance = GameObject.Instantiate(prefab, parent).GetComponent<SubUIBase>();
|
|
instance.uIManager = this;
|
|
instance.name = $"Sub_{type}_Panel";
|
|
instance.Init(type);
|
|
instance.transform.SetAsLastSibling();
|
|
panels[type] = instance;
|
|
instance.Show(args);
|
|
return instance;
|
|
}
|
|
|
|
AsyncOperationHandle<GameObject> handle = Addressables.LoadAssetAsync<GameObject>(address);
|
|
await handle.Task; // 等待异步完成
|
|
|
|
if (handle.Status == AsyncOperationStatus.Succeeded)
|
|
{
|
|
prefabCache[type] = handle.Result;
|
|
handleCache[type] = handle;
|
|
|
|
var instance2 = GameObject.Instantiate(handle.Result, parent).GetComponent<SubUIBase>();
|
|
instance2.uIManager = this;
|
|
instance2.name = $"Sub_{type}_Panel";
|
|
instance2.Init(type);
|
|
instance2.transform.SetAsLastSibling(); // 新面板放到最上层
|
|
panels[type] = instance2;
|
|
instance2.Show(args);
|
|
return instance2;
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError($"Failed to load UI prefab at {address}");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void Hide(UIPanel type)
|
|
{
|
|
if (panels.TryGetValue(type, out var panel) && panel != null)
|
|
panel.Hide();
|
|
}
|
|
public void Hide(SubUIBase type)
|
|
{
|
|
|
|
foreach (var panel in panels.Values)
|
|
{
|
|
if (panel== type)
|
|
{
|
|
panel.Hide();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
public void Close(UIPanel type)
|
|
{
|
|
if (panels.TryGetValue(type, out var panel) && panel != null)
|
|
{
|
|
panel.Hide();
|
|
GameObject.Destroy(panel.gameObject);
|
|
}
|
|
panels.Remove(type);
|
|
}
|
|
|
|
public void CloseAll()
|
|
{
|
|
foreach (var kv in panels)
|
|
{
|
|
if (kv.Value != null)
|
|
{
|
|
kv.Value.Hide();
|
|
GameObject.Destroy(kv.Value.gameObject);
|
|
}
|
|
}
|
|
panels.Clear();
|
|
}
|
|
|
|
// ==================== 预加载 / 释放(优化加载速度)==================
|
|
|
|
/// <summary>
|
|
/// 预加载 config 里所有子面板的 prefab 到缓存。
|
|
/// 调用时机:父面板 OnShow 时调用,之后打开任何子面板都秒开。
|
|
/// </summary>
|
|
public async void PreloadAll(System.Action onDone = null)
|
|
{
|
|
var todo = new List<KeyValuePair<UIPanel, string>>();
|
|
foreach (var kv in addressMap)
|
|
{
|
|
if (!prefabCache.ContainsKey(kv.Key) && !string.IsNullOrEmpty(kv.Value))
|
|
todo.Add(kv);
|
|
}
|
|
|
|
if (todo.Count == 0)
|
|
{
|
|
onDone?.Invoke();
|
|
return;
|
|
}
|
|
|
|
var handles = new List<AsyncOperationHandle<GameObject>>();
|
|
foreach (var kv in todo)
|
|
{
|
|
var handle = Addressables.LoadAssetAsync<GameObject>(kv.Value);
|
|
handleCache[kv.Key] = handle;
|
|
handles.Add(handle);
|
|
}
|
|
|
|
// 等待全部完成
|
|
bool allDone = false;
|
|
while (!allDone)
|
|
{
|
|
allDone = true;
|
|
foreach (var h in handles)
|
|
{
|
|
if (!h.IsDone)
|
|
{
|
|
allDone = false;
|
|
break;
|
|
}
|
|
}
|
|
if (!allDone) await Task.Yield();
|
|
}
|
|
|
|
foreach (var kv in todo)
|
|
{
|
|
if (handleCache.TryGetValue(kv.Key, out var h) && h.Status == AsyncOperationStatus.Succeeded)
|
|
prefabCache[kv.Key] = h.Result;
|
|
}
|
|
|
|
onDone?.Invoke();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 释放所有 prefab 缓存(父面板销毁时调用)
|
|
/// </summary>
|
|
public void ReleaseAll()
|
|
{
|
|
CloseAll();
|
|
foreach (var kv in handleCache)
|
|
{
|
|
Addressables.Release(kv.Value);
|
|
}
|
|
handleCache.Clear();
|
|
prefabCache.Clear();
|
|
}
|
|
|
|
//private UIBase GetOrCreate(UIPanel type,GameObject prefab)
|
|
//{
|
|
// if (panels.TryGetValue(type, out var existing) && existing != null)
|
|
// return existing;
|
|
|
|
// if (!addressMap.TryGetValue(type, out var obj) || prefab == null)
|
|
// {
|
|
// Debug.LogError($"[SubUI] No prefab for {type}");
|
|
// return null;
|
|
// }
|
|
|
|
// var instance = Object.Instantiate(prefab, parent).GetComponent<SubUIBase>();
|
|
// instance.name = $"Sub_{type}_Panel";
|
|
// instance.Init(type);
|
|
// panels[type] = instance;
|
|
// return instance;
|
|
//}
|
|
}
|