斯坦福UE4 + C++课学习记录 13:UMG-血量条

文章目录

  • 一、创建血量属性
  • 二、应用血量更改
  • 三、血量UI

一、创建血量属性

  1. Unreal Motion Graphics (UMG)是 UE中用于创建用户界面 (UI) 的工具。它可以实现如下复杂功能:
    (1)动画:UMG 支持为控件添加动画。可以在 Widget Blueprint中创建动画,并在蓝图脚本中控制动画的播放。
    (2)绑定数据:可以将控件的属性绑定到变量或函数,实现动态更新 UI。比如本节中,将进度条的值绑定到角色的健康值。
    (3)事件处理:UMG 提供了丰富的事件处理功能。可以为按钮点击、鼠标悬停等事件添加处理函数,实现交互逻辑。
    (4)自定义控件:可以创建自定义的Widge类,封装复杂的 UI 逻辑,并在其他地方复用。
  2. UMGHUD,在UE4中的HUD主要是指
    (1)UE3那里继承来的Head-Up Display功能,在UE4中主要是用来Debug
    (2)向画布上添加图形图元的功能,表示文字的功能,还有简单的HitBox处理,用来检测鼠标等
    但是由于这些功能UMG都可以干,所以UE4的HUD功能也不是需要一定要掌握了
  3. UMG是对Slate进行了扩展方便在游戏中使用的框架,Slate是不依靠某个平台的UI框架,UE4的Editor和游戏中的UI都是使用Slate构建的。
    (1)继承了UObject使得Blueprint也可以方便使用
    (2)方便在UE4的Editor上确认渲染结果
    (3)简单的制作UI动画
  4. Widget 层次结构
  • UMG 的WidgetBlueprintSlate控件的结合。每个UMG Widget都有一个对应的Slate Widget。UMG 通过将高层次的蓝图控件映射到Slate控件来实现 UI。
  • UUserWidget:UMG 中所有Widget的基类。
  • SUserWidget:与UUserWidget对应的Slate控件。
  1. 事件驱动系统
  • UMG 和 Slate 使用事件驱动系统来处理用户输入事件。常见的事件包括:
    ①点击事件:如按钮的点击事件。
    ②悬停事件:鼠标悬停在控件上时触发的事件。
    ③键盘事件:处理键盘输入的事件。
  • 事件的处理依赖于DelegateBinding系统。UMG 中的事件通常是通过BlueprintC++中的Delegate绑定来处理的。
  1. 数据绑定属性系统
  • UMG 支持将控件的属性绑定到数据源。数据绑定使得 UI 能够自动更新,以反映数据的变化。常见的数据绑定机制包括:
    Property Binding:通过 UMG 的绑定功能,将控件属性绑定到类的属性或函数。
    Delegate Binding:通过 Delegate 绑定,处理属性变化时的自定义逻辑。
  1. UMG的三种控件:
  • UWidget : 所有 UMG 控件的公共基类,不提供增加子节点功能
  • UPanelWidget : 提供了增加子节点功能,可以有多个子节点
  • UContentWidget : 继承于UPanelWidget,是 UPanelWidget的一种特例,只能有一个子节点

(1)不能有子节点的控件:这个类别的控件的公共基类都是UWidget,每个 UMG 控件,都持有一个 Slate控件的智能指针
(2)可以增加子节点的控件

  • 有一个子节点的控件继承的父类依次是 UComponentWidget->UPanelWidget,父类 UComponentWidget构造函数中设置了不允许多个孩子标记位:(源码如下)
UContentWidget::UContentWidget(const FObjectInitializer& ObjectInitializer): Super(ObjectInitializer)
{bCanHaveMultipleChildren = false;
}
  • 公共基类UPanelWidget定义了AddChild函数,可以增加对应的子节点:(源码如下)
UPanelSlot* UPanelWidget::AddChild(UWidget* Content)
{if ( Content == nullptr ){return nullptr;  //表示无法添加空控件}//检查是否可以有多个子控件if ( !bCanHaveMultipleChildren && GetChildrenCount() > 0 ){return nullptr;}//将 Content 从其当前父控件中移除。这一步确保控件没有其他父控件,并准备将其添加到新的 UPanelWidget 中。Content->RemoveFromParent();//初始化新对象的标志。//默认情况下,使用RF_Transactional,这意味着该对象的更改是可撤销的。//如果UPanelWidget有RF_Transient标志,则新对象也设置这个标志,表示它在运行时创建,并且不会保存到磁盘。EObjectFlags NewObjectFlags = RF_Transactional;if (HasAnyFlags(RF_Transient)){NewObjectFlags |= RF_Transient;}//创建新的 PanelSlot 对象UPanelSlot* PanelSlot = NewObject<UPanelSlot>(this, GetSlotClass(), NAME_None, NewObjectFlags);  //GetSlotClass()是UPanelSlot的类类型NAME_None表示没有指定名称,新对象的标志是之前设置的NewObjectFlags。//关联控件和PanelSlotPanelSlot->Content = Content;PanelSlot->Parent = this;//设置控件的 Slot//将Content的Slot属性设置为新创建的PanelSlot。这一步建立了控件与其布局信息之间的双向链接。Content->Slot = PanelSlot;//将PanelSlot添加到Slots数组//Slots数组维护所有子控件的布局信息Slots.Add(PanelSlot);//触发Slot添加事件。OnSlotAdded方法是一个虚函数,可以在子类中重写,以处理Slot添加后的特定逻辑。OnSlotAdded(PanelSlot);//使布局和易变性失效//这将强制重建控件树和重新计算布局InvalidateLayoutAndVolatility();return PanelSlot;
}
  1. UMG中的Slot
    (1)Slot是一种用于管理控件布局和对齐的机制,UMG 中的每个Widget都有一个Slot,用于确定其在父控件中的布局规则。
    (2)主要 Slot 类型及其属性:

UCanvasPanelSlot

  • 用于UCanvasPanel,提供绝对位置和大小。
    属性包括Position, Size, Anchors, Offsets等。

UHorizontalBoxSlot

  • 用于UHorizontalBox,提供水平布局
    属性包括Padding, Size, HorizontalAlignment, VerticalAlignment等。

UVerticalBoxSlot

  • 用于UVerticalBox,提供垂直布局
    属性包括Padding, Size, HorizontalAlignment, VerticalAlignment等。
    (3)SPanelSCompoundWidget可以作为父节点,控件之间的父子关系是依赖Slot实现的。父控件引用SlotSlot引用子控件并且保留子控件相对于父控件的布局信息。
  1. Slate控件类:
    *Slate中除了SWidget之外有三个基础类,其他控件都是继承者三个基类。
    SPanel: 有多个子节点
    SLeafWidget: 没有子节点
    SCompoundWidget: 可以有一个子节点

  2. UCanvasPanel控件树:
    在这里插入图片描述

  • UCanvasPanel是 UMG 中的高层次控件,底层的实现是SConstraintCanvas,它处理实际的布局和渲染逻辑,UCanvasPanel将子控件添加到 SConstraintCanvas中,并通过UCanvasPanelSlot设置布局属性。
  • UCanvasPanelSlotUCanvasPanel中每个子控件的Slot类。它存储子控件的布局信息,比如位置、大小、锚点等。每个添加到UCanvasPanel的子控件都会有一个对应的UCanvasPanelSlot
  • SConstraintCanvas使用SConstraintCanvas::FSlot来存储子控件的布局信息。SConstraintCanvas::FSlot继承自FSlot,并添加了特定于SConstraintCanvas的布局属性。
  • UCanvasPanel增加一个UCanvasPanelSlot,其SConstraintCanvas引用也相应的添加一个FSlot(SConstraintCanvas::FSlot),且UCanvasPanelSlot保存FSlot的引用。
  • 当修改UCanvasPanelSlot的属性时,通用引用也修改了SConstraintCanvas::FSlot对应的属性。
void UCanvasPanelSlot::SetOffsets(FMargin InOffset)
{LayoutData.Offsets = InOffset;if ( Slot ){Slot->Offset(InOffset);}
}
  1. 为角色添加属性,如果直接在角色类中定义一个Health变量,这种方式的弊端显而易见:随着项目的扩展、游戏不断更新迭代新版本,角色的属性可能达到几十上百,若是加上角色的技能、特性、天赋或其他各种角色相关内容,角色类的内容将膨胀到极难维护。
  • 在UE中解决这个问题的办法很简单,可以使用UE中的ActorComponent类,让整个类以组件的形式被SCharacter拥有。因此,我们从ActorComponent创建角色的SAttributeComponent类,用于实现角色的各种属性。

  • SAttributeComponent.h

#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "SurAttributeComponent.generated.h"UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class SURKEAUE_API USurAttributeComponent : public UActorComponent
{GENERATED_BODY()protected:UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Attributes")float Health;public:USurAttributeComponent();UFUNCTION(BlueprintCallable, Category="Attributes")bool ApplyHealthChange(float Delta);};
  • SAttributeComponent.h
#include "SurAttributeComponent.h"USurAttributeComponent::USurAttributeComponent()
{Health = 100;}bool USurAttributeComponent::ApplyHealthChange(float Delta)
{Health += Delta;// 用于判断操作是否成功完成,如角色死亡、特殊机制等情况可能失败// 目前先返回truereturn true;
}
  1. 然后使用如下方法在SCharacter中声明组件,并在.cpp中创建相应实例:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
USurAttributeComponent* AttributeComp; 

二、应用血量更改

  1. SMagicProjectile中为球体组件绑定一个OnComponentBeginOverlap事件,旨在当魔法粒子与物体重叠时触发。比起使用阻挡来触发,使用重叠可以通过判定重叠对象来更方便的忽略友军伤害,并且让魔法粒子直接穿过友军继续在场景中计算(记得对应的Projectile碰撞设置也要进行更改)。
  2. 一个小技巧:在为创建绑定事件的函数时,我们可以在VS中利用右键“转到定义”去找到该事件默认的输入,找到参数数量最多的一个函数重载,然后复制粘贴除第一个参数(UE函数的签名)外的其他参数,去掉逗号作为绑定函数的参数。
  3. 在函数中实现减少血量的代码
//SurMagicProjectile.hUFUNCTION()
void OnActorOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);//SurMagicProjectile.cppSphereComp->OnComponentBeginOverlap.AddDynamic(this, &ASurMagicProjectile::OnActorOverlap);void ASurMagicProjectile::OnActorOverlap(...)
{if (OtherActor) {//获得AttributeCompUSurAttributeComponent* AttributeComp = Cast<USurAttributeComponent>(OtherActor->GetComponentByClass(USurAttributeComponent::StaticClass()));// 再次判空,可能碰到的是墙壁、箱子等没有血量的物体if (AttributeComp) {// 魔法粒子造成20血量伤害AttributeComp->ApplyHealthChange(-20.0f);// 一旦造成伤害就销毁,避免穿过角色继续计算Destroy();}}
} 
  1. Player中利用蓝图实现在屏幕上打印血量的字符串,以让我们实时了解角色的血量。这个蓝图实现很简单,唯一注意的是设置显示时长为0关闭Print to Log,这样屏幕上只会出现一个数字(事件Tick会在每一帧都调用),且不会在Log中输出大量无用信息:
    在这里插入图片描述
  2. 利用蓝图系统快速实现一个攻击玩家的敌人 (箭头)
    (1) 从Actor派生一个名为ProjectileCanon的蓝图类,为其添加Utility下的箭头组件并设置为根,并设置颜色(UE中用红绿蓝表示XYZ轴,箭头默认的红色与X轴相同容易混乱),去掉“渲染”属性中的“游戏中隐藏”。
    (2)在事件图表中从“开始运行”节点添加循环计时器,并添加名为OnTimerElapsed的自定义事件,设置该事件为朝箭头方向发射魔法粒子;同时,在Tick节点后实现在每一帧将箭头指向玩家,方向向量由两个Actor的坐标相减得到。

三、血量UI

  1. 首先在Content文件夹下创建UI文件夹,用于存放所有UI相关的资产。在UI文件夹中创建“用户界面” -> “控件蓝图”,命名为PlayerHealth_Widget。双击打开UMG的操作界面
  2. 在左侧“控制板”中的“通用”分别添加一个进度条和文本,在“层级”中选择任意组件,右键添加水平框,并将另外一个拖入其中,这样水平框会为我们管理两个元素的水平对齐。
  3. 然后在进度条右侧的“细节”面板中找到“插槽”,选择“尺寸”为填充,拉动水平框的整体长度就可以控制血条的长度。将水平框的“锚点”选择为左上角,设置位置XY值,完成后就做好了简单的血条UI。
  4. Player的蓝图中选择“事件开始运行”,并添加Create Widget节点,选择PlayerHealth_Widget,然后将其添加到视口,这样,在我们运行关卡时UI就会显示在屏幕上。
  5. 此时UI的内容还是固定的,UI需要和数据进行绑定后,才能实时根据数据进行显示。选择文本块,点击 “内容” -> 文本-> 绑定 -> 创建绑定,UE会在蓝图中创建相应函数,我们将其重命名为GetHealthText。添加“获取拥有玩家PawnGet Owning Player Pawn)” -> 按类获取组件Get Component By Class)-> 选择classSAttributeComponet-> GetHealth -> 连接到“返回节点”的return value引脚;然后在“获取拥有玩家Pawn”后添加Is Valid判空。编译保存运行,可以看到数字能够实时显示血量了。

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

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

相关文章

扩散模型系列0 DDPM:Denoising Diffusion Probabilistic Models

前言&#xff1a; 从7月12号开始 学习了一些扩散模型的论文&#xff0c;越看越上瘾&#xff0c;对未知的渴求激励着我不断地读论文整理、学习、分析、理解 以前发的博客仅仅是对论文的翻译&#xff0c;现在觉得仅仅翻译是不够的&#xff0c;读了一篇论文以后&#xff0c;要形成…

智慧出行新纪元:Vatee万腾平台引领未来交通蓝图

在科技日新月异的今天&#xff0c;智慧出行已成为连接城市脉动、重塑生活方式的关键词。Vatee万腾平台&#xff0c;作为智慧交通领域的佼佼者&#xff0c;正以前瞻性的视角和创新的技术&#xff0c;为我们描绘出一幅未来交通的宏伟蓝图&#xff0c;让每一次出行都成为一次前所未…

扩散模型系列ControlNet: Adding Conditional Control to Text-to-Image Diffusion Models

向文本到图像扩散模型添加条件控制 摘要解读&#xff1a; 我对摘要英文的理解&#xff1a; 我们提出了一个神经网络架构ControlNet&#xff0c;可以向大规模的预训练好的文本到图像的扩散模型中添加空间条件控制。ControlNet锁住了准备生产的大规模扩散模型&#xff0c;并且重…

TCP为什么需要四次挥手?

tcp为什么需要四次挥手&#xff1f; 答案有两个&#xff1a; 1.将发送fin包的权限交给被动断开发的应用层去处理&#xff0c;也就是让程序员处理 2.接第一个答案&#xff0c;应用层有了发送fin的权限&#xff0c;可以在发送fin前继续向对端发送消息 为了搞清楚这个问题&…

生鲜云订单零售系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;商品分类管理&#xff0c;商品信息管理&#xff0c;订单评价管理&#xff0c;订单管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;商品信息&#x…

力扣高频SQL 50题(基础版)第二十三题

文章目录 力扣高频SQL 50题&#xff08;基础版&#xff09;第二十三题596.超过5名学生的课题目说明实现过程准备数据实现方式结果截图 力扣高频SQL 50题&#xff08;基础版&#xff09;第二十三题 596.超过5名学生的课 题目说明 表: Courses -------------------- | Colum…

家具缓冲器:提升家居体验的得力助手

在家具和工业设备的设计与制造中&#xff0c;钢珠滑轨缓冲器的安装与否一直是一个备受争议的话题。钢珠滑轨缓冲器作为一种能够减少冲击和噪音的装置&#xff0c;其存在具的价值&#xff0c;但也并非在所有情况下是必需的。首先&#xff0c;从功能和使用体验的角度来看&#xf…

算力共享:如何理解、标识与调控多层次算力资源的异构性和复杂性,实现智能算力网生态诸要素有效互操作?

目录 鹏程云主机和NPU计算服务器关系 NPU计算服务器 两者关系 结论 两种不同类型的处理器或计算单元 FPGA MLU NS3(Network Simulator version 3) 一、基本属性 二、主要功能与特点 三、应用与前景 对象存储和HDD存储 一、定义与特点 二、应用场景 三、总结 对…

html+css+js前端作业和平精英6个页面页面带js

htmlcssjs前端作业和平精英6个页面页面带js 下载地址 https://download.csdn.net/download/qq_42431718/89595600 目录1 目录2 项目视频 htmlcssjs前端作业和平精英6个页面带js 页面1 页面2 页面3 页面4 页面5 页面6

3.2.微调

微调 ​ 对于一些样本数量有限的数据集&#xff0c;如果使用较大的模型&#xff0c;可能很快过拟合&#xff0c;较小的模型可能效果不好。这个问题的一个解决方案是收集更多数据&#xff0c;但其实在很多情况下这是很难做到的。 ​ 另一种方法就是迁移学习(transfer learning…

Go语言编程 学习笔记整理 第2章 顺序编程 前半部分

前言&#xff1a;《Go语言编程》编著 许式伟 吕桂华 等 1.1 变量 var v1 int var v2 string var v3 [10]int // 数组 var v4 []int // 数组切片 var v5 struct { f int } var v6 *int // 指针 var v7 map[string]int // map&#xff0c;key为string类型&#xff0c;value为in…

【QT】qt 文件操作

qt 文件 qt 文件1. Qt 文件概述2. 输入输出设备类3. 文件读写类4. 文件和目录信息类 qt 文件 1. Qt 文件概述 文件操作是应用程序必不可少的部分。Qt 作为⼀个通用开发库&#xff0c;提供了跨平台的文件操作能力。 Qt 提供了很多关于文件的类&#xff0c;通过这些类能够对文件…

微服务--配置管理

现在依然还有几个问题需要解决&#xff1a; 网关路由在配置文件中写死了&#xff0c;如果变更必须重启微服务 某些业务配置在配置文件中写死了&#xff0c;每次修改都要重启服务 每个微服务都有很多重复的配置&#xff0c;维护成本高 这些问题都可以通过统一的配置管理器服…

DP的优化途径---单调队列

1.前缀和单调队列&#xff1a;https://www.acwing.com/problem/content/137/ 我们先预处理下前缀和&#xff0c;以下标为i的点为有边界&#xff1a; 也就是求()的min&#xff0c;考虑到j的范围是定值&#xff0c;用单调队列维护即可。 AC代码&#xff1a; #include<bits/…

OpenGL3.3_C++_Windows(32)

demo SSAO SSAO 环境光照(Ambient Lighting)&#xff1a;光的散射&#xff0c;我们通过一个固定的常量作为环境光的模拟&#xff0c;但是这种固定的环境光并不能很好模拟散射&#xff0c;因为环境光不是一成不变的&#xff0c;环境光遮蔽&#xff1a;让&#xff08;褶皱、孔洞…

更新至2023年上市公司ESG数据合集(十份数据:华证年度、华证季度、商道融绿、wind、秩鼎、润灵环球、盟浪、富时罗素、上市银行华证ESG)

更新至2023年上市公司ESG数据合集&#xff08;十份数据&#xff1a;华证年度、华证季度、商道融绿、wind、秩鼎、润灵环球、盟浪、富时罗素、上市银行华证ESG&#xff09; 数据名称&#xff1a; 一、2018-2023年上市公司富时罗素ESG评分数据 二、2018-2023年上市公司Wind ES…

深度学习实战笔记3循环神经网络实现

我们要训练一个基于循环神经网络的字符级语言模型&#xff0c;根据用户提供的文本的前缀生成后续文本。 import math import torch from torch import nn from torch.nn import functional as F from d2l import torch as d2l batch_size, num_steps 32, 35 train_iter, voc…

C#插件 调用存储过程(输出参数类型)

存储过程 CREATE PROCEDURE [dbo].[GetSum]num1 INT,num2 INT,result INT OUTPUT AS BEGINselect result num1 num2 END C#代码 using Kingdee.BOS; using Kingdee.BOS.App.Data; using Kingdee.BOS.Core.Bill.PlugIn; using Kingdee.BOS.Util; using System; using System.…

MySQL死锁问题案例

MySQL死锁问题 问题描述&#xff1a;在一张流水生成的记录表中&#xff0c;当没有当前条件的数据时候&#xff0c;并发情况下会导致有线程因为死锁问题生成流水号失败。 场景 有一张生成流水的表&#xff1a; 场景复现&#xff1a; 简单来说&#xff0c;在根据流水类型、年、月…

Python如何快速定位最慢的代码?优雅了~

编写Python代码时&#xff0c;我们常常会遇到性能瓶颈&#xff0c;这不仅影响程序的执行效率&#xff0c;还可能导致用户体验下降。那么&#xff0c;如何快速定位代码中最慢的部分&#xff0c;成为每个开发者必须掌握的技能。 如何快速定位 Python 代码中的性能瓶颈&#xff1…