Unreal Engine 4 —— GAS系统学习 (八) UMG外传

在前一节中我们实现了血条功能,但是部分功能是在蓝图中实现的,因为在AttributeSetBase类中定义了动态多播代理,而这次是想直接使用代码来全部完成,不在蓝图中使用。

新建了一个UI,作为血条。在C++中不能直接CAST蓝图类,这就很让人抓狂。

于是,用C++新建了一个HealthWidget类,继承自UserWidget。

它的头文件里是这样的:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Components/ProgressBar.h"
#include "Components/CanvasPanel.h"
#include "HealthWidget.generated.h"

/**
 * 
 */
UCLASS()
class SHIBI_API UHealthWidget : public UUserWidget
{
	GENERATED_BODY()

public:

	UPROPERTY(EditAnywhere,BlueprintReadWrite,meta = (BindWidget))
	class UProgressBar* healthBar;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (BindWidget))
	class UCanvasPanel* rootPanel;

	bool Initialize() override;
};

healthBar和rootPanel要记住这俩名字,因为刚才 BP123蓝图类中的组件必须改为这俩名字,否则找不到组件,编译不通过。

而且要重写bool Initialize方法。

它的CPP文件是这样的:

// Fill out your copyright notice in the Description page of Project Settings.


#include "HealthWidget.h"

bool UHealthWidget::Initialize()
{
	Super::Initialize();
	rootPanel = Cast<UCanvasPanel>(GetRootWidget());
	if (rootPanel) {
	healthBar = Cast<UProgressBar>(GetWidgetFromName("healthBar"));
	healthBar->SetPercent(1.0f);
	}
	return true;
}

这一操作就是将C++的HealthWidget中的变量与 BP123中的组件相关联,这一步很重要。

接下来编译,编译通过后,打开BP123

看到图左下角的两个组件名字了吗,要改成与HealthWidget类变量一样的名字。

为这个BP123的蓝图选择一个父类,就是我们定义的C++的HealthWidget类。

因为我们要改变的目标没变,还是血条数据,所以进入到属性AttributeSetBase类中,进行修改。

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AttributeSetBase.generated.h"

/**
 * 
 */


//DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FHealthDelegate, float, Health, float, MaxHealth);
DECLARE_MULTICAST_DELEGATE_TwoParams(FHealthDelegate,float,float);


UCLASS()
class SHIBI_API UAttributeSetBase : public UAttributeSet
{
public:
	GENERATED_BODY()
	UAttributeSetBase();
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Properties From AttributeSetBase")
	FGameplayAttributeData Health;
	FGameplayAttributeData MaxHealth;

	FHealthDelegate onHealthChangeDelegate;

	void PostGameplayEffectExecute(const struct FGameplayEffectModCallbackData& Data) override;


};

这里使用的不再是动态多播代理了,而是多播代理。意味着我们不需要在蓝图中实现血条数据变化的功能了。

它的CPP内容没变,依旧和原来一样:

// Fill out your copyright notice in the Description page of Project Settings.


#include "AttributeSetBase.h"
#include "GameplayEffectExtension.h"
#include "GameplayEffect.h"

UAttributeSetBase::UAttributeSetBase():Health(200.0f), MaxHealth(200.0f){
	
}

void UAttributeSetBase::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
	if (Data.EvaluatedData.Attribute.GetUProperty() == FindFieldChecked<UProperty>(UAttributeSetBase::StaticClass(),GET_MEMBER_NAME_CHECKED(UAttributeSetBase,Health))) {
		onHealthChangeDelegate.Broadcast(Health.GetBaseValue(),MaxHealth.GetCurrentValue());
	}
}

现在就差最后一步,让主角(和敌人)拥有血条UI,并改变血量数据从而影响UI的显示。

在主角的头文件中引入:#include "Components/WidgetComponent.h"和#include "HealthWidget.h"(这是我们刚才定义的C++的UserWidget的子类)

让主角能够拥有widget的Component。

并增加以下代码。onDamage就是处理血条数据的。Health与MaxHealth数据是由AttributeSetBase类中的postGameplayEffectExecute方法通过多播代理传递过来的。

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Shinbi | UI")
	class UWidgetComponent* widget;

	UFUNCTION(BlueprintCallable)
	void onDamage(float Health, float MaxHealth);

在主角构造器中加入以下代码:

	widget = CreateDefaultSubobject<UWidgetComponent>(TEXT("widget"));
	widget->SetupAttachment(shibiSkeletal);
	widget->SetRelativeLocation(FVector(0,0,200));
	auto asset = LoadClass<UHealthWidget>(NULL, TEXT("WidgetBlueprint'/Game/BP123.BP123_C'"));

	widget->SetWidgetClass(asset);
	widget->SetWidgetSpace(EWidgetSpace::Screen);
	

	//attributeComponent->onHealthChangeDelegate.AddDynamic(this, &AShinbi::OnHealthChanged);
	attributeComponent->onHealthChangeDelegate.AddUObject(this, &AShinbi::onDamage);

1.先创建UWidgetComponent的对象。

2.调整widget对象与人物的相对位置。

3.通过LoadClass来读取BP123蓝图类。

4.将蓝图类BP123设置为widget组件的WidgetClass属性的参数,这样人物就可以拥有显示出来的UI血条了。

5.设置widget组件为screen,保证在任何角度都能够清楚看见血条。

6.实施多播代理的绑定。

 

绑定的方法如下:

void AShinbi::onDamage(float Health, float MaxHealth) {
	float temp = Health / MaxHealth;
	UUserWidget* tobeCast = widget->GetUserWidgetObject();
	UHealthWidget* bp123 = Cast<UHealthWidget>(tobeCast);
	bp123->healthBar->SetPercent(temp);

}

这一过程与蓝图操作一致。这里能成功将widget组件中的UserWidget类的UI转成UHealthWidget类,且成功访问到healthBar,是因为多态机制决定的。我们利用这一机制完成了类型转换。同事UHealthWidget的参数是绑定了BP123中的组件的,此时访问UHealthWidget中的参数就是在访问BP123中的组件。

成功运行,效果如下:

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值