Add new Perception Senses

This commit is contained in:
baz 2024-02-13 21:23:15 +00:00
parent 5b90d26bc6
commit 763706ac5c
5 changed files with 121 additions and 3 deletions

BIN
Content/Enemy/Worker/AIC_Worker.uasset (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -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);
}

View File

@ -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);
}; };

View File

@ -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;
}

View File

@ -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;
};