我正在用 UE4 开发一个小游戏,遇到了一个小问题。
到目前为止,我已经让玩家在 C++ 中对敌人造成伤害(通过光线投射/线追踪)。现在我试图让敌人在他们的碰撞盒重叠时对玩家造成伤害。
玩家和敌人使用
TakeDamage()
功能互相造成伤害
目前,当两个碰撞重叠时,敌人确实会对使用此蓝图设置的玩家造成伤害。
我正在尝试将其翻译成 C++。 我一直在看许多网站,这些网站说要使用
OnActorBeginOverlap()
或 OnComponentBeginOverlap()
与 AddDynamic()
功能。但是,当尝试调用 OnActorBeginOverlap()
时,当我执行 BoxCollider->
但 OnComponentBeginOverlap()
时它不会出现,但没有 AddDynamic()
功能。据我了解,AddDynamic 是一个我不太熟悉的宏。 OnActorBeginOverlap()
确实出现没有BoxCollider->
。两个对象都是演员。
有什么想法吗?
代码示例:
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->OnComponentBeginOverlap.AddDynamic(this, &AMainCharacter::OnCollision);
在AddDynamic下有一条红线
我在用于 UE4 开发的 Discord 服务器中,但我并没有从那里获得任何帮助。
我可以看看你的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);
另外,当我学习虚幻引擎时,我处理了很多陷阱。尝试找到虚幻引擎开发人员社区并与他们一起学习。