diff --git a/Content/CombatSystem/Blueprints/AI/BB_Base.uasset b/Content/CombatSystem/Blueprints/AI/BB_Base.uasset index ae8141ea..fefb567b 100644 Binary files a/Content/CombatSystem/Blueprints/AI/BB_Base.uasset and b/Content/CombatSystem/Blueprints/AI/BB_Base.uasset differ diff --git a/Content/CombatSystem/Blueprints/AI/BP_ExampleEnemy.uasset b/Content/CombatSystem/Blueprints/AI/BP_ExampleEnemy.uasset index 908e286e..9a257ca2 100644 Binary files a/Content/CombatSystem/Blueprints/AI/BP_ExampleEnemy.uasset and b/Content/CombatSystem/Blueprints/AI/BP_ExampleEnemy.uasset differ diff --git a/Source/D1/AI/CombatAIController.cpp b/Source/D1/AI/CombatAIController.cpp index 1e2ba5af..36fbf5a7 100644 --- a/Source/D1/AI/CombatAIController.cpp +++ b/Source/D1/AI/CombatAIController.cpp @@ -3,10 +3,34 @@ #include "AI/CombatAIController.h" +#include "GameplayTagAssetInterface.h" #include "MasterAI.h" +#include "BehaviorTree/BlackboardComponent.h" +#include "Perception/AIPerceptionComponent.h" +#include "Perception/AISenseConfig_Damage.h" +#include "Perception/AISenseConfig_Sight.h" ACombatAIController::ACombatAIController() { + PerceptionComponent = CreateDefaultSubobject(TEXT("PerceptionComponent")); + + SightConfig = CreateDefaultSubobject(TEXT("SightConfig")); + SightConfig->SightRadius = 3000.f; + SightConfig->LoseSightRadius = 3500.f; + SightConfig->PeripheralVisionAngleDegrees = 45.f; + FAISenseAffiliationFilter AffiliationFilter; + AffiliationFilter.bDetectEnemies = true; + AffiliationFilter.bDetectFriendlies = true; + AffiliationFilter.bDetectNeutrals = true; + SightConfig->DetectionByAffiliation = AffiliationFilter; + SightConfig->AutoSuccessRangeFromLastSeenLocation = 500.f; + PerceptionComponent->ConfigureSense(*SightConfig); + + DamageConfig = CreateDefaultSubobject(TEXT("DamageConfig")); + DamageConfig->SetMaxAge(3.f); // Expired 3 Seconds + PerceptionComponent->ConfigureSense(*DamageConfig); + + PerceptionComponent->OnPerceptionUpdated.AddDynamic(this, &ACombatAIController::OnUpdatePerception); } void ACombatAIController::OnPossess(APawn* InPawn) @@ -20,3 +44,40 @@ void ACombatAIController::OnPossess(APawn* InPawn) RunBehaviorTree(MasterAI->GetBeHaviorTree()); } } + +void ACombatAIController::OnUpdatePerception(const TArray& PerceivedActors) +{ + for (auto SensoredActor : PerceivedActors) + { + FActorPerceptionBlueprintInfo PerceptionInfo; + GetPerceptionComponent()->GetActorsPerception(SensoredActor, PerceptionInfo); + + for(int i = 0; i < PerceptionInfo.LastSensedStimuli.Num(); i++) + { + auto Info = PerceptionInfo.LastSensedStimuli[i]; + auto SensedClass = UAIPerceptionSystem::GetSenseClassForStimulus(this, Info); + if(SensedClass == UAISense_Sight::StaticClass()) + { + if(Info.WasSuccessfullySensed()) + { + if(Cast(SensoredActor)->HasMatchingGameplayTag(FCombatGameplayTags::Get().Character_Player)) + { + Blackboard->SetValueAsObject(TEXT("Target"), SensoredActor); + } + } + else + Blackboard->SetValueAsObject(TEXT("Target"), nullptr); + } + else if(SensedClass == UAISense_Damage::StaticClass()) + { + if(Info.WasSuccessfullySensed() && !Info.IsExpired()) //After DamageConfig->GetMaxAge then Expired + { + if(Cast(SensoredActor)->HasMatchingGameplayTag(FCombatGameplayTags::Get().Character_Player)) + { + Blackboard->SetValueAsObject(TEXT("Target"), SensoredActor); + } + } + } + } + } +} diff --git a/Source/D1/AI/CombatAIController.h b/Source/D1/AI/CombatAIController.h index f8b04472..a56b30ab 100644 --- a/Source/D1/AI/CombatAIController.h +++ b/Source/D1/AI/CombatAIController.h @@ -16,9 +16,16 @@ class D1_API ACombatAIController : public AAIController public: ACombatAIController(); - -protected: +protected: //Inherited Func virtual void OnPossess(APawn* InPawn) override; +public: //Delegate Func + UFUNCTION(BlueprintCallable) + void OnUpdatePerception(const TArray& PerceivedActors); private: + UPROPERTY() TObjectPtr MasterAI; + UPROPERTY() + TObjectPtr SightConfig; + UPROPERTY() + TObjectPtr DamageConfig; }; diff --git a/Source/D1/AI/MasterAI.cpp b/Source/D1/AI/MasterAI.cpp index d9376115..51aeb81a 100644 --- a/Source/D1/AI/MasterAI.cpp +++ b/Source/D1/AI/MasterAI.cpp @@ -16,6 +16,7 @@ #include "DamageType/AttackDamageType.h" #include "Kismet/KismetMathLibrary.h" #include "Kismet/GameplayStatics.h" +#include "Perception/AISense_Damage.h" AMasterAI::AMasterAI() { @@ -98,12 +99,16 @@ float AMasterAI::TakeDamage(float Damage, FDamageEvent const& DamageEvent, ACont if (DamageEvent.IsOfType(FPointDamageEvent::ClassID)) { const FPointDamageEvent* PointDamageEvent = static_cast(&DamageEvent); - + APawn* Attacker = EventInstigator->GetPawn(); + //스텟 관련 처리 StatsComponent->TakeDamageOnStat(Damage); + //데미지 관련 AI 처리 + UAISense_Damage::ReportDamageEvent(GetWorld(), this, Attacker, Damage, PointDamageEvent->HitInfo.Location, PointDamageEvent->HitInfo.Location); + //앞에서 맞았는지 뒤에서 맞았는지 판별 - bHitFront = UKismetMathLibrary::InRange_FloatFloat(this->GetDotProductTo(EventInstigator->GetPawn()), -0.1f, 1.f); + bHitFront = UKismetMathLibrary::InRange_FloatFloat(this->GetDotProductTo(Attacker), -0.1f, 1.f); LastHitInfo = PointDamageEvent->HitInfo; //play sound, effect diff --git a/Source/D1/CombatCharacter.cpp b/Source/D1/CombatCharacter.cpp index ce709372..48e4b1e8 100644 --- a/Source/D1/CombatCharacter.cpp +++ b/Source/D1/CombatCharacter.cpp @@ -92,8 +92,12 @@ ACombatCharacter::ACombatCharacter() JoggingSpeed = 500.f; SprintSpeed = 700.f; + //Settings OwnedGameplayTags + OwnedGameplayTags.AddTag(FCombatGameplayTags::Get().Character_Player); + ChargeAttackTime = 0.18f; PelvisBoneName = TEXT("pelvis"); + } void ACombatCharacter::BeginPlay() diff --git a/Source/D1/CombatCharacter.h b/Source/D1/CombatCharacter.h index 072d969c..4a921388 100644 --- a/Source/D1/CombatCharacter.h +++ b/Source/D1/CombatCharacter.h @@ -3,6 +3,7 @@ #pragma once #include "CoreMinimal.h" +#include "GameplayTagAssetInterface.h" #include "GameFramework/Character.h" #include "InputActionValue.h" #include "InputAction.h" @@ -11,11 +12,12 @@ #include "Components/StatsComponent.h" #include "Components/TargetingComponent.h" #include "Definitions/GameEnums.h" +#include "Interface/CombatGameplayTag.h" #include "CombatCharacter.generated.h" UCLASS(config=Game) -class ACombatCharacter : public ACharacter, public ICombatInterface +class ACombatCharacter : public ACharacter, public ICombatInterface, public IGameplayTagAssetInterface { GENERATED_BODY() @@ -108,7 +110,9 @@ public: virtual void SetCanMove_Implementation(bool inputCanMove) override; virtual EMovementSpeedMode GetCombatMovementSpeedMode() override { return GetMovementSpeedMode(); } - + + // Inherited via IGameplayTagAssetInterface + virtual void GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const override { TagContainer = OwnedGameplayTags; } public: void SetMovementSpeedMode(EMovementSpeedMode NewSpeedMode); FORCEINLINE EMovementSpeedMode GetMovementSpeedMode() const { return MovementSpeedMode; } @@ -206,12 +210,13 @@ public: private: FTimerHandle StaminaTimerHandle; - + private: bool IsHeavyAttack; float AttackHeldTime; bool bAttackCharged; bool bCanMove = true; bool bHitFront; - FHitResult LastHitInfo; + FHitResult LastHitInfo; + FGameplayTagContainer OwnedGameplayTags; }; diff --git a/Source/D1/Definitions/CombatGameplayTags.cpp b/Source/D1/Definitions/CombatGameplayTags.cpp index 2c9938c5..c170d0cc 100644 --- a/Source/D1/Definitions/CombatGameplayTags.cpp +++ b/Source/D1/Definitions/CombatGameplayTags.cpp @@ -8,8 +8,16 @@ FCombatGameplayTags FCombatGameplayTags::GameplayTags; void FCombatGameplayTags::InitializeNativeGameplayTags() { - if(GameplayTags.Character_State_Attacking.IsValid()) //Already Execute? then Do not Execute + if(GameplayTags.Character_Player.IsValid()) //Already Execute? then Do not Execute return; + + /** + * Player + */ + GameplayTags.Character_Player = UGameplayTagsManager::Get().AddNativeGameplayTag( + FName("Character.Player"), + FString("Player") + ); /** * State diff --git a/Source/D1/Definitions/CombatGameplayTags.h b/Source/D1/Definitions/CombatGameplayTags.h index a2fe3941..f898203e 100644 --- a/Source/D1/Definitions/CombatGameplayTags.h +++ b/Source/D1/Definitions/CombatGameplayTags.h @@ -12,6 +12,9 @@ public: static void InitializeNativeGameplayTags(); public: + //Character + FGameplayTag Character_Player; + //State FGameplayTag Character_State_Attacking; FGameplayTag Character_State_Dead; diff --git a/Source/D1/Interface/CombatGameplayTag.cpp b/Source/D1/Interface/CombatGameplayTag.cpp new file mode 100644 index 00000000..29c2e6e3 --- /dev/null +++ b/Source/D1/Interface/CombatGameplayTag.cpp @@ -0,0 +1,6 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Interface/CombatGameplayTag.h" + +// Add default functionality here for any ICombatGameplayTag functions that are not pure virtual. diff --git a/Source/D1/Interface/CombatGameplayTag.h b/Source/D1/Interface/CombatGameplayTag.h new file mode 100644 index 00000000..cc60f8d5 --- /dev/null +++ b/Source/D1/Interface/CombatGameplayTag.h @@ -0,0 +1,27 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "GameplayTagContainer.h" +#include "UObject/Interface.h" +#include "CombatGameplayTag.generated.h" + +// This class does not need to be modified. +UINTERFACE(MinimalAPI) +class UCombatGameplayTag : public UInterface +{ + GENERATED_BODY() +}; + +/** + * + */ +class D1_API ICombatGameplayTag +{ + GENERATED_BODY() + + // Add interface functions to this class. This is the class that will be inherited to implement this interface. +public: + virtual FGameplayTagContainer GetOwnedGameplayTag() = 0; +};