文章目录
- 前言
- 整套框架分为三大部分
- 框架代码
- 调用
- 源码
- 参考
- 完结
前言
开发一款游戏美术成本是极其高昂的,以我们常见的宣传片CG为例,动辄就要成百上千万的价格,因此这种美术物料一般只会放在核心剧情节点,引爆舆论,做高潮展示!
而另外一种表意方武:则是通过玩法设计,层层导玩家深入探讨游戏世界,这里则需要策划的精心设计和程序的秃头爆肝,因此对于绝大多数游戏而言,选择UI来进行剧情展示、玩法交互和核心表达才是最物美价廉的选择。
unity在4.6版本之后,引入了自己的界面显示系统,全称unity graphic user interface,即我们所熟知的ugui,毕竟是unity的亲儿子,这个系统一经推出,就与其灵活快速可视化。
迅速抢占用户市场,逐渐成为unity ui的主流系统,但是它也并不是完美的,对于开发人员来说,使用这套系统往往需要面对如下困境,比如缺乏跨场景的u管理器,界面的上下层关系紊乱三,界面之间的通信手段贫乏等等,上述几个问题大大影响到我们的开发效率。
上述几个问题大大影响到我们的开发效率,因此针对上述问题,我在此分享一套简单易用的框架,这套框架是b站up小棋参考了网上的大量资料,并结合个人工作经验,一个代码一个代码敲出来的,绝对是良心干货,所以废话少说,让我们开始吧!
整套框架分为三大部分
在游戏运行时,我们会把界面配置关系配置在UIManager中,当我们创建好了一个界面,比如用户列表界面,那么我们就给这个界面取一个名,并且把它放在prefab下的一个文件夹,并且配置在这个配置关系表中,后面我们在新创建一些界面,比如菜单界面,也可以把它配置在这个界面关系配置表中
我总共使用了三个界面来举例,最后一个界面是创建新用户的一个界面,总共配了三个配置关系,包含名称、路径和预制体
配置完成后,我们给UIManager提供两个最重要的方法,一个是OpenPanel和ClosePanel,用于打开界面和关闭界面,介绍完框架的设计
我们就可以开始书写代码了
打开游戏编辑器,我们首先在一个空场景中创建canvas画布,并且将其参数设置为合适的范围和类型,这个主要根据自己项目来设置
接着我们使用工程中的ui素材拼接界面,我这里分了如下几个界面,主菜单界面,用户列表界面和新用户界面等等,最后把这些界面拖拽到resources下的某个目录,将其制作成预制件执行
加入代码后,最终的运行效果就是这样的
框架代码
UIManager.cs
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
// 用户界面管理器
public class UIManager
{// 单例模式的实例private static UIManager _instance;// 用户界面的根节点private Transform _uiRoot;// 路径配置字典private Dictionary<string, string> pathDict;// 预制件缓存字典private Dictionary<string, GameObject> prefabDict;// 已打开界面的缓存字典public Dictionary<string, BasePanel> panelDict;// 获取单例模式的实例public static UIManager Instance{get{if (_instance == null){_instance = new UIManager();}return _instance;}}// 获取用户界面的根节点public Transform UIRoot{get{if (_uiRoot == null){if (GameObject.Find("Canvas")){_uiRoot = GameObject.Find("Canvas").transform;}else{_uiRoot = new GameObject("Canvas").transform;}};return _uiRoot;}}// 用户界面管理器的构造函数private UIManager(){InitDicts();}// 初始化字典private void InitDicts(){prefabDict = new Dictionary<string, GameObject>();panelDict = new Dictionary<string, BasePanel>();pathDict = new Dictionary<string, string>(){{UIConst.AllCardPanel, "Menu/AllCardPanel"},{UIConst.MenuPanel, "Menu/MenuPanel"},{UIConst.MainMenuPanel, "Menu/MainMenuPanel"},{UIConst.MenuTipPanel, "Menu/MenuTipPanel"},{UIConst.NewUserPanel, "Menu/NewUserPanel"},{UIConst.UserPanel, "Menu/UserPanel"},{UIConst.ReNameUserPanel, "Menu/ReNameUserPanel"},};}// 打开面板public BasePanel OpenPanel(string name){BasePanel panel = null;// 检查是否已打开if (panelDict.TryGetValue(name, out panel)){Debug.Log("界面已打开: " + name);return null;}// 检查路径是否配置string path = "";if (!pathDict.TryGetValue(name, out path)){Debug.Log("界面名称错误,或未配置路径: " + name);return null;}// 使用缓存预制件GameObject panelPrefab = null;if (!prefabDict.TryGetValue(name, out panelPrefab)){string realPath = "Prefab/Panel/" + path;panelPrefab = Resources.Load<GameObject>(realPath) as GameObject;prefabDict.Add(name, panelPrefab);}// 打开界面GameObject panelObject = GameObject.Instantiate(panelPrefab, UIRoot, false);panel = panelObject.GetComponent<BasePanel>();panelDict.Add(name, panel);panel.OpenPanel(name);return panel;}// 关闭面板public bool ClosePanel(string name){BasePanel panel = null;if (!panelDict.TryGetValue(name, out panel)){Debug.Log("界面未打开: " + name);return false;}panel.ClosePanel();// panelDict.Remove(name);return true;}// 显示提示public void ShowTip(string tip){MenuTipPanel menuTipPanel = OpenPanel(UIConst.MenuTipPanel) as MenuTipPanel;menuTipPanel.InitTip(Globals.TipCreateOne);}
}// 用户界面常量
public class UIConst
{// menu panelspublic const string AllCardPanel = "AllCardPanel";public const string MenuPanel = "MenuPanel";public const string MainMenuPanel = "MainMenuPanel";public const string MenuTipPanel = "MenuTipPanel";public const string NewUserPanel = "NewUserPanel";public const string UserPanel = "UserPanel";public const string ReNameUserPanel = "ReNameUserPanel";
}
BasePanel.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class BasePanel : MonoBehaviour // 基础面板类,继承自MonoBehaviour
{protected bool isRemove = false; // 是否移除,默认为否protected new string name; // 面板名称public virtual void SetActive(bool active) // 设置面板活动状态{gameObject.SetActive(active); // 设置游戏对象活动状态}public virtual void OpenPanel(string name) // 打开面板方法{this.name = name; // 设置面板名称SetActive(true); // 设置面板为活动状态}public virtual void ClosePanel() // 关闭面板方法{isRemove = true; // 设置移除状态为是SetActive(false); // 设置面板为非活动状态Destroy(gameObject); // 销毁游戏对象if (UIManager.Instance.panelDict.ContainsKey(name)) // 如果UI管理器的面板字典包含该面板{UIManager.Instance.panelDict.Remove(name); // 从字典中移除该面板}}
}
调用
以我视频中所示的这些界面为例,每一个界面我都会给他们挂接上一个脚本,这些脚本继承自base panel,比如在主菜单界面,当我点击修改用户时,则会弹出用户列表的这个界面,这时候我只需要调用UIManager.Instance.OpenPanel,然后打开这个界面即可
public void OnBtnChangeUser()
{print("OnBtnChangeUser");UIManager.Instance.OpenPanel(UIConst.UserPanel);
}
关闭界面,也是类似的道理,只要调用close panel即可
public void OnBtnCancel(){print("OnBtnRename");ClosePanel();
}
源码
整理好我会放上来
参考
【视频】https://www.bilibili.com/video/BV1zT411b7L3/
完结
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,以便我第一时间收到反馈,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~