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

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分别拖到里面去.如图所示
PauseMenu
这次我们不用脚本实现事件添加而是手动去添加,选中Button对象,在鼠标单击的栏目下添加Canvas对象,再在右边的事件下选择Canvas对象中的对应的方法,像Resume按钮就选择ResumeEvent方法,Quit按钮选择QuitEvent方法,如图所示
ButtonClick

将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向此事件添加委托以在卸载场景时收到通知。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值