From 763706ac5c06def7161f75adaa9e81c1fd5109ca Mon Sep 17 00:00:00 2001 From: baz Date: Tue, 13 Feb 2024 21:23:15 +0000 Subject: [PATCH] Add new Perception Senses --- Content/Enemy/Worker/AIC_Worker.uasset | 3 ++ Source/Nakatomi/EnemyAIController.cpp | 63 ++++++++++++++++++++++++-- Source/Nakatomi/EnemyAIController.h | 14 ++++++ Source/Nakatomi/Tasks/BTTSetState.cpp | 17 +++++++ Source/Nakatomi/Tasks/BTTSetState.h | 27 +++++++++++ 5 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 Content/Enemy/Worker/AIC_Worker.uasset create mode 100644 Source/Nakatomi/Tasks/BTTSetState.cpp create mode 100644 Source/Nakatomi/Tasks/BTTSetState.h diff --git a/Content/Enemy/Worker/AIC_Worker.uasset b/Content/Enemy/Worker/AIC_Worker.uasset new file mode 100644 index 0000000..105a3ce --- /dev/null +++ b/Content/Enemy/Worker/AIC_Worker.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50deb580132c8059cab1d6b9cd9556977ece12cd3300827cb696e1940801377a +size 19654 diff --git a/Source/Nakatomi/EnemyAIController.cpp b/Source/Nakatomi/EnemyAIController.cpp index e67cc77..66fd18c 100644 --- a/Source/Nakatomi/EnemyAIController.cpp +++ b/Source/Nakatomi/EnemyAIController.cpp @@ -27,8 +27,19 @@ AEnemyAIController::AEnemyAIController(const FObjectInitializer& object_initiali SightConfig->DetectionByAffiliation.bDetectEnemies = true; SightConfig->DetectionByAffiliation.bDetectNeutrals = true; + HearingConfig = CreateDefaultSubobject(TEXT("Hearing Sense Config")); + HearingConfig->HearingRange = 800.0f; + HearingConfig->SetMaxAge(3.0f); + HearingConfig->DetectionByAffiliation.bDetectEnemies = true; + HearingConfig->DetectionByAffiliation.bDetectNeutrals = true; + + DamageConfig = CreateDefaultSubobject(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& actors) { - for (auto actor : actors) + for (AActor* actor : actors) { if (!actor->GetClass()->IsChildOf(APlayerCharacter::StaticClass())) { @@ -130,13 +141,32 @@ void AEnemyAIController::OnPerceptionUpdated(const TArray& 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(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(Blackboard->GetValueAsEnum("State")); + + + if (CurrentState == EAIState::PASSIVE || CurrentState == EAIState::INVESTIGATING) + { + SetStateAsAttacking(actor); + } +} + +void AEnemyAIController::SensedHearing(AActor* actor, FAIStimulus& stimulus) +{ + EAIState CurrentState = static_cast(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); +} diff --git a/Source/Nakatomi/EnemyAIController.h b/Source/Nakatomi/EnemyAIController.h index 28f02e5..d14f019 100644 --- a/Source/Nakatomi/EnemyAIController.h +++ b/Source/Nakatomi/EnemyAIController.h @@ -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); }; diff --git a/Source/Nakatomi/Tasks/BTTSetState.cpp b/Source/Nakatomi/Tasks/BTTSetState.cpp new file mode 100644 index 0000000..afb0f28 --- /dev/null +++ b/Source/Nakatomi/Tasks/BTTSetState.cpp @@ -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(owner.GetAIOwner())) + { + EnemyController->SetState(NewState); + return EBTNodeResult::Succeeded; + } + + return EBTNodeResult::Failed; +} diff --git a/Source/Nakatomi/Tasks/BTTSetState.h b/Source/Nakatomi/Tasks/BTTSetState.h new file mode 100644 index 0000000..2aa3518 --- /dev/null +++ b/Source/Nakatomi/Tasks/BTTSetState.h @@ -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; + +};