当游戏里的界面多了之后,如果没有管理的话是很很不方便的,因此我在网上查找资料学习之后,写了一个简单版本的UI框架。目前功能很基础,后续会慢慢更新
点击按钮可以打开对应的界面,并暂停所有其他界面(不可以交互),当关闭当前的界面后,上一个被打开的界面会恢复暂停状态(可以被交互)且可以按顺序回到上个界面,如打开界面的顺序为ABCD,从D开始关闭界面会依次打开CBA界面
一共有如下几个类
从面板基类开始,这里界面分为:进入事件,暂停事件,恢复事件,退出事件,还有关闭事件,包括一个初始化的方法。这里是用了canvasgroup来控制界面的显示和隐藏。代码如下
public class BasePanel : MonoBehaviour
{
private CanvasGroup canvasGroup;
private Button closeBtn;
private void Awake()
{
Init();
}
private void Init()
{
canvasGroup = this.GetComponent<CanvasGroup>();
if (canvasGroup == null) canvasGroup = gameObject.AddComponent<CanvasGroup>();
Transform btn = this.transform.Find("Close");
if (btn!=null)
{
closeBtn= btn.GetComponent<Button>();
closeBtn.onClick.AddListener(Close);
}
}
/// <summary>
/// 进入面板
/// </summary>
public virtual void OnEnter()
{
canvasGroup.alpha = 1;
canvasGroup.blocksRaycasts = true;
}
/// <summary>
/// 暂停面板
/// </summary>
public virtual void OnPause()
{
canvasGroup.alpha = 1;
canvasGroup.blocksRaycasts = false;
}
/// <summary>
/// 恢复暂停
/// </summary>
public virtual void OnResume()
{
canvasGroup.alpha = 1;
canvasGroup.blocksRaycasts = true;
}
/// <summary>
/// 退出面板
/// </summary>
public virtual void OnExit()
{
canvasGroup.alpha = 0;
canvasGroup.blocksRaycasts = false;
}
/// <summary>
/// 关闭按钮
/// </summary>
public void Close()
{
UIManager.Manager.PopPanel();
}
}
然后是2个UI信息类
public class UIPanel
{
public UIPanelType uiPanelType;//界面类型
public string uiPanelPath;//界面路径
public UIPanel()
{ }
public UIPanel(string path, UIPanelType type)
{
uiPanelPath = path;
uiPanelType = type;
}
}
public enum UIPanelType
{
MainMenuPanel,
SystemSettingPanel,
StorePanel,
SecondPanel,
}
最后是核心管理类,这里用了栈进行存储操作,并把此类做成了单例
public class UIManager
{
/// <summary>
/// 预制体路径
/// </summary>
readonly string panelPreafabPath = Application.dataPath + @"/Resources/UIPanelPrefab";
/// <summary>
/// json文件路径
/// </summary>
readonly string jsonPath = Application.dataPath + @"/Json/UIJson.json";
/// <summary>
/// UIManager单例
/// </summary>
private static UIManager manager;
public static UIManager Manager
{
get
{
if (manager == null)manager = new UIManager();
return manager;
}
}
/// <summary>
/// 场景中的Canvas
/// </summary>
private Transform canvasTransform;
public Transform CanvasTransform
{
get
{
if (canvasTransform==null)canvasTransform = GameObject.Find("Canvas").transform;
return canvasTransform;
}
}
/// <summary>
/// 存储所有panel
/// </summary>
private List<UIPanel> panelList;
/// <summary>
/// 存储所有BasePanel
/// </summary>
private Dictionary<UIPanelType, BasePanel> panelDic;
/// <summary>
/// 存储当前正在展示的界面
/// </summary>
private Stack<BasePanel> panelStack;
private UIManager()
{
SaveUIPanelInfoToJson();
}
/// <summary>
/// 根据路径读取json文件并返回list
/// </summary>
/// <param name="jsonPath">json路径</param>
/// <returns></returns>
public List<UIPanel> ReadJsonFile(string jsonPath)
{
if (!File.Exists(jsonPath)) File.WriteAllText(jsonPath, "[]");
List<UIPanel> list = JsonMapper.ToObject<List<UIPanel>>(File.ReadAllText(jsonPath));
return list;
}
/// <summary>
/// 根据路径写入json到本地文件
/// </summary>
/// <param name="jsonPath">json路径</param>
/// <param name="panels">list对象</param>
public void WriteJsonFile(string jsonPath,List<UIPanel> panels)
{
string json = JsonMapper.ToJson(panels);
File.WriteAllText(jsonPath,json);
}
/// <summary>
/// 根据预制体写入json到本地
/// </summary>
public void SaveUIPanelInfoToJson()
{
panelList = ReadJsonFile(jsonPath);
//读取文件夹信息
DirectoryInfo folder = new DirectoryInfo(panelPreafabPath);
foreach (FileInfo file in folder.GetFiles("*.prefab"))
{
//获取panel类型
UIPanelType type = (UIPanelType)Enum.Parse(typeof(UIPanelType), file.Name.Replace(".prefab", ""));
//组合path拿到路径
string path= @"UIPanelPrefab/" + file.Name.Replace(".prefab", "");
//判断是否查找成功
bool UIPanelISInList = false;
UIPanel uiPanel = panelList.SearchPanelForType(type);
if (uiPanel!=null)//如果有就更新一下luj
{
uiPanel.uiPanelPath = path;
UIPanelISInList = true;
}
if (!UIPanelISInList)//如果没有就新建一个并加入list
{
UIPanel panel = new UIPanel(path, type);
panelList.Add(panel);
}
}
WriteJsonFile(jsonPath, panelList);
AssetDatabase.Refresh();
}
/// <summary>
/// 获取对应的界面
/// </summary>
/// <param name="type">界面的类型</param>
/// <returns></returns>
public BasePanel GetPanel(UIPanelType type)
{
if (panelDic==null)panelDic = new Dictionary<UIPanelType, BasePanel>();
BasePanel panel = panelDic.TryGetValue(type);
if (panel==null)
{
string path = panelList.SearchPanelForType(type).uiPanelPath;
if (path==null)
throw new Exception("查无此UIPanelType的Prefab");
if (Resources.Load(path) == null)
throw new Exception("无法找到该路径下的prefab");
GameObject instPanel = GameObject.Instantiate(Resources.Load(path)) as GameObject;
instPanel.transform.SetParent(CanvasTransform, false);
panelDic.Add(type, instPanel.GetComponent<BasePanel>());
return instPanel.GetComponent<BasePanel>();
}
return panel;
}
/// <summary>
/// 界面入栈
/// </summary>
/// <param name="type"></param>
public void PushPanel(UIPanelType type)
{
if (panelStack==null)panelStack = new Stack<BasePanel>();
if (panelStack.Count>0)
{
BasePanel topPanel = panelStack.Peek();
topPanel.OnPause();
}
BasePanel panel = GetPanel(type);
panelStack.Push(panel);
panel.OnEnter();
}
/// <summary>
/// 界面出栈
/// </summary>
public void PopPanel()
{
if (panelStack == null) panelStack = new Stack<BasePanel>();
if (panelStack.Count <= 0) return;
BasePanel topPanel = panelStack.Pop();
topPanel.OnExit();
if (panelStack.Count <= 0) return;
BasePanel topPanel2 = panelStack.Peek();
topPanel2.OnResume();
}
}
最后2个拓展方法