今天给大家介绍一个UI框架,我自己用的,挺好用,可以方便的切换各种Panel显示不同的界面,预备,开始。
罗列一下关键的几个类:GameManager、Singleton、UIManager、BaseWnd以及其他的继承与BaseWnd的子类。以下分别介绍各个类的主要函数及功能:
游戏管理者,游戏的入口,是一个切换场景不会销毁的类,只挂它,其他不用挂。下面来看一下他的最初的样子:
class GameManager:MonoBehaviour
{
void Start()
{
DontDestroyOnLoad(this);
}
}
只有一个不被销毁的方法,我们来看看其他的的类。
泛型类,用于定义单例模板,当然我们这个单例严格意义上来说不是真的,懂的人一看就明白,不懂的人…私信我。下面来看看代码:
class Singleton<T> where T:class,new()
{
static T instance;
public static T Instance
{
get
{
if(instance==null)
{
instance = new T();
}
return instance;
}
}
}
泛型不用说了,说说后面的where吧,万一有人不知道呢,where T代表泛型约束,就是指继承于这个类的子类,必须是符合后面的条件的,什么条件?我们这里的条件是class,new(),class:子类必须是类new():子类必须可以实例化。
其实这个类,不写也行,但那样你就得每一次需要让某个类单例的时候,就写一遍上边的代码,既增加了工作量,又显得不优雅。程序员都想偷懒,说好听点这叫复用。
UI界面管理类,单例,先看代码:
public class UIManager : Singleton<UIManager> {
Dictionary<string, BaseWnd> _allWnds;//存储所有窗口
Transform _canvasTransform;//存储Canvas的Transform,生成新窗口以后将其设置为子节点
///
/// 初始化
///
///
public void Initial(Transform canvasTransform)
{
_canvasTransform = canvasTransform;
_allWnds = new Dictionary<string, BaseWnd>();
}
///
/// 打开一个窗口,如果存在,就激活;否则,就创建一个新的
///
///
public void OpenWnd<T>()where T:BaseWnd,new()
{
string wndName = typeof(T).Name;//通过反射获取类名
if (_allWnds.ContainsKey(wndName))//如果字典中存在,则激活
{
_allWnds[wndName].Open();
}
else//否则,创建一个新的
{
T wnd = new T();
wnd.CreateWnd(wndName, _canvasTransform);
wnd.Initial();
_allWnds.Add(wndName, wnd);
}
}
///
/// 获得一个窗口,存在就返回窗口;否则,返回空
///
///
///
public T GetWnd<T>()where T:BaseWnd
{
string wndName = typeof(T).Name;
if (_allWnds.ContainsKey(wndName))
{
return _allWnds[wndName] as T;
}
return null;
}
}
获取窗口的时候采用了泛型的方法,这样比较方便,不容易出错,接下来我们看BaseWnd。
先看代码:
public abstract class BaseWnd
{
protected Transform SelfTransform { get; private set; }//当前类控制的窗口的Transform
///
/// 创建新的窗口
///
/// 窗口的名称
/// Canvas的Transform
public void CreateWnd(string wndName, Transform canvasTransform)
{
GameObject originWnd = Resources.Load<GameObject>("Wnd/" + wndName);//根据名称,读取预制体
GameObject cloneWnd = GameObject.Instantiate<GameObject>(originWnd);//克隆
SelfTransform = cloneWnd.transform;//获得克隆体的Transform
SelfTransform.SetParent(canvasTransform, false);//设置父节点
}
///
/// 抽象方法,供各个窗口子类重写,用于初始化
///
public abstract void Initial();
///
/// 激活,窗口创建以后,没有特殊需求就不销毁,只是失活和激活
///
public void Open()
{
SelfTransform.gameObject.SetActive(true);
}
///
/// 失活
///
public void Close()
{
SelfTransform.gameObject.SetActive(false);
}
}
从CreateWnd中,我们可以看出创建窗口其实是克隆预制体,这个方法需要两个参数,第一个参数是名称,名称从哪来?我们自己传字符串吗?不是的,还记得UIManager中的泛型方法吗,我们传入类,通过反射获取类名,把类的名字传到CreateWnd中,所以我们需要把创建的窗口子类的名称和窗口预制体的名称统一起来,比如我们的开始界面的窗口,预制体名称为StartWnd,子类名称就得也是StartWnd。提供了一个抽象方法,供子类重写,这样我们就可以个性化子类了。
基本框架就是这样,简单吧,接下来我们来实际的创建一个子类,就拿StartWnd开刀吧。
我们先来看下结构,最上面的是一个空节点,我取名叫GameManager,挂的是GameManager脚本 ,底下依次是:摄像机,Canvas,窗口,EventSystem。摄像机就不说了,Canvas是UI的根节点,StartWnd就是我们创建的预制体,在StartWnd下创建一个Button,取名叫StartBtn,EventSystem是UGUI的事件机制的基础。
把StartWnd拖成预制体,放在Resources目录下,然后我们创建一个类,取名为StartWnd,看下StartWnd的代码:
public class StartWnd:BaseWnd
{
public void Initial()
{
Button startBtn = SelfTransform.Find("StartBtn").GetComponent<Button>();
startBtn.onClick.AddListener(()=>{});
}
}
在Initial方法中,获取子物体,这里我们获取的是一个Button组件,用Lambda表达式来添加了一个空方法。如此一来,我们最基本的个性化子类就写好了。