diff --git a/Config/DefaultInput.ini b/Config/DefaultInput.ini index 8838ce3e..463466fe 100644 --- a/Config/DefaultInput.ini +++ b/Config/DefaultInput.ini @@ -86,11 +86,11 @@ DoubleClickTime=0.200000 +ActionMappings=(ActionName="Aiming",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=RightMouseButton) +ActionMappings=(ActionName="Aiming",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Gamepad_LeftTrigger) +ActionMappings=(ActionName="Select",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=E) -+ActionMappings=(ActionName="Select",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Gamepad_FaceButton_Right) ++ActionMappings=(ActionName="Select",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Gamepad_FaceButton_Top) +ActionMappings=(ActionName="Reload",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=R) +ActionMappings=(ActionName="Reload",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Gamepad_FaceButton_Left) +ActionMappings=(ActionName="Crouch",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=C) -+ActionMappings=(ActionName="Crouch",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Gamepad_RightThumbstick) ++ActionMappings=(ActionName="Crouch",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Gamepad_FaceButton_Right) +ActionMappings=(ActionName="FKey",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=F) +ActionMappings=(ActionName="1Key",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=One) +ActionMappings=(ActionName="2Key",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Two) @@ -114,5 +114,6 @@ DoubleClickTime=0.200000 DefaultPlayerInputClass=/Script/EnhancedInput.EnhancedPlayerInput DefaultInputComponentClass=/Script/EnhancedInput.EnhancedInputComponent DefaultTouchInterface=/Engine/MobileResources/HUD/DefaultVirtualJoysticks.DefaultVirtualJoysticks -+ConsoleKeys=Tilde +-ConsoleKeys=Tilde ++ConsoleKeys=` diff --git a/Content/_Game/Enemies/EnemyBP.uasset b/Content/_Game/Enemies/EnemyBP.uasset index 4f99e436..2f02113f 100644 --- a/Content/_Game/Enemies/EnemyBP.uasset +++ b/Content/_Game/Enemies/EnemyBP.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:835362e0ba630357ca82cb33a972ce20db252ee0519f135fc4a1849a84106d0e -size 133539 +oid sha256:60207243d023df1dcd3ef62c14c9f00d3dd4bbaeb02a353a4b93c57e855cbf99 +size 132630 diff --git a/Content/_Game/EnemyController/EnemyBehaviorTree.uasset b/Content/_Game/EnemyController/EnemyBehaviorTree.uasset new file mode 100644 index 00000000..beffe377 --- /dev/null +++ b/Content/_Game/EnemyController/EnemyBehaviorTree.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6c553be7d4751b78d3e0c54182f38c772dec797f553a1ed7f225ab6ebbd16a54 +size 5928 diff --git a/Content/_Game/EnemyController/EnemyBlackboard.uasset b/Content/_Game/EnemyController/EnemyBlackboard.uasset new file mode 100644 index 00000000..ddd31980 --- /dev/null +++ b/Content/_Game/EnemyController/EnemyBlackboard.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b69ffc0f53462966801e5013c80d64f97474cb04aca873051f7390007194053f +size 2603 diff --git a/Content/_Game/EnemyController/EnemyControllerBP.uasset b/Content/_Game/EnemyController/EnemyControllerBP.uasset new file mode 100644 index 00000000..ef102fae --- /dev/null +++ b/Content/_Game/EnemyController/EnemyControllerBP.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:011e0022d5cae8acf1de4bfe729777c821e9ae7e905e018ec3de94c49f60c84d +size 19672 diff --git a/Content/_Game/Maps/DefaultMap.umap b/Content/_Game/Maps/DefaultMap.umap index ad3cfec2..b8d2af8c 100644 --- a/Content/_Game/Maps/DefaultMap.umap +++ b/Content/_Game/Maps/DefaultMap.umap @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:11d94cd5a091fe823d2f70fdc4a479bfdb5abcefee0ff56e81652c66b9aa702e -size 238914 +oid sha256:72c1d191dfd0235b9a2609b05238abd55452ebedc0181c4cfc9b9bc54dae5bc7 +size 3650510 diff --git a/Shooter.uproject b/Shooter.uproject index 2fbe866d..d6640821 100644 --- a/Shooter.uproject +++ b/Shooter.uproject @@ -9,7 +9,8 @@ "Type": "Runtime", "LoadingPhase": "Default", "AdditionalDependencies": [ - "Engine" + "Engine", + "AIModule" ] } ], diff --git a/Source/Shooter/Enemy.cpp b/Source/Shooter/Enemy.cpp index 9444119c..f6445fe1 100644 --- a/Source/Shooter/Enemy.cpp +++ b/Source/Shooter/Enemy.cpp @@ -7,6 +7,10 @@ #include "Kismet/GameplayStatics.h" #include "Sound/SoundCue.h" #include "Particles/ParticleSystemComponent.h" +#include "Kismet/KismetMathLibrary.h" +#include "DrawDebugHelpers.h" +#include "EnemyController.h" +#include "BehaviorTree/BlackboardComponent.h" // Sets default values AEnemy::AEnemy() : @@ -28,6 +32,19 @@ void AEnemy::BeginPlay() Super::BeginPlay(); GetMesh()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Visibility, ECollisionResponse::ECR_Block); + + // Get the AI Controller + EnemyController = Cast(GetController()); + + const FVector WorldPatrolPoint = UKismetMathLibrary::TransformLocation(GetActorTransform(), PatrolPoint); + DrawDebugSphere(GetWorld(), WorldPatrolPoint, 25.f, 12, FColor::Red, true); + + if (EnemyController) + { + EnemyController->GetBlackboardComponent()->SetValueAsVector("PatrolPoint", WorldPatrolPoint); + EnemyController->RunBehaviorTree(BehaviorTree); + } + } void AEnemy::ShowHealthBar_Implementation() diff --git a/Source/Shooter/Enemy.h b/Source/Shooter/Enemy.h index f32b95e2..56b04a1d 100644 --- a/Source/Shooter/Enemy.h +++ b/Source/Shooter/Enemy.h @@ -10,6 +10,8 @@ class UParticleSystem; class USoundCue; class UAnimMontage; +class UBehaviorTree; +class AEnemyController; UCLASS() class SHOOTER_API AEnemy : public ACharacter, public IBulletHitInterface @@ -91,6 +93,16 @@ private: /** Time before a hit number is removed from the screen */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Combat, meta = (AllowPrivateAccess = true)) float HitNumberDestroyTime; + + /** Behavior tree for the AI Character */ + UPROPERTY(EditAnywhere, Category = "Behavior Tree", meta = (AllowPrivateAccess = true)) + UBehaviorTree* BehaviorTree; + + /** Point for the enemy to move to */ + UPROPERTY(EditAnywhere, Category = "Behavior Tree", meta = (AllowPrivateAccess = true, MakeEditWidget = true)) + FVector PatrolPoint; + + AEnemyController* EnemyController; public: // Called every frame virtual void Tick(float DeltaTime) override; @@ -106,4 +118,6 @@ public: UFUNCTION(BlueprintImplementableEvent) void ShowHitNumber(int32 Damage, FVector HitLocation, bool bHeadshot); + + FORCEINLINE UBehaviorTree* GetBehaviorTree() const { return BehaviorTree; } }; diff --git a/Source/Shooter/EnemyController.cpp b/Source/Shooter/EnemyController.cpp new file mode 100644 index 00000000..e8eeaa43 --- /dev/null +++ b/Source/Shooter/EnemyController.cpp @@ -0,0 +1,33 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "EnemyController.h" + +#include "Enemy.h" +#include "BehaviorTree/BehaviorTree.h" +#include "BehaviorTree/BehaviorTreeComponent.h" +#include "BehaviorTree/BlackboardComponent.h" + +AEnemyController::AEnemyController() +{ + BlackboardComponent = CreateDefaultSubobject(TEXT("BlackboardComponent")); + check(BlackboardComponent); + + BehaviorTreeComponent = CreateDefaultSubobject(TEXT("BehaviorTreeComponent")); + check(BehaviorTreeComponent); +} + +void AEnemyController::OnPossess(APawn* InPawn) +{ + Super::OnPossess(InPawn); + + if (!InPawn) return; + + if (AEnemy* Enemy = Cast(InPawn)) + { + if (Enemy->GetBehaviorTree()) + { + BlackboardComponent->InitializeBlackboard(*(Enemy->GetBehaviorTree()->BlackboardAsset)); + } + } +} diff --git a/Source/Shooter/EnemyController.h b/Source/Shooter/EnemyController.h new file mode 100644 index 00000000..b11ac5fd --- /dev/null +++ b/Source/Shooter/EnemyController.h @@ -0,0 +1,34 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "AIController.h" +#include "EnemyController.generated.h" + +class UBlackboardComponent; +class UBehaviorTreeComponent; + +/** + * + */ +UCLASS() +class SHOOTER_API AEnemyController : public AAIController +{ + GENERATED_BODY() +public: + AEnemyController(); + virtual void OnPossess(APawn* InPawn) override; + +private: + /** Blackboard component for this enemy */ + UPROPERTY(BlueprintReadWrite, Category = "AI Behavior", meta = (AllowPrivateAccess = true)) + UBlackboardComponent* BlackboardComponent; + + /** BehaviorTree component for this enemy */ + UPROPERTY(BlueprintReadWrite, Category = "AI Behavior", meta = (AllowPrivateAccess = true)) + UBehaviorTreeComponent* BehaviorTreeComponent; + +public: + FORCEINLINE UBlackboardComponent* GetBlackboardComponent() const { return BlackboardComponent; } +}; diff --git a/Source/Shooter/Shooter.Build.cs b/Source/Shooter/Shooter.Build.cs index 85dec8c2..6adb35d1 100644 --- a/Source/Shooter/Shooter.Build.cs +++ b/Source/Shooter/Shooter.Build.cs @@ -8,7 +8,7 @@ public class Shooter : ModuleRules { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; - PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UMG", "PhysicsCore" }); + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UMG", "PhysicsCore", "NavigationSystem", "AIModule" }); PrivateDependencyModuleNames.AddRange(new string[] { });