Add reworked Worker Enemy AI #3
Binary file not shown.
|
@ -27,8 +27,19 @@ AEnemyAIController::AEnemyAIController(const FObjectInitializer& object_initiali
|
|||
SightConfig->DetectionByAffiliation.bDetectEnemies = true;
|
||||
SightConfig->DetectionByAffiliation.bDetectNeutrals = true;
|
||||
|
||||
HearingConfig = CreateDefaultSubobject<UAISenseConfig_Hearing>(TEXT("Hearing Sense Config"));
|
||||
HearingConfig->HearingRange = 800.0f;
|
||||
HearingConfig->SetMaxAge(3.0f);
|
||||
HearingConfig->DetectionByAffiliation.bDetectEnemies = true;
|
||||
HearingConfig->DetectionByAffiliation.bDetectNeutrals = true;
|
||||
|
||||
DamageConfig = CreateDefaultSubobject<UAISenseConfig_Damage>(TEXT("Damage Sense Config"));
|
||||
DamageConfig->SetMaxAge(5.0f);
|
||||
|
||||
AIPerception->SetDominantSense(SightConfig->GetSenseImplementation());
|
||||
AIPerception->ConfigureSense(*SightConfig);
|
||||
AIPerception->ConfigureSense(*HearingConfig);
|
||||
AIPerception->ConfigureSense(*DamageConfig);
|
||||
}
|
||||
|
||||
void AEnemyAIController::OnPossess(APawn* InPawn)
|
||||
|
@ -120,7 +131,7 @@ void AEnemyAIController::OnDeath(FDamageInfo info)
|
|||
|
||||
void AEnemyAIController::OnPerceptionUpdated(const TArray<AActor*>& actors)
|
||||
{
|
||||
for (auto actor : actors)
|
||||
for (AActor* actor : actors)
|
||||
{
|
||||
if (!actor->GetClass()->IsChildOf(APlayerCharacter::StaticClass()))
|
||||
{
|
||||
|
@ -130,13 +141,32 @@ void AEnemyAIController::OnPerceptionUpdated(const TArray<AActor*>& actors)
|
|||
FActorPerceptionBlueprintInfo perceptionInfo;
|
||||
PerceptionComponent->GetActorsPerception(actor, perceptionInfo);
|
||||
|
||||
for (auto& stimulus : perceptionInfo.LastSensedStimuli)
|
||||
for (FAIStimulus& stimulus : perceptionInfo.LastSensedStimuli)
|
||||
{
|
||||
if (!stimulus.IsValid() || stimulus.IsExpired())
|
||||
if (!stimulus.IsValid() || stimulus.IsExpired() ||
|
||||
static_cast<EAIState>(Blackboard->GetValueAsEnum("State")) == EAIState::DEAD)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FAISenseID SightID = SightConfig->GetSenseID();
|
||||
FAISenseID HearingID = HearingConfig->GetSenseID();
|
||||
FAISenseID DamageID = DamageConfig->GetSenseID();
|
||||
|
||||
if (stimulus.Type == SightID)
|
||||
{
|
||||
SensedSight(actor, stimulus);
|
||||
}
|
||||
else if (stimulus.Type == HearingID)
|
||||
{
|
||||
SensedHearing(actor, stimulus);
|
||||
stimulus.StimulusLocation;
|
||||
}
|
||||
else if (stimulus.Type == DamageID)
|
||||
{
|
||||
SensedDamaged(actor, stimulus);
|
||||
}
|
||||
|
||||
Blackboard->SetValueAsObject("TargetActor", actor);
|
||||
|
||||
if (stimulus.IsActive())
|
||||
|
@ -199,3 +229,30 @@ void AEnemyAIController::SetStateAsAttacking(AActor* target)
|
|||
Blackboard->SetValueAsObject("TargetActor", target);
|
||||
SetState(EAIState::ATTACKING);
|
||||
}
|
||||
|
||||
void AEnemyAIController::SensedSight(AActor* actor, FAIStimulus& stimulus)
|
||||
{
|
||||
EAIState CurrentState = static_cast<EAIState>(Blackboard->GetValueAsEnum("State"));
|
||||
|
||||
|
||||
if (CurrentState == EAIState::PASSIVE || CurrentState == EAIState::INVESTIGATING)
|
||||
{
|
||||
SetStateAsAttacking(actor);
|
||||
}
|
||||
}
|
||||
|
||||
void AEnemyAIController::SensedHearing(AActor* actor, FAIStimulus& stimulus)
|
||||
{
|
||||
EAIState CurrentState = static_cast<EAIState>(Blackboard->GetValueAsEnum("State"));
|
||||
|
||||
if (CurrentState == EAIState::PASSIVE || CurrentState == EAIState::INVESTIGATING)
|
||||
{
|
||||
SetState(EAIState::INVESTIGATING);
|
||||
Blackboard->SetValueAsVector("InvestigationLocation", stimulus.StimulusLocation);
|
||||
}
|
||||
}
|
||||
|
||||
void AEnemyAIController::SensedDamaged(AActor* actor, FAIStimulus& stimulus)
|
||||
{
|
||||
SetStateAsAttacking(actor);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "EAIState.h"
|
||||
#include "EnemyCharacter.h"
|
||||
#include "PlayerCharacter.h"
|
||||
#include "Perception/AISenseConfig_Damage.h"
|
||||
#include "Perception/AISenseConfig_Hearing.h"
|
||||
#include "Perception/AISenseConfig_Sight.h"
|
||||
#include "EnemyAIController.generated.h"
|
||||
|
||||
|
@ -30,6 +32,10 @@ private:
|
|||
|
||||
UAISenseConfig_Sight* SightConfig;
|
||||
|
||||
UAISenseConfig_Hearing* HearingConfig;
|
||||
|
||||
UAISenseConfig_Damage* DamageConfig;
|
||||
|
||||
bool HasAttackToken = false;
|
||||
|
||||
public:
|
||||
|
@ -69,4 +75,12 @@ public:
|
|||
|
||||
UFUNCTION()
|
||||
void SetStateAsAttacking(AActor* target);
|
||||
|
||||
private:
|
||||
|
||||
void SensedSight(AActor* actor, FAIStimulus& stimulus);
|
||||
|
||||
void SensedHearing(AActor* actor, FAIStimulus& stimulus);
|
||||
|
||||
void SensedDamaged(AActor* actor, FAIStimulus& stimulus);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "../Tasks/BTTSetState.h"
|
||||
|
||||
#include "Nakatomi/EnemyAIController.h"
|
||||
|
||||
EBTNodeResult::Type UBTTSetState::ExecuteTask(UBehaviorTreeComponent& owner, uint8* memory)
|
||||
{
|
||||
if (AEnemyAIController* EnemyController = Cast<AEnemyAIController>(owner.GetAIOwner()))
|
||||
{
|
||||
EnemyController->SetState(NewState);
|
||||
return EBTNodeResult::Succeeded;
|
||||
}
|
||||
|
||||
return EBTNodeResult::Failed;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "BehaviorTree/BTTaskNode.h"
|
||||
#include "Nakatomi/EAIState.h"
|
||||
#include "BTTSetState.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class NAKATOMI_API UBTTSetState : public UBTTaskNode
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = "Options",
|
||||
Meta = (AllowPrivateAccess = "true", DisplayName = "New State"))
|
||||
EAIState NewState;
|
||||
|
||||
public:
|
||||
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& owner, uint8* memory) override;
|
||||
|
||||
};
|
Loading…
Reference in New Issue