Nakatomi/Source/Nakatomi/EnemyAIController.cpp

138 lines
4.0 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "EnemyAIController.h"
#include "Engine/EngineTypes.h"
#include "Components/CapsuleComponent.h"
AEnemyAIController::AEnemyAIController(const FObjectInitializer& object_initializer)
{
Blackboard = CreateDefaultSubobject<UBlackboardComponent>(TEXT("Blackboard"));
BehaviorTree = CreateDefaultSubobject<UBehaviorTreeComponent>(TEXT("Behavior Tree"));
PerceptionComponent = CreateDefaultSubobject<UAIPerceptionComponent>(TEXT("Perception Component"));
AIPerception = PerceptionComponent;
UAISenseConfig_Sight* ConfigSight = CreateDefaultSubobject<UAISenseConfig_Sight>(TEXT("Sight Sense Config"));
ConfigSight->SightRadius = 1000.0f;
ConfigSight->LoseSightRadius = 1000.0f;
ConfigSight->PeripheralVisionAngleDegrees = 30.0f;
AIPerception->ConfigureSense(*ConfigSight);
}
void AEnemyAIController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
auto enemy = Cast<AEnemyCharacter>(InPawn);
check(enemy);
SetPerceptionComponent(*enemy->GetPerceptionComponent());
enemy->GetPerceptionComponent()->OnPerceptionUpdated.AddDynamic(this, &AEnemyAIController::OnPerceptionUpdated);
enemy->GetCharacterMovement()->MaxWalkSpeed = 500.f;
enemy->GetHealthComponent()->OnDamaged.BindUFunction(this, "OnDamaged");
enemy->GetHealthComponent()->OnDeath.BindUFunction(this, "OnDeath");
if (auto behaviourTree = enemy->GetBehaviourTree())
{
Blackboard->InitializeBlackboard(*behaviourTree->BlackboardAsset);
BehaviorTree->StartTree(*behaviourTree);
}
//ensure(enemy->GetMovementComponent()->UseAccelerationForPathFollowing());
}
void AEnemyAIController::BeginPlay()
{
Super::BeginPlay();
}
void AEnemyAIController::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
AEnemyCharacter* AEnemyAIController::GetEnemyCharacter()
{
return Cast<AEnemyCharacter>(GetCharacter());
}
void AEnemyAIController::OnDamaged(FDamageInfo info)
{
if (GetEnemyCharacter()->GetHealthComponent()->GetCurrentHealth() > 0.0f)
{
// TODO: Do stuff here
}
}
void AEnemyAIController::OnDeath(FDamageInfo info)
{
// TODO: Do stuff here
auto enemy = GetEnemyCharacter();
enemy->DetachFromControllerPendingDestroy();
enemy->GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
enemy->GetCapsuleComponent()->SetCollisionResponseToAllChannels(ECR_Ignore);
enemy->GetMesh()->SetCollisionProfileName("Ragdoll");
enemy->SetActorEnableCollision(true);
enemy->GetMesh()->SetAllBodiesSimulatePhysics(true);
enemy->GetMesh()->SetSimulatePhysics(true);
enemy->GetMesh()->WakeAllRigidBodies();
enemy->GetMesh()->bBlendPhysics = true;
if (auto characterMovementComponent = enemy->GetCharacterMovement())
{
characterMovementComponent->StopMovementImmediately();
characterMovementComponent->DisableMovement();
characterMovementComponent->SetComponentTickEnabled(false);
}
enemy->SetLifeSpan(10.0f);
if (enemy->DefaultWeaponInventory.Num() > 0)
{
// TODO: This can sometimes crash, need to investigate
auto weaponPickup = GetWorld()->SpawnActor<AWeaponPickup>();
weaponPickup->SetActorLocation(enemy->GetActorLocation());
weaponPickup->SetWeapon(enemy->DefaultWeaponInventory[enemy->GetCurrentInventorySlot()]);
weaponPickup->SetWeaponProperties(*enemy->CurrentWeapon->GetWeaponProperties());
}
}
void AEnemyAIController::OnPerceptionUpdated(const TArray<AActor*>& actors)
{
for (auto actor : actors)
{
if (!actor->GetClass()->IsChildOf(APlayerCharacter::StaticClass()))
{
continue;
}
FActorPerceptionBlueprintInfo perceptionInfo;
PerceptionComponent->GetActorsPerception(actor, perceptionInfo);
for (auto& stimulus : perceptionInfo.LastSensedStimuli)
{
if (!stimulus.IsValid() || stimulus.IsExpired())
{
continue;
}
Blackboard->SetValueAsObject("TargetActor", actor);
if (stimulus.IsActive())
{
PlayerCharacter = Cast<APlayerCharacter>(actor);
SetFocus(PlayerCharacter, EAIFocusPriority::Gameplay);
}
else
{
PlayerCharacter = nullptr;
SetFocus(nullptr, EAIFocusPriority::Gameplay);
}
}
}
}