更新

在之前做项目的学习到要让UI生成在我们制作成预制体之前的位置(一般情况下都是这样)
需要把对象池里面的生成函数变成这样

  public GameObject GetObject(string name,Transform parentTransfrom,bool InWorldSpace){GameObject obj = null;if (poolDic.ContainsKey(name) && poolDic[name].Count > 0){Debug.Log("Find item" + name);obj = poolDic[name][0];//obj.transform.position = location;poolDic[name].RemoveAt(0);}else{obj = GameObject.Instantiate(Resources.Load<GameObject>(name), parentTransfrom, InWorldSpace);//Debug.Log(name);}obj.SetActive(true);return obj;}

生成函数改成这样

 GameObject curPanel = PoolManager.GetInstance().GetObject(GetPanelString(panelType), CanvasTransform.position, false);

其他不需要做任何修改


目的

这只是针对大家做一些小游戏的时候可能用到的UI框架,主要目的在于:

  1. 不需要在Scene面板提前创建好UI,界面看起来更整洁
  2. 对象池保证UI重复利用,减少反复生成销毁的内存开销
  3. 栈管理UI,将UI分为两类:栈顶UI、其他UI;可分别对其处理。比如实现栈顶UI可交互,其他UI不交互,这里UI指代的是面板。

设计

UI的获取和放回使用对象池实现,

实现

对象池

用于得到不同面板的预制体,遇事不决对象池

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 对象池管理器,可以调用其中的函数获取对象
/// list存储游戏物体,Dictionary制作抽屉
/// </summary>
public class PoolManager : BaseManager<PoolManager> {public Dictionary<string, List<GameObject>> poolDic = new Dictionary<string, List<GameObject>>();/// <summary>/// 从池子里面取得物品/// </summary>/// <param name="name"></param>/// <returns></returns>public GameObject GetObject(string name, Vector3 location) {GameObject obj = null;if(poolDic.ContainsKey(name) && poolDic[name].Count > 0){//Debug.Log("Find item" + name);obj = poolDic[name][0];obj.transform.position = location;poolDic[name].RemoveAt(0);}else{obj = GameObject.Instantiate(Resources.Load<GameObject>(name), location, Quaternion.identity);//Debug.Log(name);}obj.SetActive(true);return obj;}public void PushObj(string name, GameObject obj){obj.SetActive(false);//已经拥有抽屉if(poolDic.ContainsKey(name)){poolDic[name].Add(obj);}//里面没有抽屉else{poolDic.Add(name, new List<GameObject>() { obj });}}/// <summary>/// 场景切换时调用/// </summary>public void Clear(){poolDic.Clear();}
}

单例基类

继承的类就能开单例

public class BaseManager<T> where T : new()
{private static T instance;public static T GetInstance(){if (instance == null){instance = new T();return instance;}else{return instance;}}
}

BasePanel

BasePanel,作为不同类型Panel的抽象基类,提供三个方法接口,继承Mono,其子类可以直接挂载在物体上。作用如注释。

using System.Collections;
using System.Collections.Generic;public abstract class BasePanel:MonoBehaviour
{/// <summary>/// 开启面板的时候调用/// </summary>public abstract void OnEnter();/// <summary>/// 当前面板在栈中而不是在栈顶的时候调用/// </summary>public abstract void OnPause();/// <summary>/// 当前面板再次处于栈顶的时候调用/// </summary>public abstract void OnResume();/// <summary>/// 关闭当前面板的时候调用/// </summary>public abstract void OnExit();
}

UIManager

管理所有的UI,提供生成UI和关闭UI的接口,制定调用BasePanel的三个函数的逻辑。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 管理所有UI,由于项目并不是很大,所以现阶段没有使用json存储所有的UI类型,UI的存取通过对象池来获得
/// 在场景切换的时候需要把数据结构清空
/// </summary>
public class UIManager : BaseManager<UIManager>
{/// <summary>/// 管理当前场景的UI的栈/// </summary>private Stack<BasePanel> panelStack;/// <summary>/// 管理状态(面板)的字典/// </summary>private Dictionary<PanelType, BasePanel> panelDict;private Transform canvasTransform;/// <summary>/// 返回面板类型对应字符串,便于对象池生成 /// </summary>/// <param name="newPanel"></param>private string GetPanelString(PanelType type){switch (type){case PanelType.StartPanel:return "StartPanel";case PanelType.TestPanel:return "TestPanel";case PanelType.TestPanel2:return "TestPanel2";default:Debug.Log($"不存在{type.ToString()}面板");break;}return "\0";}private Transform CanvasTransform {get {if(canvasTransform == null){canvasTransform = GameObject.Find("Canvas").transform;}return canvasTransform;}}public GameObject currentPanel;public UIManager(){panelStack = new Stack<BasePanel>();}private BasePanel GetUI(PanelType panelType){if(panelDict == null){panelDict = new Dictionary<PanelType, BasePanel>();}BasePanel panel;if(!panelDict.TryGetValue(panelType, out panel)){GameObject curPanel = PoolManager.GetInstance().GetObject(GetPanelString(panelType), CanvasTransform.position);curPanel.transform.SetParent(CanvasTransform);panel = curPanel.GetComponent<BasePanel>();panelDict.Add(panelType, panel);}else{panel = panelDict[panelType];GameObject curPanel = PoolManager.GetInstance().GetObject(GetPanelString(panelType), CanvasTransform.position);}return panel;}/// <summary>/// 推入一个面板/// </summary>/// <param name="newPanel"></param>public void PushPanel(PanelType panelType){if(panelStack == null){panelStack = new Stack<BasePanel>();}if(panelStack.Count > 0){BasePanel topPanel = panelStack.Peek();topPanel.OnPause();}BasePanel panel = GetUI(panelType);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){BasePanel panel = panelStack.Peek();panel.OnResume();}}
}

举个

实现一个负责开启两个面板的主面板
testButton1可以用find也可以直接拖拽赋值

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class StartPanel : BasePanel
{public Button testButton1;public Button testButton2;private CanvasGroup m_CanvasGroup;private void Start(){testButton1.onClick.AddListener(test1ButtonEvent);testButton2.onClick.AddListener(test2ButtonEvent);m_CanvasGroup = gameObject.GetComponent<CanvasGroup>();}public override void OnEnter(){Debug.Log("进入开始面板");}private void test1ButtonEvent(){UIManager.GetInstance().PushPanel(PanelType.TestPanel);}private void test2ButtonEvent(){UIManager.GetInstance().PushPanel(PanelType.TestPanel2);}public override void OnExit(){}public override void OnPause(){Debug.Log("开始界面被覆盖");m_CanvasGroup.blocksRaycasts = false;}public override void OnResume(){m_CanvasGroup.blocksRaycasts = true;}
}

GameManager

这里只负责一开始生成开始面板,挂载到主相机上面

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class GameManager : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){UIManager.GetInstance().PushPanel(PanelType.StartPanel);}// Update is called once per framevoid Update(){}
}

运行结果如下

TestPanel1/ TestPanel2

测试面板,只能开启其中一个,一个开启后,StartPanel的按钮将不会再生效,直到关闭

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TestPanel : BasePanel
{public Button exitButton;private CanvasGroup m_CanvasGroup;private void Start(){exitButton.onClick.AddListener(exitButtonAction);}public override void OnEnter(){Debug.Log("打开测试界面1");}public override void OnExit(){Debug.Log("测试界面1退出");PoolManager.GetInstance().PushObj("TestPanel", this.gameObject);}public override void OnPause(){Debug.Log("测试界面1被覆盖");m_CanvasGroup.blocksRaycasts = false;}public override void OnResume(){Debug.Log("测试界面1恢复");m_CanvasGroup.blocksRaycasts = true;}private void exitButtonAction(){UIManager.GetInstance().PopPanel();}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TestPanel2 : BasePanel
{public Button exitButton;private CanvasGroup m_CanvasGroup;private void Start(){exitButton.onClick.AddListener(exitButtonAction);}public override void OnEnter(){Debug.Log("打开测试界面2");}public override void OnExit(){Debug.Log("测试界面2退出");PoolManager.GetInstance().PushObj("TestPanel2", this.gameObject);}public override void OnPause(){Debug.Log("测试界面2被覆盖");m_CanvasGroup.blocksRaycasts = false;}public override void OnResume(){Debug.Log("测试界面2恢复");m_CanvasGroup.blocksRaycasts = true;}private void exitButtonAction(){UIManager.GetInstance().PopPanel();}
}

分别挂载到两个面板上


接下来测试
1. 按下测试按钮一、testPanel1出现

2. 尝试按下测试按钮二、没有反应
3. 关闭测试面板一后再次按下测试按钮二,出现测试面板二,并且一失活进入对象池

4. 同理尝试按下测试按钮一、没有反应
ヾ(✿゚▽゚)ノ说明成功了
ps:这里生成的UI并没有按照预制体之前的位置放在左右上角,根据更新所示的那样就行了

总结

很多情况下,当一个UI出现时我们都需要把其他UI的交互关闭,否则经常会造成各种bug,所以管理UI还是非常重要的。

Unity基础UI框架相关推荐

  1. 【2d游戏开发】unity实现UI框架搭建

    前言 前面一直比较忙,然后到现在才继续接游戏的文章,那么本次将带大家去搭建一个ui框架,同样,需要更具体的教学,可以到b站搜索本人的关于2d游戏开发-unity实现xxx的系列视频. 步骤 其实大致的 ...

  2. Unity的UI框架

    UI框架 UI框架的含义 含义:UI框架用于管理场景中所有的面板,负责控制面板之间的跳转 UI框架的意义 1.随着游戏系统的复杂化,UI控件越来越多,各个UI之间的直接通讯,已经UI与GameObje ...

  3. Unity | Unity中UI框架的实现与使用

    文章目录 0 前言 1 程序结构 2 工具类:UIPanelInfo.cs 3 PanelType枚举类以及BasePanel类 4 UIManager类 5 UIPanelJson文件 5 使用方法 ...

  4. Android开源库V - Layout:淘宝、天猫都在用的UI框架,赶紧用起来吧!

    前言 V- Layout 是阿里出品的基础 UI 框架,用于快速实现页面的复杂布局,在手机天猫 Android版 内广泛使用 让人激动的是,在上个月V- Layout终于在Github上开源! Git ...

  5. Android开源库V - Layout:淘宝、天猫都在用的UI框架,赶紧用起来吧

    前言 ● V- Layout 是阿里出品的基础 UI 框架,用于快速实现页面的复杂布局,在手机天猫 Android版 内广泛使用 ● 让人激动的是,在上个月V- Layout终于在Github上开源! ...

  6. unity ui框架_[教程汇总+持续更新]Unity从入门到入坟——收藏这一篇就够了

    ----------------塔防(更新中),作者重写了基础篇(下方目录为:1.1(新) 基础)目前还在持续连载了5篇,因为不多我们更新完就能追到原作者的进度了------------------- ...

  7. Unity UI框架的搭建

    为什么要使用UI框架呢? 在我刚使用Unity开发UI界面时,根本没想过用什么UI框架,都是想到要什么界面就通过UGUI拖动什么界面.如果需要实现交互功能,就会绑定对应的监听函数,这样的做法固然是非常 ...

  8. unity 前端场景搭建UI框架的设计

    在 Unity 前端场景中搭建 UI 框架时,可以采用以下设计方案: 基础组件库:设计一套基础组件库,包括常用的 UI 控件,如文本.按钮.图像等,组件库的设计应该尽量简单易用,方便开发者快速搭建 U ...

  9. 【Unity自己写框架】FairyGUI UI框架(一)

    笔者之前沉迷游戏无法自拔,但是现在之前玩的游戏也不太爱玩了,发现下班到睡觉之前有2-3个小时空闲,仿佛发现了一笔宝贵的财富不能浪费. 笔者从事手游工作也有两年的时间了,主要做的是逻辑和SDK方面的工作 ...

  10. 【游戏开发实战】(完结)使用Unity制作像天天酷跑一样的跑酷游戏——第七篇:游戏界面的基础UI

    文章目录 一.前言 二.导入游戏界面UI素材 三.制作游戏界面UI预设 四.事件管理器 五.编写GameMainPanel.cs脚本 六.游戏管理器添加金币逻辑 七.加金币 八.跳跃事件 九.运行测试 ...

最新文章

  1. folders默认配置 shell_分布式存储Ceph RBD-Mirror灾备方案(二)镜像模式配置
  2. java方法不可覆盖_详解Java构造方法为什么不能覆盖,我的钻牛角尖病又犯了.......
  3. el-tooltip位置不灵活_美团研究院:超五成生活服务业商户有灵活用工需求
  4. 什么是计算机系统计算机硬件和计算机软件,什么是计算机系统、计算机硬件和计算机软件?硬件和软件哪个更重要?...
  5. 批处理 安卓一键打包脚本快速解析
  6. win7 64位 系统安装mysql_5.7.19(msvce120 or DirectXRepair35.zip修复)
  7. Unity2D:简单人物纸娃娃换装实现(一) 服装的变换
  8. access数据库剔除重复项_使用Access数据库的站长看过来——如何自动去掉数据库中的重复文章...
  9. 编程之美--数组中的最长递增子序列(LIS longest increasement sequence)
  10. codevs 1296
  11. 巴比特 | 元宇宙每日必读:用户流失,滞销频现,平台在合规和利润面前该如何平衡?...
  12. 阿里实现Redis亿级存储的方案
  13. 减少在线去重造成的数据碎片
  14. MD文档的表情mark
  15. 代码战争之友人与敌人
  16. grafana+influxdb数据可视化
  17. 神族对抗人族的空投甲虫战术
  18. [转载]JScript 语法错误
  19. 计算机毕业设计Java小型企业员工工资管理系统(源码+系统+mysql数据库+Lw文档)
  20. 魅族 系统更新服务器,Flyme系统再次更新,魅族16系列基本在内,你尝鲜了吗?...

热门文章

  1. Python 快速验证代理IP是否有效
  2. 中山大学delphi视频下载(51讲)
  3. 微信小程序项目2(哔哩哔哩)
  4. julia语言 python解释器_深入Python解释器源码,我终于搞明白了字符串驻留的原理...
  5. python 小说分析_Python文章相关性分析---金庸武侠小说分析
  6. 开源项目工时系统_工时统计系统 - 服务端
  7. SIR传染病模型(微分方程系列1)
  8. 手机音频拼接软件_5款适合新手的手机音频剪辑APP
  9. 【收藏】韦东山嵌入式Linux课程梳理|随时更新
  10. 2017山东省ACM省赛总结(校史首金!!)