I’ll send you the Enemy.h and Enemy.cpp file.
Enemy.h file:
#pragma once
include “CoreMinimal.h”
include “GameFramework/Character.h”
include “Enemy.generated.h”UCLASS()
class MONSTER_SHOOTER_API AEnemy : public ACharacter
{
GENERATED_BODY()public:
// Sets default values for this character’s properties
AEnemy();protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;public:
// Called every frame
virtual void Tick(float DeltaTime) override;// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;UPROPERTY(EditAnywhere)
class UBoxComponent* DamageCollision;UFUNCTION()
void OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& Hit);UPROPERTY(VisibleDefaultsOnly, Category = Enemy)
class UAIPerceptionComponent* AIPerComp;UPROPERTY(VisibleDefaultsOnly, Category = Enemy)
class UAISenseConfig_Sight* SightConfig;UFUNCTION()
void OnSensed(const TArray<AActor*>& UpdatedActors);UPROPERTY(VisibleAnywhere, Category = Movement)
FRotator EnemyRotation;UPROPERTY(VisibleAnywhere, Category = Movement)
FVector BaseLocation;UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Movement)
FVector CurrentVelocity;UPROPERTY(VisibleAnywhere, Category = Movement)
float MovementSpeed;void SetNewRotation(FVector TargetPosition, FVector CurrentPosition);
bool BackToBaseLocation;
FVector NewLocation;
float DistanceSquared;UPROPERTY(EditAnywhere, BlueprintReadOnly)
float Health = 100.0f;UPROPERTY(EditAnywhere)
float DamageValue = 5.0f;public:
void DealDamage(float DamageAmount);
};
Enemy.cpp file:
include “Enemy.h”
include “Components/BoxComponent.h”
include “MonsterShooterCharacter.h”
include “Perception/AIPerceptionComponent.h”
include “Perception/AISenseConfig_Sight.h”// Sets default values
AEnemy::AEnemy()
{
// 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;DamageCollision = CreateDefaultSubobject(TEXT(“Damage Collision”));
DamageCollision->SetupAttachment(RootComponent);AIPerComp = CreateDefaultSubobject(TEXT(“AI Perception Component”));
SightConfig = CreateDefaultSubobject<UAISenseConfig_Sight>(TEXT(“Sight Config”));SightConfig->SightRadius = 10000.0f;
SightConfig->LoseSightRadius = 10030.0f;
SightConfig->PeripheralVisionAngleDegrees = 90.0f;
SightConfig->DetectionByAffiliation.bDetectEnemies = true;
SightConfig->DetectionByAffiliation.bDetectFriendlies = true;
SightConfig->DetectionByAffiliation.bDetectNeutrals = true;
SightConfig->SetMaxAge(0.1f);AIPerComp->ConfigureSense(*SightConfig);
AIPerComp->SetDominantSense(SightConfig->GetSenseImplementation());
AIPerComp->OnPerceptionUpdated.AddDynamic(this, &AEnemy::OnSensed);CurrentVelocity = FVector::ZeroVector;
MovementSpeed = -375.0f;DistanceSquared = BIG_NUMBER;
}// Called when the game starts or when spawned
void AEnemy::BeginPlay()
{
Super::BeginPlay();DamageCollision->OnComponentBeginOverlap.AddDynamic(this, &AEnemy::OnHit);
BaseLocation = this->GetActorLocation();
}// Called every frame
void AEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);if (!CurrentVelocity.IsZero())
{
NewLocation = GetActorLocation() + CurrentVelocity * DeltaTime;if (BackToBaseLocation) { if ((NewLocation - BaseLocation).SizeSquared2D() > DistanceSquared) { DistanceSquared = (NewLocation - BaseLocation).SizeSquared2D(); } else { CurrentVelocity = FVector::ZeroVector; DistanceSquared = BIG_NUMBER; BackToBaseLocation = false; SetNewRotation(GetActorForwardVector(), GetActorLocation()); } } SetActorLocation(NewLocation);
}
}// Called to bind functionality to input
void AEnemy::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);}
void AEnemy::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& Hit)
{
AMonsterShooterCharacter* Char = Cast(OtherActor);if (Char)
{
Char->DealDamage(DamageValue);
}
}void AEnemy::OnSensed(const TArray<AActor*>& UpdatedActors)
{
for (int i = 0; i < UpdatedActors.Num(); i++)
{
FActorPerceptionBlueprintInfo Info;
AIPerComp->GetActorsPerception(UpdatedActors[i], Info);if (Info.LastSensedStimuli[0].WasSuccessfullySensed()) { FVector dir = UpdatedActors[i]->GetActorLocation() - GetActorLocation(); dir.Z = 0.0f; CurrentVelocity = dir.GetSafeNormal() * MovementSpeed; SetNewRotation(UpdatedActors[i]->GetActorLocation(), GetActorLocation()); } else { FVector dir = BaseLocation - GetActorLocation(); dir.Z = 0.0f; if (dir.SizeSquared2D() > 1.0f) { CurrentVelocity = dir.GetSafeNormal() * MovementSpeed; BackToBaseLocation = true; SetNewRotation(BaseLocation, GetActorLocation()); } }
}
}void AEnemy::SetNewRotation(FVector TargetPosition, FVector CurrentPosition)
{
FVector NewDirection = TargetPosition - CurrentPosition;
NewDirection.Z = 0.0f;EnemyRotation = NewDirection.Rotation();
SetActorRotation(EnemyRotation);
}void AEnemy::DealDamage(float DamageAmount)
{
Health -= DamageAmount;if (Health <= 0.0f)
{
Destroy();
}
}