草庐IT

Unity之UI和登陆界面与暂停界面

StrangeStranger 2023-04-10 原文

Unity————UI和登陆界面与暂停界面

接触了Unity制作不管是程序还是游戏都避免不了UI的制作,但是在网上搜的UI制作的学习过程,额…一言难尽,就像是拼图一样在那一块块搜索然后再将它拼装起来,痛苦万分.因此撰此文以记录我的UI的学习过程.首先要理解的就是UI设计的含义,UI包括登陆界面,暂停界面等等但不只有这些东西.UI称之为(User Interface),是指对软件的人机交互,操作逻辑,界面美观的整体设计.UI设计的目的是操作变得更舒适简单自由.一般来说在游戏中接触最多的UI就是登陆界面,暂停界面,设置界面,教程界面之类的,或者说游戏右上角假如有一个暂停按键(开挂按键)那么它也可以称之为UI.

参考网址:https://docs.unity.cn/cn/current/Manual/UIToolkits.html

一般来说在开始搜索“UI的制作过程”都是在要制作登陆界面或者暂停界面遇到了瓶颈,所以本文将着重于如何快速的利用unity的内置工具制作出一个能用能看的简易UI,用到的是unity教程里的unity UI而不是unity工具包,若在自行查阅文档过程中可以着重看这一部分.

如果目标是为了制作一个登陆界面,那么我们现在最需要的就是一个界面,一个按钮,然后按下这个按钮从界面进入到游戏中(假设游戏为场景SceneGame并且已经制作完成),那么登陆界面的操作就是创建一个新的场景SceneLogin然后里面有个按钮Button,按下Button后场景切换(利用UnityEngine.SceneManagement)切换到SceneGame,这就是一个简单的登陆界面.暂停界面则是设备检测到一个按键被按下(比如Esc),然后让整个游戏暂停,再调出一个界面,上面有两个按钮“恢复游戏”与“退出游戏”,前者让一切恢复正常,后者则是直接退出游戏.这篇文章的目的就是建立这两个界面.

Canvas画布

只要在百度这个离谱的搜索引擎上搜索过unity的UI制作就不会对这个词感到陌生
参考:https://blog.csdn.net/qq_45548042/article/details/121011915.
一切UI的控制部件都是在canvas进行布置的.令人疑惑不解的是为什么所有的UI组件都需要在canvas上进行布置呢?官方的说法如下:

画布 (Canvas) 是应该容纳所有 UI 元素的区域。画布是一种带有画布组件的游戏对象,所有 UI 元素都必须是此类画布的子项。
创建新的 UI 元素(如使用菜单 GameObject > UI > Image 创建图像)时,如果场景中还没有画布,则会自动创建画布。UI 元素将创建为此画布的子项。
画布区域在 Scene 视图中显示为矩形。这样可以轻松定位 UI 元素,而无需始终显示 Game 视图。
画布 使用 EventSystem 对象来协助消息系统。

以我浅薄的理解,canvs设计的必要性有以下几条:

  • 方便渲染
  • 定位UI元素而不需要显示Game视图
  • 协助消息系统
  • 对不同分辨率的屏幕尽可能显示出一致的界面(锚点功能)

Canvas总共有三种模式,第一种模式(Screen Space-Overlay)是camera镜头里只有canvas,就相当于我们所做的界面操作,unity只会渲染canvas而不会渲染其他的物品,大部分登陆界面用的是第一种模式.第二种模式(Screen Space-Camera)canvas会一直放在camera的前面,显示在镜头前面的一定距离的地方,它不会影响正常场景的渲染,视觉感觉来说就是你面前一直存在一个具有一定大小的界面.第三种模式(World Space),Canvas就被当成了正常的物品对象,跟一个正方体没有什么区别,也不会随着摄像头的移动而移动,个人理解为在制作3D人物上的血条,或者是很炫酷的那种控制界面用这种Canvas比较多.

登陆界面

哦,要不我们开始试试创建一个登陆界面?

首先在“项目”界面右键创建一个新场景(命名为SceneLogin),然后再在左侧的“层级”界面右键-UI-按钮,因为所有的UI组件都会在Canvas里面,所以Unity会自动帮你创建一个Canvas.应该能注意到按钮挂在Canvas下面,而按钮下面还挂着一个Text,这是控制你按钮上的字体显示的.有可能你的按钮上没有显示字体,这是因为你还没有把字体文件库导入进去,字体文件在Text里的Font Asset里进行设置,点开来会发现里面是空.这时候点击菜单栏(就最上面那一排)的窗口——TextMeshPro——导入TMP基本资源,就可以将字体文件导入进去了,此时字体就配置好了.这就是我们的登陆界面,虽然它什么功能都没有,但至少是像一个登陆界面了.里面的细节可以根据手册自己摸索,这不是我们的主线任务,我们就不再进行赘述了

创建按钮参考:https://www.csdn.net/tags/MtjaUgysNDU3MzMtYmxvZwO0O0OO0O0O.html

按钮控制

现在我们给按钮加上一个脚本附件,我想这个操作对于依葫芦画瓢做过一次项目的人(如果没有建议去做一下)已经是轻车熟路了

using System.Collections;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityEngine;

public class LoadScene: MonoBehaviour
{
    Button LoginButton;
    public void OnClickLogin()
    {
        SceneManager.LoadScene(1);
    }
    private void Awake()
    {
        LoginButton = GetComponent<Button>();
        LoginButton.onClick.AddListener(OnClickLogin);
    }
}

这里面用到了UnityEngine.UIUnityEngine.SceneManagement,分别用作给按钮加上监听函数,以及对场景进行切换,注意要对(Building Setting 生成设置)进行操作

切换场景参考:https://blog.csdn.net/weixin_44831924/article/details/100055216
这篇文章里面的一些操作已经过时了,但是里面对生成设置的操作有必要阅读

现在我们一个最最最最基础的登陆界面就制作完成了,但是我们不能只知其然不知其所以然,所以接下来我们会对代码进行深一步的挖掘

SceneManager

SceneManager是对场景进行管理的类,具体的成员和方法详细见附录,用的最多的就是LoadScene,利用场景编号或者场景名称对场景进行切换,这里要注意下其与LoadSceneAsync的区分,可参考这篇文章:https://blog.csdn.net/qq_42462109/article/details/83096135?spm=1001.2014.3001.5502.在loadscene的过程中还可以指定加载哪种类型的场景,可以加载单模式和附加模式,单模式就是普通的切换场景,附加模式使得屏幕中中包含两个场景,比如说做背包血条栏可以利用这种模式.注意与MergeScene的区别,合并场景会破坏原场景,这是一种破坏性行为.

另外,在用附加模式的加载场景的过程中,要注意活动场景的设置,对应方法是SetActiveScene,因为一些操作都是需要对应活动场景的,比如新建一个Object,烘焙等等操作,都是对应活动的场景,参考https://www.jianshu.com/p/f897ac4376f9

using UnityEngine;
using UnityEngine.SceneManagement;

public class ExampleClass : MonoBehaviour
{
    void Start()
    {
        // Only specifying the sceneName or sceneBuildIndex will load the Scene with the Single mode
        SceneManager.LoadScene("OtherSceneName", LoadSceneMode.Additive);
    }
}

Button

这里的Button成员指UnityEngine.UI.Button,参考文档:https://docs.unity.cn/cn/2019.2/ScriptReference/UI.Button.html

Button的继承树如下:UI.Button->UI.Selectable->EventSystem.UIBehaviour->MonoBehaviour

MonoBehaviour大家都很熟了,老朋友了,所有的Unity脚本都派生于此类.UIBehaviour手册上写的是具有Unity生命周期函数的受保护实现的基准行为,将里面类似Start之类的方法添加protected关键字,相当于Unity已经实现这些方法并且不希望有人去动它.UI.Selectable为简单的可选择对象(Selectable Object),通过它创造可选择的对象,比如Button.(详细见附录)

对于Button来说,最重要的就是里面的成员onClick,这是一个当按钮被按下后所触发的Unity的事件,它的类型是UI.Button.ButtonClickedEvent,继承于UnityEvent,详情可以看附录里记录的UnityEvent的用法,最常用就是增加监听函数的方法AddListener.

哦如果想用一点复杂的按钮的用法的话,可以尝试了解下OnPointerClick回调函数,它是鼠标按下后的回调函数Unity会传过来一个EventSystems.PointerEventData类型的数据称作eventData,通过重载这个回调函数可以实现更加复杂的代码,参考代码如下:

//Attatch this script to a Button GameObject
using UnityEngine;
using UnityEngine.EventSystems;

public class Example : MonoBehaviour, IPointerClickHandler
{
    //Detect if a click occurs
    public void OnPointerClick(PointerEventData pointerEventData)
    {
        //Use this to tell when the user right-clicks on the Button
        if (pointerEventData.button == PointerEventData.InputButton.Right)
        {
            //Output to console the clicked GameObject's name and the following message. You can replace this with your own actions for when clicking the GameObject.
            Debug.Log(name + " Game Object Right Clicked!");
        }

        //Use this to tell when the user left-clicks on the Button
        if (pointerEventData.button == PointerEventData.InputButton.Left)
        {
            Debug.Log(name + " Game Object Left Clicked!");
        }
    }
}

关于PointerEventData的文档:https://docs.unity.cn/cn/2019.2/ScriptReference/EventSystems.PointerEventData.html

暂停界面

接下来便是制作暂停界面,暂停界面的要求是按下Esc后,游戏停止,并跳出界面,上面应该至少含有两个按钮,一个按钮为Resume用于恢复游戏,另一个按钮为Quit用于退出游戏.参考文章https://blog.csdn.net/dangoxiba/article/details/122922065

首先我们创建一个Canvas,并且在Canvas下创建两个按钮,分别命名和调整里面的字体内容为Resume和Quit.接着编写以下脚本,并且将其添加为Canvas的组件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PauseMenu : MonoBehaviour
{
    public GameObject QuitButton;
    public GameObject ResumeButton;
    bool isPause=false;
    // Start is called before the first frame update
    void Start()
    {
        QuitButton.SetActive(false);
        ResumeButton.SetActive(false);
    }
    public void QuitEvent()
    {
        Application.Quit(0);
    }
    public void ResumeEvent()
    {
        isPause = false;
        QuitButton.SetActive(false);
        ResumeButton.SetActive(false);
        Time.timeScale = 1.0f;
    }
    // Update is called once per frame
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Escape)&& !isPause)
        {
            isPause = true;
            QuitButton.SetActive(true);
            ResumeButton.SetActive(true);
            Time.timeScale = 0.0f;
        }
    }
}

添加到Canvas组件后可以看到组件PauseMenu上有两个属性,将QuitButton和ResumeButton分别拖到里面去.如图所示

这次我们不用脚本实现事件添加而是手动去添加,选中Button对象,在鼠标单击的栏目下添加Canvas对象,再在右边的事件下选择Canvas对象中的对应的方法,像Resume按钮就选择ResumeEvent方法,Quit按钮选择QuitEvent方法,如图所示

将Canvas的图层设置为1,一直将其放置在顶层,至此一个最最最基础的暂停界面就完成了,按下Esc即可暂停.

代码详解

此功能的代码并没有太多的新知识点,InputGameObject都是Unity基础知识里了解过的东西,GameObject.SetActive设置对象是否活动,设置为True即活动并且可见,设置为False即不活动且不可见,Input.GetKeyDown检测键盘上是否有按键是否按下,Application.Quit退出播放器程序,对于UnityEngine.Application更多的用法详见用户手册https://docs.unity.cn/cn/2021.3/ScriptReference/Application.html

time里的timescale设置对像物理运动的快慢,可以通过增加或减小timescale来实现感觉上的加速和减速.设置Time.timescale=0.0f即可达到停止效果,反之设置Time.timescale=1.0f恢复正常.关于Time的更多用法详见用户手册https://docs.unity.cn/cn/2021.3/ScriptReference/Time-timeScale.html

附录

UnityEventBase

UnityEvent 的抽象基类。
此类为 UnityEvent 提供了基本功能。

备注:不要看中文解释,去看他英文名字以理解其含义,中文解释跟坨?一样

公共函数:

名称解释
GetPersistentEventCount获取已注册的持久性监听器的数量。
GetPersistentMethodName获取索引处的监听器的目标方法名称。
GetPersistentTarget获取索引处的监听器的目标组件。
RemoveAllListeners从事件中删除所有非持久性(即通过脚本创建的)监听器。
SetPersistentListenerState修改持久性监听器的执行状态。

静态函数:

名称解释
GetValidMethodInfo提供了对象、函数名称和参数类型列表;找到匹配的方法。

UnityEvent:UnityEventBase

可以与场景一起保存的0参数持久回调

构造函数
UnityEvent:构造函数。

公共函数:

名称解释
AddListener向UnityEvent添加非持久性监听器。
Invoke调用所有已注册的回调(运行时和持久性)。
RemoveListener从UnityEvent中删除非持久性监听器。

UnityEvent< T0>: UnityEventBase

同:

  • UnityEvent< T0,T1>
  • UnityEvent< T0,T1,T2>
  • UnityEvent< T0,T1,T2,T3>

这相当于UnityEvent的多参数版本,要注意的是如果需要用这种多参数的版本需要对参数进行覆盖,以下将利用两参数版本进行范例:

using UnityEngine;
using UnityEngine.Events;

[System.Serializable]
public class MyIntEvent : UnityEvent<int, int>
{
}
public class ExampleClass : MonoBehaviour
{
    public MyIntEvent m_MyEvent;
    void Start()
    {
        if (m_MyEvent == null)
            m_MyEvent = new MyIntEvent();

        m_MyEvent.AddListener(Ping);
    }
    void Update()
    {
        if (Input.anyKeyDown &amp;&amp; m_MyEvent != null)
        {
            m_MyEvent.Invoke(5, 6);
        }
    }
    void Ping(int i, int j)
    {
        Debug.Log("Ping" + i + ", " + j);
    }
}

UI.Selectable:EventSystems.UIBehaviour

简单的可选择对象 - 可从中派生,以创建可选择控件。

静态变量:

名称解释
allSelectablesList of all the selectable objects currently active in the Scene.

变量:

名称解释
animationTriggers用于此可选择对象的 AnimationTriggers。
animator便捷函数,用于获取 GameObject 中的 Animator 组件。
colors用于此可选择对象的 ColorBlock。
image便捷函数,可将引用的 Graphic 转换为 Image(如果可能)。
interactable用于启用或禁用对可选择 UI 元素(例如,按钮)进行选择的功能。
navigation此可选择对象的 Navigation 设置。
spriteState用于此可选择对象的 SpriteState。
targetGraphic将过渡的 Graphic。
transition过渡的类型,当状态更改时将应用于 targetGraphic。

公共函数:

名称解释
FindSelectable查找此对象旁边的可选择对象。
FindSelectableOnDown查找此对象下方的可选择对象。
FindSelectableOnLeft查找此对象左侧的可选择对象。
FindSelectableOnRight查找此对象右侧的可选择对象。
FindSelectableOnUp查找此对象上方的可选择对象。
IsInteractableUI.Selectable.IsInteractable。
OnDeselect撤消选择并过渡到适当状态。
OnMove确定应在 4 个移动方向中的哪个方向找到下一个可选择对象。
OnPointerDown评估当前状态并过渡至按下状态。
OnPointerEnter评估当前状态并过渡至适当状态。
OnPointerExit评估当前状态并过渡至正常状态。
OnPointerUp评估 eventData 并过渡至适当状态。
OnSelect设置选择并过渡到适当状态。
Select选择此 Selectable 对象。

SceneManagement.SceneManager

运行时的场景管理。

静态变量:

名称解释
sceneCount当前加载的场景总数。
sceneCountInBuildSettingsBuild Settings 中的场景数量。

静态函数:

名称解释
CreateScene在运行时使用给定名称创建一个新的空场景。
GetActiveScene获取当前活动的场景。
GetSceneAt获取 SceneManager 的已加载场景列表中索引处的场景。
GetSceneByBuildIndex从构建索引中获取场景结构。
GetSceneByName搜索已加载的场景,查找包含给定名称的场景。
GetSceneByPath搜索所有已加载的场景,查找具有给定资源路径的场景。
LoadScene按照 Build Settings 中的名称或索引加载场景。
LoadSceneAsync在后台异步加载场景。
MergeScenes这会将源场景合并到 destinationScene 中。
MoveGameObjectToScene将游戏对象从当前场景移至新场景。
SetActiveScene将场景设置为活动状态。
UnloadSceneAsync销毁所有与给定场景关联的游戏对象,并将场景从 SceneManager 中移除。

事件:

名称解释
activeSceneChanged订阅此事件可在活动场景发生变化时收到通知。
sceneLoaded向此事件添加委托,以在加载场景时收到通知。
sceneUnloaded向此事件添加委托以在卸载场景时收到通知。

有关Unity之UI和登陆界面与暂停界面的更多相关文章

  1. ruby - i18n Assets 管理/翻译 UI - 2

    我正在使用i18n从头开始​​构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在ruby​​onrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi

  2. ruby-on-rails - 如何在 Ruby on Rails 中实现由 JSF 2.0 (Primefaces) 驱动的 UI 魔法 - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道ruby​​onrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim

  3. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

  4. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  5. unity---接入Admob - 2

    目录1.AdmobSDK下载地址2.将下载好的unityPackagesdk导入到unity里​编辑 3.解析依赖到项目中

  6. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

  7. ruby-on-rails - Rails 3 - 过滤器链暂停为 :authentication rendered or redirected - 2

    我仍然收到标题中的“错误”消息,但不知道如何解决。在ApplicationController中,classApplicationController在routes.rb#match'set_activity_account/:id/:value'=>'users#account_activity',:as=>:set_activity_account--thisdoesn'tworkaswell..resources:usersdomemberdoget:action_a,:action_bendcollectiondoget'account_activity'endend和User

  8. Unity Shader 学习笔记(5)Shader变体、Shader属性定义技巧、自定义材质面板 - 2

    写在之前Shader变体、Shader属性定义技巧、自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用,方便后续回顾查看,如有以偏概全、不祥不尽之处,还望海涵。1、Shader变体先看一段代码......Properties{ [KeywordEnum(on,off)]USL_USE_COL("IsUseColorMixTex?",int)=0 [Toggle(IS_RED_ON)]_IsRed("IsRed?",int)=0}......//中间省略,后续会有完整代码 #pragmamulti_c

  9. 三分钟集成 TapTap 防沉迷 SDK(Unity 版) - 2

    三分钟集成Tap防沉迷SDK(Unity版)一、SDK介绍基于国家对上线所有游戏必须增加防沉迷功能的政策下,TapTap推出防沉迷SDK,供游戏开发者进行接入;允许未成年用户在周五、六、日以及法定节假日晚上8:00-9:00进行游戏,防沉谜时间段进入游戏会弹窗进行提示!开发环境要求:Unity2019.4或更高版本iOS10或更高版本Android5.0(APIlevel21)或更高版本🔗Unity集成Demo参考链接🔗UnityTapSDK功能体验APK下载链接二、集成前准备1.创建应用进入开发者后台,按照提示开始创建应用;2.开通服务在使用TDS实名认证和防沉迷服务之前,需要在上面创建的应

  10. 【Unity大气散射】GAMES104:3A中如何实现大气散射 - 2

    写在前面前两天学习并整理的大气散射基础知识:【Unity大气渲染】关于单次大气散射的理论知识,收获了很多,但不得不承认的是,这其实已经是最早的、90年代的非常古老的方法了,后来也出现了一些优化性的计算思路和方法。因此,我打算先不急着跟各种教程在Unity中实现大气散射,而是再花时间来看看最近的游戏是如何去实现大气渲染的:06.游戏中地形大气和云的渲染(下)|GAMES104-现代游戏引擎:从入门到实践接下来就跟着GAMES104讲地形大气和云渲染的部分学习并做简单的记录,涉及到之前没提到的Mie散射也只选择直接截图PPT的方式记录啦!毕竟对于做作品来说,之后实现出来才是重要的~当然,May佬的

随机推荐