懒人UI框架与操作方式识别

前言

        有这些奇怪需求是我在GGJ2024得出来的,就上周那场。我们队伍企图做一个吸血鬼like的游戏,并非常荣幸的收获了许多BUG和需求,于是不得不花时间整理,可能之后的好几次文章可能都要围绕那个游戏做题。我在设计游戏架构之初就打算让它同时支持键鼠和手柄游玩。但到最好赶工干着干着只能忽略了,这毕竟也是GJ。所以现在回头梳理重构一下之前的框架并记录成果。

懒人UI框架

        事先声明,这个框架是非常简易的,没有任何技术含量,存粹分享个人愚笨的记录,有需要请自行拓展。

主要部分:

1.UI基类

脚本示范:

using UnityEngine;

public class UIBase : MonoBehaviour
{
    public virtual void Open() 
    { 
        gameObject.SetActive(true); 
    }

    public virtual void Close()
    {
        gameObject.SetActive(false);
    }
}

         不难看出,所谓的UI基类其实就是我们自定义UI的模板类,也就是我们自定义的UI脚本们均继承自它,然后再把它们挂载在各个UI上。在上述代码中,UIBase仅仅包含了每个UI的开启和关闭行为,我们可以根据更具体的需求进行拓展。

        一开始我其实写成一个abstract类,但猛然发现好像每个UI在开启和关闭时都需要设置Active,索性就把它们写成虚方法以便直接继承。

2.UI管理类

脚本示范:

using System;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 控制所有UI面板
/// </summary>
public class UIManager : MonoBehaviour
{
    //有更好的单例模板可以替换
    public static UIManager Instance;

    [Serializable]
    internal class Panel
    {
        [Header("面板预制体")]
        [Tooltip("UI面板的预制体,最好是一个独立的Canvas")]
        public GameObject prefab;
        [Header("开始时打开")]
        [Tooltip("比如菜单Menu那些默认打开就好了")]
        public bool startOpen = false;
    }

    [SerializeField]
    private List<Panel> panels = new List<Panel>();
    private Dictionary<string,GameObject> name2panel = new Dictionary<string,GameObject>();
    private void Awake()
    {
        Instance = this;
        DontDestroyOnLoad(this);        

        foreach (var panel in panels)
        {
            GameObject panelIns = Instantiate(panel.prefab,transform);
            panelIns.name = panel.prefab.name;
            name2panel.Add(panelIns.name, panelIns);

            if (panel.startOpen) 
            {  
                panelIns.GetComponent<UIBase>().Open();
            }
            else
            {
                panelIns.GetComponent<UIBase>().Close();
            }
            
        }
    }

    public static void Open(string PanelName)
    {
        Instance.name2panel[PanelName].GetComponent<UIBase>().Open();
    }
    public static void Close(string PanelName)
    {
        Instance.name2panel[PanelName].GetComponent<UIBase>().Close();
    }
}

         管理类的大致思路就是以内部的Panel类为单位管理所有UI,当然此Panel非彼Panel,这里说的Panel指玩家自定义UI面板,比方说一个叫Menu的UI面板。需要做的,就是将做好的UI预制体拖入Panel的prefab中:

        当前UI Manager已经挂载在同名空物体上。

具体的代码很容易理解,这里的单例模式可以替换掉,如果已经具有单例模板。

3.UI们

脚本示范:

using UnityEngine;
using UnityEngine.EventSystems;

public class Menu : UIBase
{
    [Header("打开时选择")]
    public GameObject OpenSelected;        
       
    public void OpenPlayerPanel()
    {
        UIManager.Open("角色面板");
        Close();
    }
    public override void Close()
    {
        base.Close();
    }

    public override void Open()
    {
        base.Open();
        EventSystem.current.SetSelectedGameObject(OpenSelected);
    }
}

        可以看到,Menu作为一个自定义UI脚本,继承自UIBase,在此基础上,我们根据自己想要的具体效果实现不同的操作。不如说Menu这里的Open(),重写之后每次打开我都让当前选择的物体唯一,这样可以避免当前选择对象为空这种情况发生,在之后的操作方式识别我会细说。

        与此同时,Menu脚本应该挂载在某个UI预制体上。不过不要挂在它的子物体上,因为管理类中是通过直接获取身上的组件在找到UIbase从而实现统一管控的。这里的Menu就挂在“菜单”预制体上。

框架思路:

        好的,这是十分简单的一个框架,可能以后需要更加复杂庞大的系统的,但是这种懒人式于我而言目前已经很足够了。

        我一开始确实是想非常统一的管理所有UI,但后面发现非常不现实。比方说我想只用到管理类脚本就实现全部UI和各种功能的管理,这是非常困难的。因为每个UI要做的事都不同,所谓的统一管理我就简化为了统一控制显示。

        就像上图的OpenPlayerPanel()方法,我在预制体界面将它与某个按钮绑定之后,是在脚本中描述它的功能的:“打开角色面板”然后“关闭自己”。这里的“打开角色面板”就是通过管理类来完成。

但是每个UI自己的功能只能在自己的脚本中完成,这也是没办法的事情,如果有专门构建游戏UI的UI引擎就好了,不用像这样写一顿脚本分别挂载。事实上我写这个框架之前就是这样的,为每个UI都写一个脚本,菜单一个,状态栏一个,物品栏和商店一个。但是它们之间的相互关联确总是很麻烦,索性就让它们有所共性(UIbase)然后方便管理罢了,后续应该还会添油加醋让整个UI系统更加合理高效。

        最后梳理一下大概的使用流程:1.搭好一个UI(相当于一个Canvas);2.把它变成预制体;3.把预制体拖入某个挂载有UIManager的物体上(一般是同名空物体);4.调整参数。

        对于第4点,所谓的什么参数目前就只有要不要在一开始时打开罢了。但是我们可以自行添加修改。

操作方式识别

背景

        所谓的什么操作方式,其实就是键鼠和手柄之类的,今天也只针对键鼠和手柄两种操作方式进行识别。而且要注意,这次脚本是建立在Unity new input system上的,老的输入系统有别的方式。但是因为新输入系统太好用了,我就果断放弃老输入系统。

        再者就是新输入系统呢虽然比较麻烦但是更全面更高效,所以没学习过的建议先去学习一下,我也没有很深入研究。

        也是刚好就着这个UI系统刚好能有机会演示,所以就把它们俩个放在一起记录了。

准备

        非常简单,如果你已经熟悉新输入系统的基本操作后。那么就先新建一个Input Actions,我这里新建了一个叫test的Input Actions。这里其实可以直接复制Unity默认的那个,新建一个新输入系统下的EvenSystem,它会自带有Input System UI Input Module组件,它有个属性就是默认Input Actions,可以直接复制一份出来,改个名字接着用。因为有很多UI导航相关的map已经做好了,做起来就会很方便,UI导航还是非常重要的。

        再一个就是给某个物体加上Player Input 组件。这一步非常关键,因为我们可以从Player Input组件获取Control Scheme(CS),也就是控制方案。这个控制方案是与Input Actions相关的,如果你的Input Actions是从默认的复制过来的,那么它会自带一些调好的CS:

在左上角 ,点开就可以看到几个默认的CS,我们就是通过识别CS来间接识别操作方式的。

为了方便演示,我把Player Input挂载到了EventSystem上。

脚本:

using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;

public class Menu : UIBase
{
    [Header("打开时选择")]
    public GameObject OpenSelected;
    [Header("当前控制方案提示")]
    public TextMeshProUGUI tip;    
        
    private void FixedUpdate()
    {
        if (EventSystem.current.currentSelectedGameObject == null) EventSystem.current.SetSelectedGameObject(OpenSelected);

        if(EventSystem.current.GetComponent<PlayerInput>().currentControlScheme == "Gamepad")
        {
            tip.text = "use left stick to select...";
        }
        if (EventSystem.current.GetComponent<PlayerInput>().currentControlScheme == "Keyboard&Mouse")
        {
            tip.text = "use WASD to select...";
        }
    }
    
    public void OpenPlayerPanel()
    {
        UIManager.Open("角色面板");
        Close();
    }
    public override void Close()
    {
        base.Close();
    }

    public override void Open()
    {
        base.Open();
        EventSystem.current.SetSelectedGameObject(OpenSelected);
    }
}

        OK啊非常容易理解,就是我们在FixedUpdate中直接判断现在的CS,然后根据它切换提示。

具体CS的名字都可以改,原理就是这么个原理。然后这段代码直接加在了Menu上。

演示

        可以看到一开始我们是用键盘操作的,所以提示就变成键盘提示,后来我转到手柄操作它就自动变成手柄提示了。

意义

        相信操作方式很容易理解,但是具体的原理,特别是CS和Input Actions这一块还是要花点时间。

        至于这个东西有什么用?嘿嘿,用处就是我刚刚演示的那样:识别玩家操作方式,从而改变操作提示。经常玩游戏的都知道这是非常常见的游戏支持。我一开始做我们GGJ那个项目的时候就是想这样做一个提示,因为当时需要做一个商店页面,然后提供卖出物品这个功能,所以需要做一个按键的提示,如果玩家用的键鼠就提示玩家“鼠标右键出售”,如果是手柄就提示玩家“按B出售”;

        当时因为时间和经验的不足,没能完成这个需求,其实GJ本来也用不到,只是自己想挑战一下。

        当然还有另外一种比较节省的改提示的方式:就是把操作方式直接改在游戏设置里面,这样玩家可以更自己修改自己想要的提示。当然这两者一起作用最好。我记得法环好像就是这样的。

        当然还有其他功能需要大家的想象力了,比如根据玩家使用的操作方式改变游戏机制。这也很常见。当然基本原理也大同小异。

常见问题

        1.Player Input和Input System UI Input Module具有连带关系,可能会导致一些问题(放心,一般不会),具体可以去手册看看。但是又不得不用上Player Input组件,因为这能快速查询CS,其实虽然叫做Player,但是你想挂载在哪都行。

        2.这里虽然未提到,但是我还是想提一嘴手柄游戏操作UI的按钮导航最好设为Explicit,因为Unity的导航判断不了遮挡关系,也就是子UI上的按钮可以导航到父UI,或者反过来,这也是我在做UI时发现的小问题,可能会找个时间特地研究下优化手柄游戏的UI,这里就先提一嘴。

  • 17
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。
### 回答1: macOS 10.12懒人版是苹果公司推出的操作系统的一个版本。这个版本的主要特点是为用户提供更加直观和便捷的操作体验。 首先,macOS 10.12懒人版改进了系统的界面设计和操作方式。用户可以通过更简洁明了的界面来轻松找到他们想要的应用程序,而不需要进行复杂的操作。新版系统还引入了一些直观的手势控制,比如滑动屏幕、捏放缩小等,使用户可以通过简单的手势来控制和操作系统。 此外,macOS 10.12懒人版还提供了更多个性化的设置选项,让用户可以根据自己的喜好和习惯来定制系统。用户可以自由选择系统的主题颜色、壁纸等,打造属于自己的个性化系统界面。 除此之外,macOS 10.12懒人版还加强了系统的性能和稳定性。通过优化系统的内核和资源管理,提高了系统的运行速度和响应能力。同时,系统还增加了一些智能的功能,比如自动备份、智能识别设备等,使用户能够更加便捷地管理和使用电脑。 总的来说,macOS 10.12懒人版是一款用户友好、操作便捷的操作系统。它通过简化界面、优化性能和增加个性化设置,为用户提供了更好的使用体验。无论是专业人士还是普通用户,都能够从中受益,并享受到更加高效、愉快的电脑使用过程。 ### 回答2: macOS 10.12也被称为"懒人版"是因为它在使用上更加方便快捷。首先,macOS 10.12引入了一项名为"懒人用户界面"的新功能,它为用户提供了更直观、更简洁的界面设计,使用户能够更快速地完成各种操作。 其次,macOS 10.12还加入了一系列智能化的功能,可以根据用户的习惯和喜好来自动调整一些设置。例如,它可以根据用户的使用时间和频率自动调整屏幕亮度和音量,以满足用户在不同环境下的需求。此外,还有一种名为"智能文件管理"的功能,它可以根据文件的类型和使用频率将文件自动整理和分类,使用户能够更轻松地查找和管理文件。 另外,macOS 10.12还引入了一种名为"一键任务"的功能,它可以让用户通过简单的点击完成一系列常用操作。例如,用户只需点击一下鼠标,就能够同时打开所有喜欢的应用程序和网页,省去了一个个打开的步骤,提高了工作效率。 最后,macOS 10.12还加入了更多与iOS系统的互通功能,使得Mac和iOS设备之间更加紧密地结合。用户可以通过iCloud同步功能将文件、照片和联系人等数据在不同设备之间自动同步,方便快捷。而且,用户还可以通过Handoff功能在Mac和iOS设备之间无缝切换任务,使得工作更加流畅和连贯。 总之,macOS 10.12的"懒人版"具有更直观、更智能的用户界面设计,提供了一系列方便快捷的操作功能,帮助用户更高效地完成各种任务。 ### 回答3: macOS 10.12(懒人版)是苹果公司推出的一款操作系统。该系统的懒人版主要是为了提供更加便捷的使用体验和操作方式。 首先,在桌面界面上,懒人版加入了更多的快捷方式和工具,使得用户可以更方便地访问常用的应用程序和文件。例如,用户可以通过一键打开常用的浏览器、邮件、社交媒体、音乐播放器等应用程序。 其次,懒人版有更智能的搜索功能。用户只需在桌面上点击搜索栏,输入关键词即可快速找到相关文件、应用程序或互联网资源。同时,懒人版还可以智能推荐最常用的搜索结果,提高了用户的工作效率。 此外,懒人版还加入了更多的操作快捷键,并对系统设置进行了优化,使得用户可以更快速地进行常用操作,减少了重复的步骤和鼠标点击。 再者,懒人版对于多任务处理也进行了改进。用户可以通过简单的手势操作或快捷键,在不同的应用程序之间切换,并且可以同时进行多任务处理,提高了工作效率。 最后值得一提的是,懒人版还加入了智能电源管理功能,可以根据用户的使用习惯和需求来调整电脑的电源模式,延长电池的使用寿命。 总的来说,macOS 10.12(懒人版)通过添加更多的快捷方式、优化操作和搜索功能,提高了用户的使用便捷性和效率。无论是对于新手用户还是老手用户,都能够有更好的体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Moweiii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值