您现在的位置是:首页 >技术教程 >unity进阶学习笔记:UI框架网站首页技术教程
unity进阶学习笔记:UI框架
一般来说,一个游戏内具有大量的UI组件。如果只是使用之前的消息框架处理所有UI相关的信息会十分复杂且低效。因此我们将UI系统作为一个独立的系统进行处理,并搭建一套UI框架
UI框架主要分3层:UIManager用于管理所有UI组件,UIController用于管理某一个UI面板,如角色信息面板,商店面板等。UIControl用于控制每一个单独的UI组件
在UI系统中,我们放弃之前消息系统中使用的广播框架,因为该方案需要专门为每一个UI组件编写发送和接受消息的方法,过于复杂。我们希望通过UIController和UI Manager可以让每一个UI组件访问到任何一个另外的UI组件。如在“商店”控制器中的按钮组件可以直接更改“背包”控制器中背包格子图片,直接实现商店购买物品加入背包的功能。
1 UIManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIManager : ManagerBase<UIManager> {
public Dictionary<string, UIController> UIControllerDic = new Dictionary<string, UIController>();
public void SetActive(string controllerName, bool active) {
transform.Find(controllerName).gameObject.SetActive(active);
}
public UIControl GetUIControl(string controllerName, string controlName) {
if (UIControllerDic.ContainsKey(controllerName)) {
if (UIControllerDic[controllerName].UIControlDic.ContainsKey(controlName)) {
return UIControllerDic[controllerName].UIControlDic[controlName];
}
}
return null;
}
public override byte GetMessageType() {
return MessageType.Type_UI;
}
}
这里我们创建一个字典用于保存UIManager下面所有UIController。
在SetActive方法中控制各个UIController的开关。GetUIControl用于查找一个特点的UIControl。注意这里我们先找到对应UIController,再在UIController下面找到UIControl。这一方法可以减少要遍历的组件个数,提高效率,同时避免不同UIController下面出现同名组件的问题
UIManager uiManager = UIManager.Instance as UIManager;
注意这一句的作用。UIManager类继承ManagerBase,而ManagerBase继承SingletonBase并将其类型设为ManagerBase。这导致UIManager.Instance类型依然属于ManagerBase,出现问题。因此这里我们需要强制将ManagerBase向下转换为UIManager
2 UIController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIController : MonoBehaviour
{
public Dictionary<string, UIControl> UIControlDic = new Dictionary<string, UIControl>();
void Awake() {
UIManager.Instance.UIControllerDic.Add(transform.name, this);
foreach (Transform trans in transform) {
if (trans.gameObject.GetComponent<UIControl>() == null) {
trans.gameObject.AddComponent<UIControl>();
}
}
}
}
在UIController中创建字典用于保存该UIController下面的UIControl。
在Awake方法中,我们先在UIManager的字典里注册该组件。同时,考虑到在一个UIController下可能会有很多UI组件,手动添加会过于麻烦。于是我们遍历UIController下面的UI物体并为每一个添加UIControl组件
3 UIControl
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
public class UIControl : MonoBehaviour
{
void Awake() {
if (transform.parent != null) {
UIController controller = transform.GetComponentInParent<UIController>();
if (controller != null) {
controller.UIControlDic.Add(transform.name, this);
}
}
}
public void ChangeText(string str) {
if (GetComponent<Text>() != null) {
GetComponent<Text>().text = str;
}
}
public void ChangeImage(Sprite sprite) {
if (GetComponent<Image>() != null) {
GetComponent<Image>().sprite = sprite;
}
}
public void AddButtonClickEvent(UnityAction action) {
Button control = GetComponent<Button>();
if (control != null) {
control.onClick.AddListener(action);
}
}
public void AddSliderEvent(UnityAction<float> action) {
Slider control = GetComponent<Slider>();
if (control != null) {
control.onValueChanged.AddListener(action);
}
}
public void AddInputFieldEvent(UnityAction<string> action) {
InputField control = GetComponent<InputField>();
if (control != null) {
control.onValueChanged.AddListener(action);
}
}
}
在Awake方法里,我们将该UIControl组件注册到UIController中。这里我们已经完成了框架的搭建。后面的ChangeText,ChangeImage,AddButtonClickEvent,AddInputFieldEvent都是方便UI操作的函数。这里拿AddButtonClickEvent为例:
public void AddButtonClickEvent(UnityAction action) {
Button control = GetComponent<Button>();
if (control != null) {
control.onClick.AddListener(action);
}
}
AddButtonClickEvent参数类型为UnityAction,该类型可以理解为一个匿名方法,使用UnityAction类型需要导入UnityEngine.Events。在下面程序中我们获取到该游戏物体的按钮组件control,并在control上挂载对action的监听。
对于其他方法实现原理类似,在后续开发中还可以根据实际需求加入更多的UI控制方法。