Enemies behave normally when I start the game, but when I respawn, the enemies approach me but don’t attack me… why??
// Fill out your copyright notice in the Description page of Project Settings.
include “Enemy/Enemy.h”
include “Components/SkeletalMeshComponent.h”
include “GameFramework/CharacterMovementComponent.h”
include “Perception/PawnSensingComponent.h”
include “Component/AttributeComponent.h”
include “HUD/HealthBarComponent.h”
include “Components/CapsuleComponent.h”
include “Navigation/PathFollowingComponent.h”
include “Item/Weapon/Weapon.h”
include “AIController.h”
include “Character/SlashCharacter.h”
AEnemy::AEnemy()
{
PrimaryActorTick.bCanEverTick = true;
GetMesh()->SetCollisionObjectType(ECollisionChannel::ECC_WorldDynamic);
GetMesh()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Visibility, ECollisionResponse::ECR_Block);
GetMesh()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Camera, ECollisionResponse::ECR_Ignore);
GetMesh()->SetGenerateOverlapEvents(true);
HealthBarWidget = CreateDefaultSubobject<UHealthBarComponent>(TEXT("HealthBar"));
HealthBarWidget->SetupAttachment(GetRootComponent());
GetCharacterMovement()->bOrientRotationToMovement = true;
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
PawnSensing = CreateDefaultSubobject<UPawnSensingComponent>(TEXT("PawnSensing"));
PawnSensing->SightRadius = 4000.f;
PawnSensing->SetPeripheralVisionAngle(80.f);
}
void AEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (IsDead()) return;
if (EnemyState > EEnemyState::EES_Patrolling)
{
CheckCombatTarget();
}
else
{
CheckPatrolTarget();
}
}
float AEnemy::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
HandleDamage(DamageAmount);
CombatTarget = EventInstigator->GetPawn();
if (IsInsideAttackRadius())
{
EnemyState = EEnemyState::EES_Attacking;
}
else if (IsOutsideAttackRadius())
{
ChaseTarget();
}
return DamageAmount;
}
void AEnemy::Destroyed()
{
if (EquippedWeapon)
{
EquippedWeapon->Destroy();
}
}
void AEnemy::GetHit_Implementation(const FVector& ImpactPoint, AActor* Hitter)
{
Super::GetHit_Implementation(ImpactPoint, Hitter);
if (!IsDead()) ShowHealthBar();
ClearPatrolTimer();
ClearAttackTimer();
SetWeaponCollisionEnabled(ECollisionEnabled::NoCollision);
StopAttackMontage();
}
void AEnemy::OnCharacterRespawn(ASlashCharacter* Character)
{
if (Character)
{
EnemyState = EEnemyState::EES_Attacking;
}
}
void AEnemy::BeginPlay()
{
Super::BeginPlay();
if (PawnSensing) PawnSensing->OnSeePawn.AddDynamic(this, &AEnemy::PawnSeen);
InitializeEnemy();
Tags.Add(FName("Enemy"));
}
void AEnemy::Die()
{
Super::Die();
EnemyState = EEnemyState::EES_Dead;
ClearAttackTimer();
HideHealthBar();
DisableCapsule();
SetLifeSpan(DeathLifeSpan);
GetCharacterMovement()->bOrientRotationToMovement = false;
SetWeaponCollisionEnabled(ECollisionEnabled::NoCollision);
}
void AEnemy::Attack()
{
Super::Attack();
if (CombatTarget == nullptr) return;
EnemyState = EEnemyState::EES_Engaged;
PlayAttackMontage();
}
bool AEnemy::CanAttack()
{
bool bCanAttack =
IsInsideAttackRadius() &&
!IsAttacking() &&
!IsEngaged() &&
!IsDead();
return bCanAttack;
}
void AEnemy::AttackEnd()
{
EnemyState = EEnemyState::EES_NoState;
CheckCombatTarget();
}
void AEnemy::HandleDamage(float DamageAmount)
{
Super::HandleDamage(DamageAmount);
if (Attributes && HealthBarWidget)
{
HealthBarWidget->SetHealthPercent(Attributes->GetHealthPercentage());
}
}
AActor* AEnemy::ChoosePatrolTarget()
{
TArray<AActor*> ValidTargets;
for (AActor* Target : PatrolTargets)
{
if (Target != PatrolTarget)
{
ValidTargets.AddUnique(Target);
}
}
const int32 NumPatrolTargets = ValidTargets.Num();
if (NumPatrolTargets > 0)
{
const int32 TargetSelection = FMath::RandRange(0, NumPatrolTargets - 1);
return ValidTargets[TargetSelection];
}
return nullptr;
}
void AEnemy::CheckCombatTarget()
{
if (IsOutsideCombatRadius())
{
ClearAttackTimer();
LoseInterest();
if (!IsEngaged()) StartPatrolling();
}
else if (IsOutsideAttackRadius() && !IsChasing())
{
ClearAttackTimer();
if (!IsEngaged()) ChaseTarget();
}
else if (CanAttack())
{
StartAttackTimer();
}
}
void AEnemy::PatrolTimerFinished()
{
MoveToTarget(PatrolTarget);
}
void AEnemy::HideHealthBar()
{
if (HealthBarWidget)
{
HealthBarWidget->SetVisibility(false);
}
}
void AEnemy::ShowHealthBar()
{
if (HealthBarWidget)
{
HealthBarWidget->SetVisibility(true);
}
}
void AEnemy::LoseInterest()
{
CombatTarget = nullptr;
HideHealthBar();
}
void AEnemy::StartPatrolling()
{
EnemyState = EEnemyState::EES_Patrolling;
GetCharacterMovement()->MaxWalkSpeed = PatrollingSpeed;
MoveToTarget(PatrolTarget);
}
void AEnemy::ChaseTarget()
{
EnemyState = EEnemyState::EES_Chasing;
GetCharacterMovement()->MaxWalkSpeed = ChasingSpeed;
MoveToTarget(CombatTarget);
}
bool AEnemy::IsOutsideCombatRadius()
{
return !InTargetRange(CombatTarget, CombatRadius);
}
bool AEnemy::IsOutsideAttackRadius()
{
return !InTargetRange(CombatTarget,AttackRadius);
}
bool AEnemy::IsInsideAttackRadius()
{
return InTargetRange(CombatTarget, AttackRadius);
}
bool AEnemy::IsChasing()
{
return EnemyState == EEnemyState::EES_Chasing;
}
bool AEnemy::IsAttacking()
{
return EnemyState == EEnemyState::EES_Attacking;
}
bool AEnemy::IsDead()
{
return EnemyState == EEnemyState::EES_Dead;
}
bool AEnemy::IsEngaged()
{
return EnemyState == EEnemyState::EES_Engaged;
}
void AEnemy::ClearPatrolTimer()
{
GetWorldTimerManager().ClearTimer(PatrolTimer);
}
void AEnemy::PawnSeen(APawn* SeenPawn)
{
const bool bShouldChaseTarget =
EnemyState != EEnemyState::EES_Dead &&
EnemyState != EEnemyState::EES_Chasing &&
EnemyState < EEnemyState::EES_Attacking &&
SeenPawn->ActorHasTag(FName(“EngageableTarget”));
if (bShouldChaseTarget)
{
CombatTarget = SeenPawn;
ClearPatrolTimer();
ChaseTarget();
}
}
void AEnemy::StartAttackTimer()
{
EnemyState = EEnemyState::EES_Attacking;
const float AttackTime = FMath::RandRange(AttackMin, AttackMax);
GetWorldTimerManager().SetTimer(AttackTimer, this, &AEnemy::Attack, AttackTime);
}
void AEnemy::ClearAttackTimer()
{
GetWorldTimerManager().ClearTimer(AttackTimer);
}
void AEnemy::SpawnDefaultWeapon()
{
UWorld* World = GetWorld();
if (World && WeaponClass)
{
AWeapon* DefaultWeapon = World->SpawnActor(WeaponClass);
DefaultWeapon->Equip(GetMesh(), FName(“WeaponSocket”), this, this);
DefaultWeapon->IgnoreActors.Emplace(this);
EquippedWeapon = DefaultWeapon;
}
}
bool AEnemy::InTargetRange(AActor* Target, double Radius)
{
if (Target == nullptr) return false;
const double DistanceToTarget = (Target->GetActorLocation() - GetActorLocation()).Size();
return DistanceToTarget <= Radius;
}
void AEnemy::MoveToTarget(AActor* Target)
{
if (EnemyController == nullptr || Target == nullptr) return;
FAIMoveRequest MoveRequest;
MoveRequest.SetGoalActor(Target);
MoveRequest.SetAcceptanceRadius(AcceptanceRadius);
EnemyController->MoveTo(MoveRequest);
}
void AEnemy::InitializeEnemy()
{
EnemyController = Cast(GetController());
MoveToTarget(PatrolTarget);
HideHealthBar();
SpawnDefaultWeapon();
}
void AEnemy::CheckPatrolTarget()
{
if (InTargetRange(PatrolTarget, PatrolRadius))
{
PatrolTarget = ChoosePatrolTarget();
const float WaitTime = FMath::RandRange(PatrolWaitMin, PatrolWaitMax);
GetWorldTimerManager().SetTimer(PatrolTimer, this, &AEnemy::PatrolTimerFinished, WaitTime);
}
}