官方项目《内容示例》中Common UI部分笔记:Common UI 分场景使用教程

文章目录

  • 前言
  • 0. 通用设置
    • 0.1 开启插件
    • 0.2 设置Viewport
  • 1. 分场景教程
    • 1. 1 在仅使用鼠标控制的场景下
      • Common Activatable Stack
      • Common Activatable Widget
    • 1.2 当焦点落到一个按钮时显示默认确认(Click/Accept)按键图标
        • Common Input Action DataBase
        • Input Data
        • Common Input Base Controller Data
    • 1.3 即使焦点没有落到该按钮上,也可以使用指定按键触发该按钮,并且按钮上会显示按键提示图标(Input Action和Triggering Input Action)
    • 1.4 当前UI触发按键提示栏(Common Bound Action Bar)
  • 2. 小结

前言

Common UI给虚幻的UI系统带来了很多新特性,这些新特性往往面向不同的使用场景。目前我看到很多的Common UI教程,都是把这些特性很笼统地展示一遍,这就很容易造成初学者的困惑:“我当前做的这些工作,到底是为了实现什么?”所以本文采用分场景介绍的方式,希望能够帮初学者理清一下Common UI的工作逻辑。

0. 通用设置

只要使用Common UI就要做的设置

0.1 开启插件

开启Common UI插件
在这里插入图片描述

0.2 设置Viewport

Viewport是程序运行时Widget的容器及管理器,Common UI从原来的Widget继承树上又派生了新的分支,新分支自然需要扩展后的新Viewport(CommonGameViewportClient)去管理。
在这里插入图片描述

1. 分场景教程

1. 1 在仅使用鼠标控制的场景下

如果你游戏完全用鼠标控制,那么除了上述通用设置以外,Common UI中最值得关注的部分就是新增的Common Activatable Widget 以及Common Activatable Stack

Common Activatable Widget
Common Activatable Widget
Common Activatable Stack
Common Activatable Stack

Common Activatable Stack

Common Activatable Stack 顾名思义就是一个栈。UI中的Widget经常会有上下堆叠的状态,处于顶层的Widget处于可用状态(Activate)(当用键盘或游戏手柄控制的时候,它会获得控制焦点),而非顶层的Widget会处于不可用状态,被置灰或者隐藏。这时候我们往往要自己动手实现一个Stack,来管理这些Widget的行为。Common Activatable Stack 就是Common UI为我们内置的这样一个Stack。

在这里插入图片描述
Common Activatable Stack Common Activatable Widget进行Push Widget操作时,会将原来栈顶的Common Activatable Widget进行DeactivateWidget。当然也可以手动ActivateWidgetDeactivateWidget

void UCommonActivatableWidgetContainerBase::SetSwitcherIndex(int32 TargetIndex, bool bInstantTransition /*= false*/)
{if (MySwitcher && MySwitcher->GetActiveWidgetIndex() != TargetIndex){if (DisplayedWidget){DisplayedWidget->OnDeactivated().RemoveAll(this);if (DisplayedWidget->IsActivated()){DisplayedWidget->DeactivateWidget();}else if (MySwitcher->GetActiveWidgetIndex() != 0){// The displayed widget has already been deactivated by something other than us, so it should be removed from the container// We still need it to remain briefly though until we transition to the new index - then we can remove this entry's slotbRemoveDisplayedWidgetPostTransition = true;}}MySwitcher->TransitionToIndex(TargetIndex, bInstantTransition);}
}

Common Activatable Widget

只有Common Activatable Widget才可以被Common Activatable Stack 管理,在Common Activatable WidgetActivation中设置ActivateWidgetDeactivateWidgetCommon Activatable Widget的行为:

在这里插入图片描述

void UCommonActivatableWidget::NativeOnActivated()
{if (ensureMsgf(bIsActive, TEXT("[%s] has called NativeOnActivated, but isn't actually activated! Never call this directly - call ActivateWidget()"))){if (bSetVisibilityOnActivated){SetVisibility(ActivatedVisibility);UE_LOG(LogCommonUI, Verbose, TEXT("[%s] set visibility to [%s] on activation"), *GetName(), *StaticEnum<ESlateVisibility>()->GetDisplayValueAsText(ActivatedVisibility).ToString());}if (CommonUI::IsEnhancedInputSupportEnabled() && InputMapping){if (const ULocalPlayer* LocalPlayer = GetOwningLocalPlayer()){if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>()){InputSystem->AddMappingContext(InputMapping, InputMappingPriority);}}}BP_OnActivated();OnActivated().Broadcast();BP_OnWidgetActivated.Broadcast();}
}void UCommonActivatableWidget::NativeOnDeactivated()
{if (ensure(!bIsActive)){if (bSetVisibilityOnDeactivated){SetVisibility(DeactivatedVisibility);UE_LOG(LogCommonUI, Verbose, TEXT("[%s] set visibility to [%d] on deactivation"), *GetName(), *StaticEnum<ESlateVisibility>()->GetDisplayValueAsText(DeactivatedVisibility).ToString());}if (CommonUI::IsEnhancedInputSupportEnabled() && InputMapping){if (const ULocalPlayer* LocalPlayer = GetOwningLocalPlayer()){if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>()){InputSystem->RemoveMappingContext(InputMapping);}}}// Cancel any holds that were activeClearActiveHoldInputs();BP_OnDeactivated();OnDeactivated().Broadcast();BP_OnWidgetDeactivated.Broadcast();}
}

关于如何定义一个Common Activatable Widget,在《官方项目《内容示例》中Common UI部分笔记: 1.1 Activatable Widgets》一文中有较详细的叙述。

1.2 当焦点落到一个按钮时显示默认确认(Click/Accept)按键图标

上面是仅用鼠标的场景,接下来聊的都是主要用键盘或游戏手柄的场景。

当一个按钮获取到控制焦点时,按钮上显示默认的确认按键会提升玩家的使用体验。

在这里插入图片描述

实现这样的效果,需要实现一个派生自UCommonButtonBase的按钮,在UCommonButtonBase有一个UCommonActionWidget类型的InputActionWidget,从它的meta中可以看到,它是一个BindWidget,也就是说,允许我们在蓝图中定义一个同名(即名为"InputActionWidget")的UCommonActionWidget

	UPROPERTY(BlueprintReadOnly, Category = Input, meta = (BindWidget, OptionalWidget = true, AllowPrivateAccess = true))TObjectPtr<UCommonActionWidget> InputActionWidget;

在这里插入图片描述

UCommonActionWidgetUpdateActionWidget方法中会从游戏的预设**(Common Input Seetings)**中读取到默认Click按键的图标显示出来,这个UpdateActionWidget在很多情况下都会被调用,包括按钮的Hover状态。

void UCommonActionWidget::UpdateActionWidget()
{if (!IsDesignTime() && GetWorld()){const UCommonInputSubsystem* CommonInputSubsystem = GetInputSubsystem();if (GetGameInstance() && ensure(CommonInputSubsystem) && CommonInputSubsystem->ShouldShowInputKeys()){const FCommonInputActionDataBase* InputActionData = GetInputActionData();if (InputActionData || (EnhancedInputAction && CommonUI::IsEnhancedInputSupportEnabled())){if (bAlwaysHideOverride){SetVisibility(ESlateVisibility::Collapsed);}else{Icon = GetIcon();if (Icon.DrawAs == ESlateBrushDrawType::NoDrawType){SetVisibility(ESlateVisibility::Collapsed);}else if (MyIcon.IsValid()){MyIcon->SetImage(&Icon);if (GetVisibility() != ESlateVisibility::Collapsed){// The object being passed into SetImage is the same each time so layout is never invalidated// Manually invalidate it here as the dimensions may have changedMyIcon->Invalidate(EInvalidateWidgetReason::Layout);}if (IsHeldAction()){MyProgressImage->SetVisibility(EVisibility::SelfHitTestInvisible);}else{MyProgressImage->SetVisibility(EVisibility::Collapsed);}MyKeyBox->Invalidate(EInvalidateWidget::LayoutAndVolatility);SetVisibility(ESlateVisibility::SelfHitTestInvisible);return;}}}}SetVisibility(ESlateVisibility::Collapsed);}
}

接下来我们再看看刚才提到的 (Common Input Seetings)

在这里插入图片描述

Common Input Action DataBase

首先我们要创建一个格式为Common Input Action DataBase的数据表备用,这个数据表的作用其实就如同我们在Input或Enhanced Input中配置的按键和Action的映射表

在这里插入图片描述

Input Data

再回到Common Input Seetings中,新建一个Common UIInput Data类的对象,在其中选择刚才创建的数据表并配置如下两个选项:

在这里插入图片描述

  • Default Click Action : 默认的按钮确认事件
  • Default Back Action : 默认的返回(撤回)事件

Common Activatable Widget可以选择是否接受Back Action事件,如果勾选Is Back Handler默认情况下,接收到Back Action事件,该Common Activatable Widget会被Deactivate。

在这里插入图片描述

Common Input Base Controller Data

Common Input Seetings中的Controller Data下面可以就是配置针对各个平台控制器按键图标的地方

在这里插入图片描述

1.3 即使焦点没有落到该按钮上,也可以使用指定按键触发该按钮,并且按钮上会显示按键提示图标(Input Action和Triggering Input Action)

如果UI上的按钮较多或着有些常用按钮距离较远,我们常常希望即使控制焦点没有在那个按钮上,也能够用键盘或游戏手柄的某个特定按键触发这个按钮,这就是Common UI中的Input Action,类似快捷键。

在这里插入图片描述
实现Input Action的也要基于上面1.2中的若干设置,接下来实现Input Action有两种方式:

  1. 使用名为"InputActionWidget"的UCommonActionWidget,也就是上文中可以接受并显示默认Click事件图标的那个UCommonActionWidget,这时只需要在Triggering Input Action中配置触发它的事件即可,配置方法和上文中配置默认事件的方法一样。注意:Input Action无论是否获得控制焦点均会显示。这说明它就不再显示默认Click图标了。

在这里插入图片描述
2. 自定义一个UCommonActionWidget

在这里插入图片描述

这时我们需要在构造函数(Construct)或预构造函数(Pre Construct)中将它设置给Triggering Input Action

在这里插入图片描述

1.4 当前UI触发按键提示栏(Common Bound Action Bar)

当一个UI有很多按钮都有Input Action触发键的时候,我们想在一目了然的地方(比如屏幕左下角)做一个显示全部或部分触发键图标的提示栏。
在这里插入图片描述

这个功能的实现需要用到Common UI为我们提供的Common Bound Action Bar

在这里插入图片描述

Common Bound Action Bar中的按键图标以及按键功能提示依赖于Action Button Class中提供的Common Bound Action Button类,这个类派生自刚才我们使用过的UCommonButtonBase

在这里插入图片描述

它们的工作逻辑也是一样的,只不过里面又多了一个UCommonTextBlock类型的Text_ActionName,和InputActionWidget一样,Text_ActionName也是和蓝图绑定的用于显示按键说明文字。

protected:UPROPERTY(BlueprintReadOnly, meta = (BindWidget), Category = "Text Block")TObjectPtr<UCommonTextBlock> Text_ActionName;

在这里插入图片描述

如果一个按钮的触发按键想显示在Action Bar中,只需要配置其Triggering Input Action并勾选下面的选项即可。
在这里插入图片描述

2. 小结

码了这么多字,好累!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/73803.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Mysql】数据库第二讲(数据库中数据类型的介绍)

数据类型 1.数据类型分类2.数值类型介绍2.1tinyint类型2.2bit类型介绍2.3小数类型介绍2.3.1 float2.3.2decimal 3.字符串类型介绍3.1char3.2varchar面试&#xff1a;char和varchar的区别 4.日期和时间类型5.enum和set 1.数据类型分类 2.数值类型介绍 2.1tinyint类型 数值越界测…

项目(智慧教室)第三部分,人机交互在stm32上的实现

一。使用软件 1.stm32cubemx中针对汉字提供的软件 2.对数据进行处理 2.上面点击ok--》这里选择确定 3.这里选择保存即可由字符库&#xff0c;但是需要占用内存太大&#xff0c;需35M&#xff0c;但是stm32只有几百k&#xff0c;所以需要自己删减。 生成中文字符&#xff08;用…

QTday3(QT实现文件对话框保存操作、实现键盘触发事件【WASD控制小球的移动】)

1.实现文件对话框保存操作 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }void Widget::on_fontBtn_clicked() {//调用QFo…

dll文件反编译源代码 C#反编译 dotpeek反编译dll文件后export

目录 背景下载安装dotpeek导入dll文件export导出文件参考 背景 项目合作的时候&#xff0c;使用前人的或者其他部门dll文件直接在机台运行&#xff0c;会出现很多问题&#xff0c;逻辑&#xff0c;效率等等&#xff0c;此时我们可以选择对他们的代码进行反编译和重构&#xff…

redisson分布式锁

RLock官网解释 基于Redis的Java分布式可重入锁对象&#xff0c;实现了锁接口。 如果获得锁的Redisson实例崩溃&#xff0c;那么这种锁可能永远挂起在获得状态。为了避免这种情况&#xff0c;Redisson维护了锁看门狗&#xff0c;它在锁持有者Redisson实例活着的时候延长锁过期时…

算法笔记:哈夫曼树、哈夫曼编码

1 字符的机内表示 2 前缀编码 字符只放在叶结点中字符编码可以有不同的长度由于字符只放在叶结点中&#xff0c;所以每个字符的编码都不可能是其他字符编码的前缀前缀编码可被惟一解码 3 哈夫曼树 哈夫曼树是一棵最小代价的二叉树&#xff0c;在这棵树上&#xff0c;所有的字…

SpotBugs(是FindBugs的继任者)安装、使用

SpotBugs介绍 SpotBugs和FindBugs的关系 SpotBugs是FindBugs的继任者&#xff0c;从SpotBugs停止的地方继续。 备注&#xff1a;FindBugs项目已经停止了&#xff0c;从2015年发布3.0.1版本以后再没有新的版本。 SpotBugs通过静态分析寻找java代码中的bug&#xff0c;通过发现…

lv3 嵌入式开发-9 linux TFTP服务器搭建及使用

目录 1 TFTP服务器的介绍 2 TFTP文件传输的特点 3 TFTP服务器的适用场景 4 配置介绍 4.1 配置步骤 4.2 使用 5 常见错误 1 TFTP服务器的介绍 TFTP&#xff08;Trivial File Transfer Protocol&#xff09;即简单文件传输协议 是TCP/IP协议族中的一个用来在客户机与服务器…

手机也可以搭建个人博客?安卓Termux+Hexo搭建属于你自己的博客网站【cpolar实现公网访问】

文章目录 前言 1.安装 Hexo2.安装cpolar3.远程访问4.固定公网地址 前言 Hexo 是一个用 Nodejs 编写的快速、简洁且高效的博客框架。Hexo 使用 Markdown 解析文章&#xff0c;在几秒内&#xff0c;即可利用靓丽的主题生成静态网页。 下面介绍在Termux中安装个人hexo博客并结合…

mysql 安全加固

PS&#xff1a;之前在做安全测试的时候&#xff0c;报告mysql有安全漏洞&#xff0c;于是研究了下如何修复&#xff0c;于是记录下来分享给大家 1.1修改mysql 存放位置 修复 1.停服务 service mysqld stop2.迁位置 2.1 新建迁移目录 mkdir /home/database2.2 迁移数据文件…

【MySQL】MySQL8.0安装教程

下载 MySQL官网下载安装包 安装 1、双击安装程序开始安装 2、选择安装类型 选Server only&#xff08;只安装mysql&#xff09;&#xff0c;然后点击“next”。 3、检测需要的安装&#xff0c; 直接点击Execute开始安装 4、点击next 5、点击next 6、next 7、密码验证方式&a…

macos13 arm芯片(m2) 搭建hbase docker容器 并用flink通过自定义richSinkFunction写入数据到hbase

搭建hbase docker容器 下载镜像 https://hub.docker.com/r/satoshiyamamoto/hbase/tags 点击run 使用镜像新建容器 填写容器名和 容器与宿主机的端口映射 测试 通过宿主机访问容器内的hbase webUI http://localhost:60010/master-status

I2C与I3C的对比

I2C与I3C的对比 电气特性 I2C 1.半双工 2.串行数据线(SDA)和串行时钟线(SCL) 3.数据线漏极开路&#xff0c;即I2C接口接上拉电阻 4.I2C总线运行速度&#xff1a;**标准模式100kbit/s&#xff0c;快速模式400kbit/s&#xff0c;快速模式plus 1Mbit/s&#xff0c;**高速模式…

深入探讨梯度下降:优化机器学习的关键步骤(三)

文章目录 &#x1f340;引言&#x1f340;随机、批量梯度下降的差异&#x1f340;随机梯度下降的实现&#x1f340;随机梯度下降的调试 &#x1f340;引言 随机梯度下降是一种优化方法&#xff0c;主要作用是提高迭代速度&#xff0c;避免陷入庞大计算量的泥沼。在每次更新时&a…

[uniapp]踩坑日记 unexpected character > 1或‘=’>1 报错

在红色报错文档里下滑&#xff0c;找到Show more 根据提示看是缺少标签&#xff0c;如果不是缺少标签&#xff0c;看看view标签内容是否含有<、>、>、<号,把以上符合都进行以<号为例做{{“<”}}处理

Ubuntu编译运行socket.io

本篇文章记录一下自己在ubuntu上编译运行socket.io的过程&#xff0c;客户端选用的是socket.io的c的库&#xff0c;编译起来倒不难&#xff0c;但是说到运行的话&#xff0c;对我来说确实是花了点功夫。毕竟程序要能运行起来才能更方便地去熟悉代码&#xff0c;因此今天我就记录…

MySQL——索引

索引在 MySQL 数据库中分三类&#xff1a; B 树索引Hash 索引全文索引 目的&#xff1a;在查询的时候提升效率 b树 参考&#xff1a;https://blog.csdn.net/qq_40649503/article/details/115799935 数据库索引&#xff0c;是数据库管理系统中一个排序的数据结构&#xf…

在VScode中使用sftp传输本地文件到服务器端

安装SFTP 在VScode的扩展中安装sftp 注意这里需要在你没连接服务器的状态下安装&#xff0c;即本机需要有sftp 配置传输端口 安装成功后&#xff0c;使用快捷键"ctrlshiftp",输入sftp&#xff0c;选择Config 根据自己的实际情况修改配置文件&#xff0c;主要改h…

Golang-GJSON 快速而简单的方法来从 json 文档获取值

GJSON 是一个 Go 包&#xff0c;它提供了一种快速而简单的方法来从 json 文档获取值。它具有单行搜索、点符号路径、迭代和解析 json 行等功能。 GJSON 也可用于Python和Rust 入门 安装中 要开始使用GJSON 请安装 Go 并运行 go get &#xff1a; $ go get -u github.com/ti…

大型企业是否有必要进行数字化转型?

数字化转型对大型企业来说是至关重要的。随着科技的不断发展和市场竞争的加剧&#xff0c;企业面临着更高的客户期望、更复杂的供应链管理、更快的市场变化等挑战。以下是为什么大型企业有必要进行数字化转型的几个主要理由&#xff1a; 提升效率和生产力&#xff1a; 数字化…