斯坦福UE4 + C++课程学习记录 14:UMG-优化血量条

目录

1. 优化执行效率

2. 简易脉冲动画

3. 完整代码


1. 优化执行效率

        上一节虽然实现了UI的实时更新,但绑定函数会每帧刷新进而造成资源浪费,毕竟血量变化的速度和一帧比起来还是慢太多。类似于CPU控制的IO操作会导致CPU持续忙等(一直检查状态但没有实际作用),一种解决办法就是使用中断控制来解放CPU。类似的,在设计模式中有一种订阅-发布(观察者)模式就很适合这样的场景:UI组件不再自行每帧查询血量,而是让血量自己在发生变化的同时通知UI进行刷新。

        在UE中可使用多播委托自定义事件来实现,它的作用主要是只需调用一次Broadcast函数就可使所有绑定的对象触发相应功能。在上一节转到OnComponentBeginOverlap的定义时,我们已经看到事件在UE中的代码结构,这里我们将使用类似的方法来实现一个自定义事件。SurAttributeComponent.h和.cpp的完整代码如下。我在写这部分代码的时候VS反应很慢,OnHealthChanged甚至找不到Broadcast方法,如果你遇到同样的情况可以复制粘贴直接编译。

#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "SurAttributeComponent.generated.h"

// 发起者,控件拥有者,改变后的血量,变化值
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FOnHealthChanged, AActor*, InstigatorActor, USurAttributeComponent*, OwningComp, float, NewHealth, float, Delta);

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class SURKEAUE_API USurAttributeComponent : public UActorComponent
{
	GENERATED_BODY()

protected:
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Attributes")
	float Health;

public:	
	USurAttributeComponent();

	UPROPERTY(BlueprintAssignable)
	FOnHealthChanged OnHealthChanged;

	UFUNCTION(BlueprintCallable, Category="Attributes")
	bool ApplyHealthChange(float Delta);

};
#include "SurAttributeComponent.h"

USurAttributeComponent::USurAttributeComponent()
{
	Health = 100;
}

bool USurAttributeComponent::ApplyHealthChange(float Delta)
{
	Health += Delta;
	OnHealthChanged.Broadcast(nullptr, this, Health, Delta);

	return true;
}

        回到UE,在Player的AttributeComp中添加刚刚编写的OnHealthChanged事件,利用PrintString节点快速验证效果,我在这里把颜色换成了紫色,以便同之前的打印结果区分。

图14-1 打印血量
图14-2 运行测试

        从测试结果来看,这个事件的效果完全满足显示血量的要求,但效率上毫无疑问地优于之前的实现方法。现在只需要把这个事件分配给相应的UI控件PlayerHealth_Widget即可,刚好其中的血条(进度条)还没有绑定数据。

        我们直接在PlayerHealth_Widget的事件图表中编写蓝图程序,在“事件构造”一开始就将将玩家Pawn的AttributeComp绑定到OnHealthChanged事件上。在每次事件触发时计算当前血量与玩家默认血量的百分比,并设置给进度条。此外,我还顺便设置了文本块显示的内容,并在设计器中取消了上一节实现的绑定函数。如果在蓝图中找不到文本框变量,记得在设计器中把相应控件前的Is Variable打开。蓝图如下所示,完整蓝图代码在文末:

图14-3 更新UI

2. 简易脉冲动画

        这部分通过在UI中添加血量减少时的脉冲动画,来了解UMG中动画的使用。

        在左下角的“动画”中点击“添加动画”,命名为PulseHealthAnim,点击动画,并选择旁边的“时间轴”。选择显示血量数字的文本块,在细节中下滑找到“渲染变换”,将缩放添加为关键帧。

图14-4 添加关键帧

        将时间轴拖拽到0.75,添加关键帧;在0.25处,将缩放的XY设置为0.5再次添加关键帧。此时拖动时间轴(或者按下空格键),就可预览到这个简易的脉冲动画。切换切换到蓝图中,添加播放动画的节点:

图14-5 播放动画

         运行测试,发现动画正常播放了,但初始状态文本的缩放变成了0.5。

图14-6 运行测试

         这是因为在刚才设置关键帧的时候更改了文本缩放的默认值,此时需要回到设计器中,点击黄色返回键将文本的缩放变为默认值:

图14-7 重置缩放

        类似的,在文本块的同一轨道中添加三个颜色的关键帧分别为白-红-白,并记得重置默认值,最终得到了如下的血量效果:

图14-8 血量动画

3. 完整代码

PlayerHealth_Widget蓝图

Begin Object Class=/Script/BlueprintGraph.K2Node_Event Name="K2Node_Event_1"
   EventReference=(MemberParent=Class'"/Script/UMG.UserWidget"',MemberName="Construct")
   bOverrideFunction=True
   NodePosX=608
   NodePosY=192
   bCommentBubblePinned=True
   NodeGuid=5C5C2C384FF042097E221CADF9B06BBD
   CustomProperties Pin (PinId=FFBD93B8414DC401A295798563A0A8C2,PinName="OutputDelegate",Direction="EGPD_Output",PinType.PinCategory="delegate",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(MemberParent=Class'"/Script/UMG.UserWidget"',MemberName="Construct"),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=F7A4FD1A4CA5E769D43CB88C4B6C3851,PinName="then",Direction="EGPD_Output",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_DynamicCast_0 A66FCF6B4C604F9D38F11EA4AA517441,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
End Object
Begin Object Class=/Script/BlueprintGraph.K2Node_CallFunction Name="K2Node_CallFunction_0"
   bIsPureFunc=True
   FunctionReference=(MemberParent=Class'"/Script/Engine.GameplayStatics"',MemberName="GetPlayerPawn")
   NodePosX=560
   NodePosY=272
   NodeGuid=DC8EF067484F0D7D6C6926AC71A41156
   CustomProperties Pin (PinId=413C6C0347AF340E6EA6379535D587B9,PinName="self",PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target"),PinToolTip="目标\nGameplay静态 对象引用",PinType.PinCategory="object",PinType.PinSubCategory="",PinType.PinSubCategoryObject=Class'"/Script/Engine.GameplayStatics"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,DefaultObject="/Script/Engine.Default__GameplayStatics",PersistentGuid=00000000000000000000000000000000,bHidden=True,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=770BEBF04E7B193464D49889283D49A3,PinName="WorldContextObject",PinToolTip="World Context Object\n{类别}",PinType.PinCategory="object",PinType.PinSubCategory="",PinType.PinSubCategoryObject=Class'"/Script/CoreUObject.Object"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=True,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,PersistentGuid=00000000000000000000000000000000,bHidden=True,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=46345CB948D781358B222994D4CEAC23,PinName="PlayerIndex",PinToolTip="Player Index\n整数",PinType.PinCategory="int",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,DefaultValue="0",AutogeneratedDefaultValue="0",PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=2DC527BA4C556E33D522FB9D8BC900A4,PinName="ReturnValue",PinToolTip="Return Value\nPawn 对象引用\n\n返回指定玩家索引处的玩家pawn",Direction="EGPD_Output",PinType.PinCategory="object",PinType.PinSubCategory="",PinType.PinSubCategoryObject=Class'"/Script/Engine.Pawn"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_DynamicCast_0 34973D504ADDA4109277CF8DEFDD55CF,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
End Object
Begin Object Class=/Script/BlueprintGraph.K2Node_DynamicCast Name="K2Node_DynamicCast_0"
   TargetType=Class'"/Script/SurkeaUE.SurCharacter"'
   NodePosX=848
   NodePosY=192
   NodeGuid=35014CBC4EA6220FD4E9F3B5492EC26A
   CustomProperties Pin (PinId=A66FCF6B4C604F9D38F11EA4AA517441,PinName="execute",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_Event_1 F7A4FD1A4CA5E769D43CB88C4B6C3851,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=8DCD68144E55A779A556AEA4BA0D005D,PinName="then",Direction="EGPD_Output",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_AssignDelegate_0 F27DED894F115C8724352180EB1738F4,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=B5F1A5824461D7D3271F918AFE65A58E,PinName="CastFailed",Direction="EGPD_Output",PinType.PinCategory="exec",PinType.PinSubCategory="",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
   CustomProperties Pin (PinId=34973D504ADDA4109277CF8DEFDD55CF,PinName="Object",PinType.PinCategory="object",PinType.PinSubCategory="",PinType.PinSubCategoryObject=Class'"/Script/CoreUObject.Object"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Surkea

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

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

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

打赏作者

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

抵扣说明:

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

余额充值