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.bDetectEnemies = true;
|
||||||
SightConfig->DetectionByAffiliation.bDetectNeutrals = 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->SetDominantSense(SightConfig->GetSenseImplementation());
|
||||||
AIPerception->ConfigureSense(*SightConfig);
|
AIPerception->ConfigureSense(*SightConfig);
|
||||||
|
AIPerception->ConfigureSense(*HearingConfig);
|
||||||
|
AIPerception->ConfigureSense(*DamageConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AEnemyAIController::OnPossess(APawn* InPawn)
|
void AEnemyAIController::OnPossess(APawn* InPawn)
|
||||||
|
@ -120,7 +131,7 @@ void AEnemyAIController::OnDeath(FDamageInfo info)
|
||||||
|
|
||||||
void AEnemyAIController::OnPerceptionUpdated(const TArray<AActor*>& actors)
|
void AEnemyAIController::OnPerceptionUpdated(const TArray<AActor*>& actors)
|
||||||
{
|
{
|
||||||
for (auto actor : actors)
|
for (AActor* actor : actors)
|
||||||
{
|
{
|
||||||
if (!actor->GetClass()->IsChildOf(APlayerCharacter::StaticClass()))
|
if (!actor->GetClass()->IsChildOf(APlayerCharacter::StaticClass()))
|
||||||
{
|
{
|
||||||
|
@ -130,13 +141,32 @@ void AEnemyAIController::OnPerceptionUpdated(const TArray<AActor*>& actors)
|
||||||
FActorPerceptionBlueprintInfo perceptionInfo;
|
FActorPerceptionBlueprintInfo perceptionInfo;
|
||||||
PerceptionComponent->GetActorsPerception(actor, 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;
|
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);
|
Blackboard->SetValueAsObject("TargetActor", actor);
|
||||||
|
|
||||||
if (stimulus.IsActive())
|
if (stimulus.IsActive())
|
||||||
|
@ -199,3 +229,30 @@ void AEnemyAIController::SetStateAsAttacking(AActor* target)
|
||||||
Blackboard->SetValueAsObject("TargetActor", target);
|
Blackboard->SetValueAsObject("TargetActor", target);
|
||||||
SetState(EAIState::ATTACKING);
|
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 "EAIState.h"
|
||||||
#include "EnemyCharacter.h"
|
#include "EnemyCharacter.h"
|
||||||
#include "PlayerCharacter.h"
|
#include "PlayerCharacter.h"
|
||||||
|
#include "Perception/AISenseConfig_Damage.h"
|
||||||
|
#include "Perception/AISenseConfig_Hearing.h"
|
||||||
#include "Perception/AISenseConfig_Sight.h"
|
#include "Perception/AISenseConfig_Sight.h"
|
||||||
#include "EnemyAIController.generated.h"
|
#include "EnemyAIController.generated.h"
|
||||||
|
|
||||||
|
@ -30,6 +32,10 @@ private:
|
||||||
|
|
||||||
UAISenseConfig_Sight* SightConfig;
|
UAISenseConfig_Sight* SightConfig;
|
||||||
|
|
||||||
|
UAISenseConfig_Hearing* HearingConfig;
|
||||||
|
|
||||||
|
UAISenseConfig_Damage* DamageConfig;
|
||||||
|
|
||||||
bool HasAttackToken = false;
|
bool HasAttackToken = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -69,4 +75,12 @@ public:
|
||||||
|
|
||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
void SetStateAsAttacking(AActor* target);
|
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