Unity3d的ugui如果用得不好,非常的影响性能,可能很多人都不知道,其实ugui是基于网格模型渲染的,一个ugui组件就是一个Mesh,ui组件的Material为空,其实他是用了默认的Material,我们在运行游戏的时候Canvas回把所有ui的Mesh合并成一个大的ShareMesh,用于渲染。所以一般情况下,ui的DrawCall会比较少,但是不一般的情况下,我们会用到动态的ui,导致cpu实时在合并网格顶点,gpu重新渲染整个ShareMesh,这就很卡了,所以我们要尽量不要用动态的ui,这怎么可能
扯了一下不相干的事,接下来我们来讲讲怎么来写一个简单的ui系统。
一个好的框架,底层少不了接口,所以我们创建一个UI的接口IView。
// **********************************************************************
// Copyright (C) XM
// Author: 吴肖牧
// Date: 2018-04-15
// Desc:
// **********************************************************************
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IView {
/// <summary>
/// 绑定组件
/// </summary>
void BindComponent();
/// <summary>
/// 注册事件
/// </summary>
void RegistrationEvent();
/// <summary>
/// 注销事件
/// </summary>
void UnregisterEvent();
/// <summary>
/// 初始化
/// </summary>
void Init();
/// <summary>
/// 关闭
/// </summary>
void Close();
}
2.接下来我们来创建一个ui的基类UIBase。
// **********************************************************************
// Copyright (C) XM
// Author: 吴肖牧
// Date: 2018-04-15
// Desc:
// **********************************************************************
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIBase : Base, IView
{
public object[] param;
public UIType uiType;
public PanelType panelType;
protected void Awake()
{
BindComponent();
RegistrationEvent();
XMAwake();
}
protected void Start()
{
Init();
}
public virtual void XMAwake()
{
}
/// <summary>
/// 绑定组件
/// </summary>
public virtual void BindComponent()
{
}
/// <summary>
/// 注册事件
/// </summary>
public virtual void RegistrationEvent()
{
}
/// <summary>
/// 注销事件
/// </summary>
public virtual void UnregisterEvent()
{
}
/// <summary>
/// 关闭
/// </summary>
public virtual void Close()
{
}
/// <summary>
/// 初始化
/// </summary>
public virtual void Init()
{
}
private void OnDestroy()
{
UnregisterEvent();
Close();
param = null;
XMUtil.ClearMemory();
//Debug.Log("~" + name + " was destroy!");
}
}
UIBase根据你们的需求可以相应的扩展,这里只写了ui类型和层级类型。
3.然后我们随便创建一个界面UIMain
// **********************************************************************
// Copyright (C) XM
// Author: 吴肖牧
// Date: 2018-04-18
// Desc:
// **********************************************************************
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UIMain : UIBase {
public Button btn_Attack;
public override void BindComponent()
{
base.BindComponent();
}
public override void RegistrationEvent()
{
base.RegistrationEvent();
btn_Attack.onClick.AddListener(Attack);
}
public override void UnregisterEvent()
{
base.UnregisterEvent();
btn_Attack.onClick.RemoveListener(Attack);
}
public override void Close()
{
base.Close();
}
public override void Init()
{
base.Init();
}
private void Attack()
{
SendMessage(BattleEvent.Attack);
}
}
每次创建新的界面我们都在UIType上添加新的类型,用于界面的创建和销毁。
public enum UIType
{
UIMain,
}
4.最后我们写一个UIManager来管理所有的ui。
using System.Collections;
// **********************************************************************
// Copyright (C) XM
// Author: 吴肖牧
// Date: 2018-04-13
// Desc:
// **********************************************************************
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 界面类型
/// </summary>
public enum PanelType
{
MainPanel,
BottomPanel,
TopPanel,
TipPanel,
}
public class UIManager : Manager {
Dictionary<UIType, GameObject> uiMap = new Dictionary<UIType, GameObject>();
Transform MainPanel;
Transform BottomPanel;
Transform TopPanel;
Transform TipPanel;
void Awake()
{
Transform tr = AppFacade.Instance.GetManager<GameManager>(ManagerName.Game).uiRoot.transform;
MainPanel = tr.Find("MainPanel");
BottomPanel = tr.Find("BottomPanel");
TopPanel = tr.Find("TopPanel");
TipPanel = tr.Find("TipPanel");
}
/// <summary>
/// 打开界面
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public GameObject Show(string path,object[] param = null)
{
GameObject ui = ResManager.CreateAsset(path);
UIBase uibase = ui.GetComponent<UIBase>();
uibase.param = param;
SetPanelParent(uibase);
ui.transform.localScale = Vector3.one;
ui.transform.localPosition = Vector3.zero;
ui.transform.rectTransform().sizeDelta = new Vector2(0, 0);
ui.transform.rectTransform().anchoredPosition = new Vector2(0, 0);
AddUI(uibase.uiType, ui);
return ui;
}
/// <summary>
/// 设置ui的父对象
/// </summary>
/// <param name="go"></param>
void SetPanelParent(UIBase uibase)
{
if (uibase.panelType == PanelType.MainPanel)
{
uibase.transform.SetParent(MainPanel);
}
else if (uibase.panelType == PanelType.BottomPanel)
{
uibase.transform.SetParent(BottomPanel);
}
else if (uibase.panelType == PanelType.TopPanel)
{
uibase.transform.SetParent(TopPanel);
}
else if (uibase.panelType == PanelType.TipPanel)
{
uibase.transform.SetParent(TipPanel);
}
}
void AddUI(UIType uiType, GameObject ui)
{
uiMap.Add(uiType, ui);
}
void RemoveUI(UIType uiType)
{
if (uiMap.ContainsKey(uiType))
{
Destroy(uiMap[uiType]);
uiMap.Remove(uiType);
}
else
{
Debug.LogError("CloseUI Fail >>>> Not Find " + name);
}
}
/// <summary>
/// 关闭面板
/// </summary>
/// <param name="name"></param>
public void Close(UIType uiType)
{
RemoveUI(uiType);
}
void OnDestroy()
{
//Debug.Log("~UIManager was destroy!");
}
}
我写的这个ui系统是很简单的,主要就是面向对象的思路展示,并不是作为一个框架中完整的UI系统来写的,所以有需要的朋友可以自行拓展。
如果有关注我的朋友,应该看过另一篇文章《Unity3D创建C#自定义模板快速实现基类接口》,我们可以创建一个UI的模版,每次创建新的界面都会自动帮我们实现基类的方法。