【Unity小技巧】手戳一个简单易用的游戏UI框架(附源码)

前言

开发一款游戏美术成本是极其高昂的,以我们常见的宣传片CG为例,动辄就要成百上千万的价格,因此这种美术物料一般只会放在核心剧情节点,引爆舆论,做高潮展示!

而另外一种表意方武:则是通过玩法设计,层层引导玩家深入探索游戏世界,这里则需要策划的精心设计和程序的秃头爆肝,因此对于绝大多数游戏而言,选择UI来进行剧情展示、玩法交互和核心表达才是最物美价廉的选择。

unity在4.6版本之后,引入了自己的界面显示系统,全称unity graphic user interface,即我们所熟知的ugui。
在这里插入图片描述
毕竟是unity的亲儿子,这个系统一经推出,就与其灵活快速可视化,迅速抢占用户市场,逐渐成为unity ui的主流系统,但是它也并不是完美的,对于开发人员来说,使用这套系统往往需要面对如下困境,比如缺乏跨场景的u管理器,界面的上下层关系紊乱三,界面之间的通信手段贫乏等等,上述几个问题大大影响到我们的开发效率。
在这里插入图片描述
上述几个问题大大影响到我们的开发效率,因此针对上述问题,我在此分享一套简单易用的框架,这套框架是b站up小棋参考了网上的大量资料,并结合个人工作经验,一个代码一个代码敲出来的,绝对是良心干货,所以废话少说,让我们开始吧!

整套框架分为三大部分

在这里插入图片描述
在游戏运行时,我们会把界面配置关系配置在UIManager中,当我们创建好了一个界面,比如用户列表界面,那么我们就给这个界面取一个名,并且把它放在prefab下的一个文件夹,并且配置在这个配置关系表中,后面我们在新创建一些界面,比如菜单界面,也可以把它配置在这个界面关系配置表中

我总共使用了三个界面来举例,最后一个界面是创建新用户的一个界面,总共配了三个配置关系,包含名称、路径和预制体,比如下图
在这里插入图片描述

素材

请添加图片描述

效果

配置完成后,我们给UIManager提供两个最重要的方法,一个是OpenPanelClosePanel,用于打开界面和关闭界面,介绍完框架的设计
我们就可以开始书写代码了

打开游戏编辑器,我们首先在一个空场景中创建canvas画布,并且将其参数设置为合适的范围和类型,这个主要根据自己项目来设置

接着我们使用工程中的ui素材拼接界面,我这里分了如下几个界面,主菜单界面,用户列表界面和新用户界面等等,最后把这些界面拖拽到resources下的某个目录,将其制作成预制件执行
在这里插入图片描述
加入代码后,最终的运行效果就是这样的,默认只有一个Canvas组件
在这里插入图片描述

框架代码

UIConst.cs

// 用户界面路径
public class UIConst
{
    
    
    public const string MainPanel = "主界面";
    public const string UserListPanel = "用户列表";
    public const string UserAddPanel = "添加用户弹窗";
}

UIManager.cs

using System.Collections.Generic;
using UnityEngine;

// 用户界面管理器
public class UIManager
{
    
    
    // 单例模式的实例
    private static UIManager _instance;
    // 用户界面的根节点
    private Transform _uiRoot;
    // 预制件缓存字典
    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>();
    }

    // 打开面板
    public BasePanel OpenPanel(string name)
    {
    
    
        BasePanel panel = null;
        // 检查是否已打开
        if (panelDict.TryGetValue(name, out panel))
        {
    
    
            Debug.Log("界面已打开: " + name);
            return null;
        }

        // 检查路径是否配置
        string path = name;

        // 使用缓存预制件
        GameObject panelPrefab = null;
        if (!prefabDict.TryGetValue(name, out panelPrefab))
        {
    
    
            string realPath = "Prefabs/Panel/" + path;
            Debug.Log(realPath);
            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;
    }
}


BasePanel.cs

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);  // 从字典中移除该面板
        }
    }
}

调用

以我视频中所示的这些界面为例,每一个界面我都会给他们挂接上一个脚本,这些脚本继承自BasePanel,比如在主菜单界面,当我点击修改用户时,则会弹出用户列表的这个界面,这时候我只需要调用UIManager.Instance.OpenPanel,然后打开这个界面即可

public void OnBtnChangeUser()
{
    
    
	print("OnBtnChangeUser");
	UIManager.Instance.OpenPanel(UIConst.UserPanel);
}

关闭界面,也是类似的道理,只要调用close panel即可

public void OnBtnCancel(){
    
    
	print("OnBtnRename");
	ClosePanel();
}

源码

https://gitcode.net/unity1/unity-ui-frame
在这里插入图片描述

参考

【视频】https://www.bilibili.com/video/BV1zT411b7L3/

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_36303853/article/details/132570934