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

news2024/10/6 6:49:13

文章目录

  • 前言
  • 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 slot
				bRemoveDisplayedWidgetPostTransition = 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 active
		ClearActiveHoldInputs();

		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 changed
							MyIcon->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.coloradmin.cn/o/977379.html

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

相关文章

JVM--Hotspot Architecture 详解

一、Java Virtual Machine &#xff08;JVM&#xff09;概述 Java Virtual Machine 虚拟机 &#xff08;JVM&#xff09; 是一种抽象的计算机。JVM本身也是一个程序&#xff0c;但是对于编写在其中执行的程序来说&#xff0c;它看起来像一台机器。对于特定的操作系统&#xff…

docker介绍和安装

docker安装 下载Docker依赖组件 yum -y install yum-utils device-mapper-persistent-data lvm2 设置下载Docker的镜像源为阿里云 yum-config-manager --add-repo http://mirrors.aliyun.com/dockerce/linux/centos/docker-ce.repo 安装Docker服务 yum -y install docker-ce 安…

Python 3.x 异常处理

文章目录 异常处理1. 什么是异常2. Python 中的异常python 中异常演示错误类型捕获try-except 语句带有多个 expect 的 try 语句捕获未知错误 异常参数else 子句finally子句练习 3&#xff1a;简化除法判断 3. 自定义异常抛出异常—raise应用场景抛出异常练习 4&#xff1a;自定…

innovus:route within pin 和限制pin shape内via 数量

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 setNanoRouteMode -routeWithViaInPin "1:1" setNanoRouteMode -routeWithViaOnlyForStandardCellPin "1:1"

git 后悔药

前言 自上而下&#xff0c;撤销可以分为从远程库撤销&#xff0c;从本地库撤销&#xff0c;从暂存库撤销。 例子&#xff1a;代码已经提交了三个记录到远程库&#xff0c;分别对应了记录1&#xff0c;内容1&#xff0c;记录2&#xff0c;内容2&#xff0c;记录3&#xff0c;内…

LeetCode73.矩阵置零

这道题我感觉还是挺简单的&#xff0c;一下子就想到了&#xff0c;不过我的算法很简单很垃圾&#xff0c;效率很低&#xff0c;我一看完题的想法就是直接遍历一遍数组&#xff0c;然后把为0的元素的行和列都存起来&#xff0c;然后把这些行和列都置零就好了&#xff0c;但是这里…

IP地址、子网掩码、网络地址、广播地址、IP网段

文章目录 IP地址IP地址分类子网掩码网络地址广播地址IP网段 本文主要讨论iPv4地址。 IP地址 实际的 IP 地址是一串32 比特的数字&#xff0c;按照 8 比特&#xff08;1 字节&#xff09;为一组分成 4 组&#xff0c;分别用十进制表示然后再用圆点隔开&#xff0c;这就是我们平…

chkdsk H:/F

chkdsk H:/F TF卡损坏

nios里面打开eclipse遇到Unresolved inclusion: “system.h“等问题

问题&#xff1a;在Nios中打开软核部分代码时&#xff0c;遇到一堆Unresolved inclusion: "system.h"等问题报错 原因&#xff1a;bsp文件和软核没关联&#xff0c;导致找不到头文件地址&#xff0c;关联一下就好 解决步骤&#xff1a; 右键bsp文件&#xff0c;点击…

虚幻引擎集成web前端<一>:win环境UE4.27导出像素流并集成到vue2环境(附案例)

本案例附件&#xff1a;https://download.csdn.net/download/rexfow/88303544 第一部分&#xff1a;虚幻引擎导出像素流windows包 第1步&#xff1a;软件设置 -AudioMixer -PixelStreamingIPlocalhost -PixelStreamingPort8888 第2步&#xff1a;信令服务器设置 1、执行run_l…

2023移动软件开发实验6

2023年夏季《移动软件开发》实验报告 姓名和学号&#xff1f;本实验属于哪门课程&#xff1f;中国海洋大学23夏《移动软件开发》实验名称&#xff1f;实验6&#xff1a;推箱子博客地址&#xff1f;XXXXXXXGithub仓库地址&#xff1f;https://github.com/enfantsRichesDeprimes…

十三、MySQL(DQL)语句执行顺序

1、DQL语句执行顺序: &#xff08;1&#xff09;from来决定表 # where来指定查询的条件 &#xff08;2&#xff09;group by指定分组 # having指定分组之后的条件 &#xff08;3&#xff09;select查询要返回哪些字段 &#xff08;4&#xff09;order by根据字段内容&#…

7.0: Dubbo服务调用源码解析

课程内容 服务提供者处理请求流程解析服务消费发送请求流程解析服务提供者端线程模型解析服务消费者端线程模型解析1.服务提供者处理请求流程解析 processon链接:服务调用流程图| ProcessOn免费在线作图,在线流程图,在线思维导图 2. 服务消费端执行逻辑 MockClusterInvoker.in…

【大数据之Kafka】七、Kafka Broker之Kafka副本

1 副本基本信息 Kafka 副本可以提高数据可靠性。分为Leader 和 Follower&#xff1b;Kafka 生产者只会把数据发往 Leader&#xff0c;然后 Follower 找Leader 进行同步数据。   Kafka 默认副本 1 个&#xff0c;生产环境一般配置为 2 个&#xff0c;保证数据可靠性&#xff1…

SAP-PP:基础概念笔记-4(物料主数据视图)

文章目录 前言一、基本视图二、分类视图三、销售视图四、采购五、生产计划和执行视图六、总工厂数据/存储七、质量管理八、会计九、成本系统创建示例&#xff1a;创建一个齿轮物料的主数据事务代码:MM01&#xff0c;另一种方式spro->xxxx 总结 前言 物料主数据为许多组织创…

linux并发服务器 —— 项目实战(九)

阻塞/非阻塞、同步/异步 数据就绪 - 根据系统IO操作的就绪状态 阻塞 - 调用IO方法的线程进入阻塞状态&#xff08;挂起&#xff09; 非阻塞 - 不会改变线程的状态&#xff0c;通过返回值判断 数据读写 - 根据应用程序和内核的交互方式 同步 - 数据的读写需要应用层去读写 …

DX底图还原

直接定位到这个地方 我们可以看到他有一个Bn函数&#xff0c;其中传入的参数有n,e,r,t 分别是这些东西 但是我们只需要还原的列表就得看是哪一段是咯 An((i (i r.split("/"))[i.length - 1]).split(".")[0]) 发现是他之后我们就直接把这个函数扣下来&…

【vue2第十三章】自定义指令 自定义v-loading指令

自定义指令 像 v-html&#xff0c;v-if&#xff0c;v-for都是vue内置指令&#xff0c;而我们也可以封装自定义指令&#xff0c;提升编码效率。 什么是自定义指令&#xff1f; 自己定义的一些指令&#xff0c;可以进行一些dom操作&#xff0c;扩展格外的功能。比如让图片懒加载…

第七章:敏捷开发工具方法-part2-CI/CD工具介绍

文章目录 前言一、CI-持续集成1.1 安装部署gitlab 二、gitlab CI配置三、jenkins实现CI / CD3.1 安装jenkins3.2 配置CI3.3 配置CD3.4 其他构建方式1、定时构建2、指定参数构建3、webhook自动根据git事件进行构建 前言 什么是CI/Cd&#xff1f; CI-Continuous integration&…

web前端——简单的网页布局案列

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 目录 问题背景 解决样例 …