【问题标题】:How to use OnActorBeginOverlap in UE4 C++如何在 UE4 C++ 中使用 OnActorBeginOverlap
【发布时间】:2021-07-04 13:21:56
【问题描述】:

我正在使用 UE4 开发一个小游戏,但遇到了一个小问题。

到目前为止,我已经让玩家在 C++ 中对敌人造成伤害(通过光线投射/线跟踪)。现在我试图让敌人在他们的碰撞框重叠时对玩家造成伤害。

玩家和敌人一样使用TakeDamage()函数互相造成伤害。

目前,当两个碰撞重叠时,敌人确实会对使用此蓝图设置的玩家造成伤害。

我正在尝试将其翻译成 C++。 我一直在查看许多网站,它们说要使用 OnActorBeginOverlap()OnComponentBeginOverlap()AddDynamic() 函数。但是,当我尝试调用OnActorBeginOverlap() 时,它不会出现,而我调用BoxCollider->OnComponentBeginOverlap() 会出现,但没有AddDynamic() 功能。据我了解,AddDynamic 是一个我不太熟悉的宏。 OnActorBeginOverlap() 确实在没有 BoxCollider-> 的情况下出现。两个对象都是 Actor。

有什么想法吗?

代码示例:

BasicZombie.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/BoxComponent.h"
#include "BasicZombie.generated.h"

UCLASS()
class MERCENARIES_API ABasicZombie : public AActor
{
    GENERATED_BODY()
    
public: 
    // Sets default values for this actor's properties
    ABasicZombie();

    void Destroy();

    UPROPERTY(EditAnywhere)
        UBoxComponent* BoxCollider;

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

    virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser) override;



private:
    UPROPERTY(EditDefaultsOnly)
        float maxHealth = 100.0f;

    UPROPERTY(VisibleAnywhere)
        float health;

    void DealDamage();
public: 
    // Called every frame
    virtual void Tick(float DeltaTime) override;

};

BasicZombie.cpp

#include "BasicZombie.h"
#include "MainCharacter.h"
#include "GameFramework/Actor.h"
#include "DrawDebugHelpers.h"
#include "Engine/Engine.h"

// Sets default values
ABasicZombie::ABasicZombie()
{
    // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = false;

    BoxCollider = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxCollider"));
    BoxCollider->OnComponentBeginOverlap.AddDynamic(this, &AMainCharacter::OnCollision);

    health = maxHealth;


    
}

// Called when the game starts or when spawned
void ABasicZombie::BeginPlay()
{
    Super::BeginPlay();
    
    
}

float ABasicZombie::TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser)
{
    float DamageToApply = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
    DamageToApply = FMath::Min(health, DamageToApply);
    health -= DamageToApply;
    UE_LOG(LogTemp, Warning, (TEXT("Health Remaining: %f")), health);
    //GEngine->AddOnScreenDebugMessage(-1, 3.0f, FColor::Red, FString::Printf(TEXT("Health Remaining: %f"), health));
    
    Destroy();

    return DamageToApply;
}

//void ABasicZombie::DealDamage()
//{
//  
//}



void ABasicZombie::Destroy()
{
    if (health <= 0)
    {
        UWorld* WorldRef = GetWorld();
        AMainCharacter* mainCharacter = Cast<AMainCharacter>(WorldRef->GetFirstPlayerController()->GetCharacter());
        mainCharacter->currentScore += 500;
        GEngine->AddOnScreenDebugMessage(-1, 3.0f, FColor::Green, FString::Printf(TEXT("Score: %i"), mainCharacter->currentScore));
        AActor::Destroy();
    }
}

// Called every frame
void ABasicZombie::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
}

MainCharacter.h

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"

#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/PlayerController.h"
#include "MainCharacter.generated.h"

class AHandgun;

UCLASS()
class MERCENARIES_API AMainCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    // Sets default values for this character's properties
    AMainCharacter();

    void OnCollision(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& Hit);

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

    virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser) override;

    

private:
    UPROPERTY(EditDefaultsOnly)
        TSubclassOf<AHandgun> HandgunClass;

    UPROPERTY()
        AHandgun* Handgun;

public: 
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    // Called to bind functionality to input
    virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

    //Handles Input for moving FORWARD and BACK
    UFUNCTION()
        void MoveForward(float value);

    //Handles input for moving RIGHT and LEFT
    UFUNCTION()
        void MoveRight(float value);

    UFUNCTION()
        void Shoot();

    UFUNCTION()
        void printHealth();

    //FPS camera
    UPROPERTY(VisibleAnywhere)
        UCameraComponent* MainCharacterCameraComponent;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
        FVector MuzzleOffset;

    UPROPERTY()
        int32 playerScore;

    UPROPERTY()
        int32 currentScore;

    UPROPERTY()
        float maxHealth = 1000.0f;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
        float currentHealth;

};

MainCharacter.cpp

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


#include "MainCharacter.h"
#include "Engine/Engine.h"
#include "GameFramework/Actor.h"
#include "Handgun.h"
#include "GameFramework/Character.h"
#include "Components/SkeletalMeshComponent.h"


// Sets default values
AMainCharacter::AMainCharacter()
{
    // Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

    //Create a first person camera component
    MainCharacterCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
    check(MainCharacterCameraComponent != nullptr);

    //Attach the camera component to our capsule component
    MainCharacterCameraComponent->SetupAttachment(CastChecked<USceneComponent, UCapsuleComponent>(GetCapsuleComponent()));

    //Position the camera slightly above the eyes
    MainCharacterCameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 50.0f + BaseEyeHeight));

    //Enable the pawn to control camera rotation
    MainCharacterCameraComponent->bUsePawnControlRotation = true;

    

    currentHealth = maxHealth;
    playerScore = currentScore;
}

// Called when the game starts or when spawned
void AMainCharacter::BeginPlay()
{
    Super::BeginPlay();

    

    check(GEngine != nullptr);
    GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("[MainCharacter DEBUG] - MainCharacter in use."));
    GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Green, FString::Printf(TEXT("[MainCharacter DEBUG] - Current Score: %f"), playerScore));

    Handgun = GetWorld()->SpawnActor<AHandgun>(HandgunClass);
    Handgun->AttachToComponent(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform, TEXT("WeaponSocket"));
    Handgun->SetOwner(this);
    
    
}

// Called every frame
void AMainCharacter::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
    //printHealth();

}

// Called to bind functionality to input
void AMainCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    //Set up movement bindings.
    PlayerInputComponent->BindAxis("MoveForward", this, &AMainCharacter::MoveForward);
    PlayerInputComponent->BindAxis("MoveRight", this, &AMainCharacter::MoveRight);

    //Set up Look Bindings
    PlayerInputComponent->BindAxis("Turn", this, &AMainCharacter::AddControllerYawInput);
    PlayerInputComponent->BindAxis("LookUp", this, &AMainCharacter::AddControllerPitchInput);

    //Setup Weapon Shooting
    PlayerInputComponent->BindAction(TEXT("Fire"), EInputEvent::IE_Pressed, this, &AMainCharacter::Shoot);
    PlayerInputComponent->BindAction(TEXT("printHealth"), EInputEvent::IE_Pressed, this, &AMainCharacter::printHealth);

}

void AMainCharacter::Shoot()
{
    Handgun->Shoot();
}

void AMainCharacter::printHealth()
{
    GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Green, FString::Printf(TEXT("[MainCharacter DEBUG] - Current Health: %f"), currentHealth));
}

float AMainCharacter::TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser)
{

    float DamageToApply = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
    DamageToApply = FMath::Min(currentHealth, DamageToApply);
    currentHealth -= DamageToApply;

    GEngine->AddOnScreenDebugMessage(-1, 3.0f, FColor::Red, FString::Printf(TEXT("Health Remaining: %f"), currentHealth));
    if (currentHealth <= 0)
    {
        GEngine->AddOnScreenDebugMessage(-1, 3.0f, FColor::Red, TEXT("You're Dead!"));
    }

    return DamageAmount;
}

void AMainCharacter::MoveForward(float value)
{
    //Find out which way is "forward" and reocrd that the player wants to move that way
    FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
    AddMovementInput(Direction, value);
}

void AMainCharacter::MoveRight(float value)
{
    //Find out which way is "right" and record that the player wants to move that way
    FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
    AddMovementInput(Direction, value);
}



但是,BasicZombie.cpp 中的BoxCollider-&gt;OnComponentBeginOverlap.AddDynamic(this, &amp;AMainCharacter::OnCollision); 在 AddDynamic 下有一条红线。

我在用于 UE4 开发的 Discord 服务器中,但我没有从那里获得任何帮助。

【问题讨论】:

    标签: c++ unreal-engine4


    【解决方案1】:

    我可以看看你的 C++ 代码吗?你是从 UBoxComponent 调用 AddDynamic 吗? 试试这个

    UPROPERTY(EditAnywhere)
         UBoxComponent* BoxCollider = nullptr;
    
    BoxCollider = GetOwner()->FindComponentByClass<UBoxComponent>();
    BoxCollider->OnComponentBeginOverlap.AddDynamic(this, &YourActor::OnCollision);
    

    将此用作您的 OnCollision 签名

    void OnCollision(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& Hit);
    

    此外,当我学习虚幻引擎时,我遇到了很多陷阱。尝试寻找虚幻引擎开发者社区并与他们一起学习。

    【讨论】:

    • 当我将您的示例用于 UBoxComponent = nullptr 时,我的编辑器崩溃了。我将用一些代码示例编辑上面的帖子。
    • 你可以试试 FindComponentByClass 吗?
    • 对不起,我试过 UBoxComponent* BoxCollider = nullptr;使用 BoxCollider->FindComponentByClass,一旦我编译,编辑器就会崩溃。
    猜你喜欢
    • 1970-01-01
    • 2021-02-20
    • 2022-08-15
    • 2021-09-10
    • 2018-09-14
    • 2020-11-15
    • 1970-01-01
    • 1970-01-01
    • 2019-06-09
    相关资源
    最近更新 更多