文章目录
前言
开发一款游戏美术成本是极其高昂的,以我们常见的宣传片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
csharp
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 panels
public 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
csharp
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,然后打开这个界面即可
csharp
public void OnBtnChangeUser()
{
print("OnBtnChangeUser");
UIManager.Instance.OpenPanel(UIConst.UserPanel);
}
关闭界面,也是类似的道理,只要调用close panel即可
csharp
public void OnBtnCancel(){
print("OnBtnRename");
ClosePanel();
}
源码
整理好我会放上来
参考
【视频】https://www.bilibili.com/video/BV1zT411b7L3/
完结
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,以便我第一时间收到反馈,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~