UEC 利用代理/委托写一个生命组件

首先基于ActorComponent创建一个组件 HealthComponent,将需要的变量与函数创建

#include "CoreMinimal.h" #include "Components/ActorComponent.h" #include "HealthComponent.generated.h"  UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) class PVETPC_API UHealthComponent : public UActorComponent {     GENERATED_BODY()  public:         // Sets default values for this component's properties     UHealthComponent();     // 初始化健康值     UFUNCTION(BlueprintCallable)         void Init(int taotalHealth,int currentHealth);     // 造成伤害     UFUNCTION(BlueprintCallable)         void HanldTakeAnyDamaged(AActor* DamagedActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);     // 恢复健康值     UFUNCTION(BlueprintCallable)         void RestoreHealth(int restoreValue);     UFUNCTION(BlueprintPure)         float GetHealth() { return CurrentHealth; } protected:     // 总健康值     float TotalHealth;     // 当前健康值     float CurrentHealth;      // Called when the game starts     virtual void BeginPlay() override;  public:         // Called every frame     virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; };

这里的 HanldTakeAnyDamaged 函数是通过代理绑定到拥有者身上

HanldTakeAnyDamaged 需要的形参需要与 OnTakeAnyDamage 的宏定义一致

除此之外还有OnTakePointDamageOnTakeRadialDamage 也是一样的操作

#include "Components/HealthComponent.h" #include "Engine.h" #include "Kismet/KismetSystemLibrary.h" // Sets default values for this component's properties UHealthComponent::UHealthComponent() {     // Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features     // off to improve performance if you don't need them.     PrimaryComponentTick.bCanEverTick = true;      // ... }  void UHealthComponent::Init(int taotalHealth, int currentHealth) {     TotalHealth = taotalHealth;     CurrentHealth = currentHealth; }  void UHealthComponent::HanldTakeAnyDamaged(AActor* DamagedActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser) {     if (Damage <= 0) { return; }     CurrentHealth = FMath::Clamp( CurrentHealth - Damage , 0.f, TotalHealth);     UE_LOG(LogTemp, Warning, TEXT("I am Demaged! CurrentHealth = %f"), CurrentHealth); }  void UHealthComponent::RestoreHealth(int restoreValue) {     CurrentHealth = FMath::Clamp(CurrentHealth + restoreValue, 0.f, TotalHealth);     GEngine->AddOnScreenDebugMessage(-1, 20, FColor::Red, FString(TEXT("I am RestoreHealth!"))); }   // Called when the game starts void UHealthComponent::BeginPlay() {     Super::BeginPlay();     // 获取拥有者     AActor* MyOwner = GetOwner();     // 如果存在就将伤害接收函数绑定     if (MyOwner)     {         UE_LOG(LogTemp, Warning, TEXT("I am bound!"));         MyOwner->OnTakeAnyDamage.AddDynamic(this, &UHealthComponent::HanldTakeAnyDamaged);     }     Init(100,100);     // ...      }  // Called every frame void UHealthComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) {     Super::TickComponent(DeltaTime, TickType, ThisTickFunction);      // ... }

这时候我们将该组件挂载在角色身上,已经有了效果,但是角色不知道组件生命值是否改变

接着我们在组件头文件的头文件申明下添加代理的宏定义,并创建一个代理对象

并在需要响应的函数中添加广播

#include "CoreMinimal.h" #include "Components/ActorComponent.h" #include "HealthComponent.generated.h"  // 自定义六参数代理事件 DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FOnHealthChangedSignature, UHealthComponent*, HealthComp, float, Health, float, HealthDelta, const class UDamageType*, DamageType, class AController*, InstigatedBy, AActor*, DamageCauser); ......     // 恢复健康值     UFUNCTION(BlueprintCallable)         void RestoreHealth(int restoreValue);     UFUNCTION(BlueprintPure)         float GetHealth() { return CurrentHealth; }        // 定义代理     UPROPERTY(BlueprintAssignable, Category = "Events")         FOnHealthChangedSignature OnHealthChanged;  ......      

void UHealthComponent::HanldTakeAnyDamaged(AActor* DamagedActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser) {     if (Damage <= 0) { return; }     CurrentHealth = FMath::Clamp( CurrentHealth - Damage , 0.f, TotalHealth);     UE_LOG(LogTemp, Warning, TEXT("I am Demaged! CurrentHealth = %f"), CurrentHealth);     // 每当该函数被调用时,就将调用一次代理函数     OnHealthChanged.Broadcast(this, CurrentHealth, Damage, DamageType, InstigatedBy, DamageCauser); }

最后再到拥有者类中添加一个用于回调的操作函数,其中形参对应在生命组件中定义的那样(注意命名是否重复)

头文件

    // 代理事件     UFUNCTION()     void OnHealthChanged(UHealthComponent* OnwerHealthComp, float Health, float HealthDelta,         const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);

cpp文件

void APCharacter::OnHealthChanged(UHealthComponent* OnwerHealthComp, float Health, float HealthDelta, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser) {     if (IsDeath) return;     UE_LOG(LogTemp, Warning, TEXT("I know I was hurt! "));     if (Health <= 0 && !IsDeath)     {         UE_LOG(LogTemp, Warning, TEXT("I am Death! "));         IsDeath = true;
     Death(); GetMovementComponent()
->StopMovementImmediately(); GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision); // 分离控制器 DetachFromControllerPendingDestroy(); // 3秒后执行 SetLifeSpan(3.0f);
} }
void APCharacter::BeginPlay() { Super::BeginPlay(); HealthComp->OnHealthChanged.AddDynamic(this, &APCharacter::OnHealthChanged); }

最后测试,结果无误

UEC 利用代理/委托写一个生命组件

 

发表评论

评论已关闭。

相关文章

当前内容话题