前面几节文章介绍了如何在角色身上添加AbilitySystemComponent和AttributeSet。并且还实现了给AttributeSet添加自定义属性。接下来,实现一下如何去修改角色身上的Attribute的值。
实现拾取药瓶回血功能
首先创建一个继承于Actor的c++类,actor是可以放置到场景中的基类。
bash
UPROPERTY(VisibleAnywhere)
TObjectPtr<UStaticMeshComponent> Mesh;
创建一个静态模型组件,用来显示当前可拾取物的模型。
bash
UPROPERTY(VisibleAnywhere)
TObjectPtr<USphereComponent> Sphere;
创建一个碰撞体球,用于检测和主角的碰撞来触发回调。
bash
Mesh = CreateDefaultSubobject<UStaticMeshComponent>("Mesh");
SetRootComponent(Mesh);
Sphere = CreateDefaultSubobject<USphereComponent>("Sphere");
Sphere->SetupAttachment(GetRootComponent());
然后初始化中,创建对象,并将Mesh设置为根节点,并将球碰撞体挂在Mesh下面。
bash
UFUNCTION()
virtual void OnOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
virtual void EndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
创建两个回调,用于碰撞触发的开始和结束。
bash
Sphere->OnComponentBeginOverlap.AddDynamic(this, &AEffectActorBase::OnOverlap);
Sphere->OnComponentEndOverlap.AddDynamic(this, &AEffectActorBase::EndOverlap);
绑定到球体碰撞事件上,如果球体触发了碰撞,则会调用这两个函数。
bash
void AEffectActorBase::OnOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
//TODO: 为了测试数值修改功能,启用了常量转变量功能。
if(IAbilitySystemInterface* ASCInterface = Cast<IAbilitySystemInterface>(OtherActor))
{
//根据类从ASC里面获取到对应的AS实例
const UAttributeSetBase* AttributeSet = Cast<UAttributeSetBase>(ASCInterface->GetAbilitySystemComponent()->GetAttributeSet(UAttributeSetBase::StaticClass()));
UAttributeSetBase* MutableAttributeSet = const_cast<UAttributeSetBase*>(AttributeSet); //将常量转为变量
MutableAttributeSet->SetHealth(AttributeSet->GetHealth() + 25.f);
Destroy(); // 销毁自身
}
}
接着在碰撞触发的时候,从接口获取到AttributeSet,然后设置数值增长。
接下来在UE里面创建一个蓝图,基于EffectActorBase。
左侧会发现我们在代码中添加的Mesh和Sphere。
添加模型网格体,然后调整球的大小。
运行场景,输入showdebug abilitysystem
如果值修改,那证明功能实现。
EffectActorBase.h
bash
// 版权归暮志未晚所有。
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "EffectActorBase.generated.h"
class USphereComponent;
class UStaticMeshComponent;
UCLASS()
class AURA_API AEffectActorBase : public AActor
{
GENERATED_BODY()
public:
AEffectActorBase();
UFUNCTION()
virtual void OnOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
virtual void EndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
protected:
// 游戏开始或生成对象时回调
virtual void BeginPlay() override;
private:
UPROPERTY(VisibleAnywhere)
TObjectPtr<USphereComponent> Sphere;
UPROPERTY(VisibleAnywhere)
TObjectPtr<UStaticMeshComponent> Mesh;
};
EffectActorBase.app
bash
// 版权归暮志未晚所有。
#include "Actor/EffectActorBase.h"
#include "AbilitySystemComponent.h"
#include "AbilitySystemInterface.h"
#include "AbilitySystem/AttributeSetBase.h"
#include "Components/SphereComponent.h"
AEffectActorBase::AEffectActorBase()
{
// 设置当前对象是否每帧调用Tick()
PrimaryActorTick.bCanEverTick = false;
Mesh = CreateDefaultSubobject<UStaticMeshComponent>("Mesh");
SetRootComponent(Mesh);
Sphere = CreateDefaultSubobject<USphereComponent>("Sphere");
Sphere->SetupAttachment(GetRootComponent());
}
void AEffectActorBase::OnOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
//TODO: 为了测试数值修改功能,启用了常量转变量功能。
if(IAbilitySystemInterface* ASCInterface = Cast<IAbilitySystemInterface>(OtherActor))
{
//根据类从ASC里面获取到对应的AS实例
const UAttributeSetBase* AttributeSet = Cast<UAttributeSetBase>(ASCInterface->GetAbilitySystemComponent()->GetAttributeSet(UAttributeSetBase::StaticClass()));
UAttributeSetBase* MutableAttributeSet = const_cast<UAttributeSetBase*>(AttributeSet); //将常量转为变量
MutableAttributeSet->SetHealth(AttributeSet->GetHealth() + 25.f);
Destroy(); // 销毁自身
}
}
void AEffectActorBase::EndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
}
void AEffectActorBase::BeginPlay()
{
Super::BeginPlay();
Sphere->OnComponentBeginOverlap.AddDynamic(this, &AEffectActorBase::OnOverlap);
Sphere->OnComponentEndOverlap.AddDynamic(this, &AEffectActorBase::EndOverlap);
}