VamPower
Platform
Engine
Language
Development Time
Team Size
PC
Unreal Engine
C++
4 Weeks
8
Your master, an imposing and sinister vampire overlord, has been vanquished in battle, yet he clings to life in his dark lair.
Armed with an array of formidable weapons, it is your duty to stand firm and protect your master’s heart from a relentless onslaught of bold heroes and desperate peasants.
These relentless attackers are determined to ensure his demise once and for all!
If you succeed in keeping your master alive amidst the chaos, he may reward your loyalty with a gift of unimaginable value—one truly worth "dying" for!
My Role
I was a AI & Gameplay Programmer.
My main responsibilities were:
-
AI
-
Behavior Trees
-
Behavior Tree Tasks

AI Base Classes & Inheritance
All of the AIs and the player were organized under different base classes to make it

Behavior Tasks
Different AI behavior tree tasks that perform the AI actions in their behavior tree. From dashing away from the player, healing itself when hurt or attacking the player.

Chase Player
AI movement system that move the ai towards a location and activates walking animation if not active.
UBTTask_ChasePlayer.cpp
#include "BTTask_ChasePlayer.h"
#include "NPC_AIController.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "Blueprint/AIBlueprintHelperLibrary.h"
UBTTask_ChasePlayer::UBTTask_ChasePlayer(FObjectInitializer const& ObjectInitializer)
{
NodeName = TEXT("Chase Target");
}
EBTNodeResult::Type UBTTask_ChasePlayer::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
//Get Character Controller
if (auto* const AIController = Cast<ANPC_AIController>(OwnerComp.GetAIOwner()))
{
auto* const AICharacter = Cast<ABaseAI>(AIController->GetPawn());
if (AICharacter->isWalking == false)
{
AICharacter->AnimationWalkNotifer();
AICharacter->isWalking = true;
}
//Get Target Location from blackboard
auto const TargetLocation = OwnerComp.GetBlackboardComponent()->GetValueAsVector(GetSelectedBlackboardKey());
//Move to Target location
UAIBlueprintHelperLibrary::SimpleMoveToLocation(AIController, TargetLocation);
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Succeeded;
}
return EBTNodeResult::Failed;
}
UBTTask_ChasePlayer.cpp.h
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/Tasks/BTTask_BlackboardBase.h"
#include "BTTask_ChasePlayer.generated.h"
/**
*
*/
UCLASS()
class GP4_GIT_API UBTTask_ChasePlayer : public UBTTask_BlackboardBase
{
GENERATED_BODY()
public:
explicit UBTTask_ChasePlayer(FObjectInitializer const& ObjectInitializer);
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
};
Dash
Propel the character towards or away from another character in a flexible strength
UBTTask_Dash.cpp
#include "BTTask_Dash.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "NPC_AIController.h"
#include "GameFramework/MovementComponent.h"
#include "GameFramework/PawnMovementComponent.h"
#include "BaseAI.h"
UBTTask_Dash::UBTTask_Dash(FObjectInitializer const& ObjectInitializer)
{
NodeName = TEXT("Dash");
}
EBTNodeResult::Type UBTTask_Dash::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
UObject* UTarget = OwnerComp.GetBlackboardComponent()->GetValueAsObject("TargetActor");
if (auto* const ATarget = UTarget)
{
AActor* TargetActor = Cast<AActor>(ATarget);
auto const* const AI = Cast<ANPC_AIController>(OwnerComp.GetAIOwner());
auto* const AIBase = Cast<ABaseAI>(AI->GetPawn());
UPawnMovementComponent* MovementComponent = AI->GetPawn()->GetMovementComponent();
FVector Direction = TargetActor->GetActorLocation() - AI->GetPawn()->GetActorLocation();
Direction.Z = 0;
float BackOrForward;
AIBase->AnimationDashNotifer();
if (DashForward)
{
BackOrForward = 1;
}
else if (!DashForward)
{
BackOrForward = -1;
}
FVector ForceDircetion;
ForceDircetion.X = Direction.X * DashForce * BackOrForward;
ForceDircetion.Y = Direction.Y * DashForce * BackOrForward;
MovementComponent->Velocity = ForceDircetion;
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Type();
}
FinishLatentTask(OwnerComp, EBTNodeResult::Failed);
return EBTNodeResult::Type();
}
UBTTask_Dash.h
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/Tasks/BTTask_BlackboardBase.h"
#include "BTTask_Dash.generated.h"
/**
*
*/
UCLASS()
class GP4_GIT_API UBTTask_Dash : public UBTTask_BlackboardBase
{
GENERATED_BODY()
public:
explicit UBTTask_Dash(FObjectInitializer const& ObjectInitializer);
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
float DashForce = 10;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
bool DashForward;
};
Find Heart Location
Get a vector location in the navigation system in the radius of a specific StaticClass.
UBTTask_FindHeartLocation.cpp
#include "BTTask_FindHeartLocation.h"
#include "NavigationSystem.h"
#include "NPC_AIController.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "Heart.h"
#include "Kismet/GameplayStatics.h"
UBTTask_FindHeartLocation::UBTTask_FindHeartLocation(FObjectInitializer const& ObjectInitializer)
{
NodeName = "Get Location of Heart";
}
EBTNodeResult::Type UBTTask_FindHeartLocation::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
if (auto* const Heart = UGameplayStatics::GetActorOfClass(GetWorld(), AHeart::StaticClass()))
{
auto const HeartLocation = Heart->GetActorLocation();
if (SearchRadius)
{
FNavLocation NavMeshLocation;
//Generate random location near the player from the navigation system
if (auto* const NavigationSystem = UNavigationSystemV1::GetCurrent(GetWorld()))
{
//Get the random location near player
if (NavigationSystem->GetRandomPointInNavigableRadius(HeartLocation, SearchRadius, NavMeshLocation))
{
OwnerComp.GetBlackboardComponent()->SetValueAsVector(GetSelectedBlackboardKey(),
NavMeshLocation.Location);
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Succeeded;
}
}
}
else
{
OwnerComp.GetBlackboardComponent()->SetValueAsVector(GetSelectedBlackboardKey(), HeartLocation);
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Succeeded;
}
}
return EBTNodeResult::Failed;
}
UBTTask_FindHeartLocation.h
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/Tasks/BTTask_BlackboardBase.h"
#include "BTTask_FindHeartLocation.generated.h"
/**
*
*/
UCLASS()
class GP4_GIT_API UBTTask_FindHeartLocation : public UBTTask_BlackboardBase
{
GENERATED_BODY()
public:
explicit UBTTask_FindHeartLocation(FObjectInitializer const& ObjectInitializer);
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
float SearchRadius = 150.f;
};
Find Player Location
Get a vector location in the navigation system in the radius of the player.
UBTTask_FindPlayerLocation.cpp
#include "BTTask_FindPlayerLocation.h"
#include "NavigationSystem.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "GameFramework/Character.h"
#include "Kismet/GameplayStatics.h"
UBTTask_FindPlayerLocation::UBTTask_FindPlayerLocation(FObjectInitializer const& ObjectInitializer)
{
NodeName = TEXT("Find Player Location");
}
EBTNodeResult::Type UBTTask_FindPlayerLocation::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
//Get player
if (auto* const Player = UGameplayStatics::GetPlayerCharacter(GetWorld(), 0))
{
auto const PlayerLocation = Player->GetActorLocation();
if (SearchRadius)
{
FNavLocation NavMeshLocation;
//Generate random location near the player from the navigation system
if (auto* const NavigationsSystem = UNavigationSystemV1::GetCurrent(GetWorld()))
{
//Get the random location near player
if (NavigationsSystem->GetRandomPointInNavigableRadius(PlayerLocation, SearchRadius, NavMeshLocation))
{
OwnerComp.GetBlackboardComponent()->SetValueAsVector(GetSelectedBlackboardKey(),
NavMeshLocation.Location);
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Succeeded;
}
}
}
else
{
OwnerComp.GetBlackboardComponent()->SetValueAsVector(GetSelectedBlackboardKey(), PlayerLocation);
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Succeeded;
}
}
return EBTNodeResult::Failed;
}
UBTTask_FindPlayerLocation.h
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/Tasks/BTTask_BlackboardBase.h"
#include "BTTask_FindPlayerLocation.generated.h"
/**
*
*/
UCLASS()
class GP4_GIT_API UBTTask_FindPlayerLocation : public UBTTask_BlackboardBase
{
GENERATED_BODY()
public:
explicit UBTTask_FindPlayerLocation(FObjectInitializer const& ObjectInitializer);
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool SearchRandom = false;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float SearchRadius = 150.f;
};
Find Target Location
Get a vector location in the navigation system in the radius of a Blackboard UObject
UBTTask_FindTargetLocation.cpp
#include "BTTask_FindTargetLocation.h"
#include "NavigationSystem.h"
#include "BehaviorTree/BlackboardComponent.h"
UBTTask_FindTargetLocation::UBTTask_FindTargetLocation(FObjectInitializer const& ObjectInitializer)
{
NodeName = TEXT("Find Target Location");
}
EBTNodeResult::Type UBTTask_FindTargetLocation::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
UObject* UTarget = OwnerComp.GetBlackboardComponent()->GetValueAsObject("TargetActor");
if (auto* const ATarget = UTarget)
{
AActor* TargetActor = Cast<AActor>(ATarget);
auto const TargetActorLocation = TargetActor->GetActorLocation();
if (SearchRadius)
{
FNavLocation NavMeshLocation;
//Generate random location near the player from the navigation system
if (auto* const NavigationSystem = UNavigationSystemV1::GetCurrent(GetWorld()))
{
//Get the random location near player
if (NavigationSystem->GetRandomPointInNavigableRadius(TargetActorLocation, SearchRadius, NavMeshLocation))
{
OwnerComp.GetBlackboardComponent()->SetValueAsVector(GetSelectedBlackboardKey(),
NavMeshLocation.Location);
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Succeeded;
}
}
}
else
{
OwnerComp.GetBlackboardComponent()->SetValueAsVector(GetSelectedBlackboardKey(), TargetActorLocation);
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Succeeded;
}
}
return EBTNodeResult::Failed;
}
UBTTask_FindTargetLocation.h
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/Tasks/BTTask_BlackboardBase.h"
#include "BTTask_FindTargetLocation.generated.h"
/**
*
*/
UCLASS()
class GP4_GIT_API UBTTask_FindTargetLocation : public UBTTask_BlackboardBase
{
GENERATED_BODY()
public:
explicit UBTTask_FindTargetLocation(FObjectInitializer const& ObjectInitializer);
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float SearchRadius = 150.f;
};
Get Starting Location
Get a vector location of the Character starting position.
UBTTask_GetStartingLocation.cpp
#include "BTTask_GetStartingLocation.h"
#include "AIController.h"
#include "BaseCharacter.h"
#include "Runtime/Engine/Classes/Engine/World.h"
#include "Engine/LatentActionManager.h"
#include "BehaviorTree/BlackboardComponent.h"
UBTTask_GetStartingLocation::UBTTask_GetStartingLocation(FObjectInitializer const& ObjectInitializer)
{
NodeName = TEXT("Get Starting Location");
}
EBTNodeResult::Type UBTTask_GetStartingLocation::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
auto const* const AI = OwnerComp.GetAIOwner();
auto* const AICharacter = Cast<ABaseCharacter>(AI->GetPawn());
FVector CharacterStartingLocation = AICharacter->StartingLocation;
OwnerComp.GetBlackboardComponent()->SetValueAsVector(GetSelectedBlackboardKey(), CharacterStartingLocation);
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Succeeded;
}
UBTTask_GetStartingLocation.h
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/Tasks/BTTask_BlackboardBase.h"
#include "BTTask_GetStartingLocation.generated.h"
/**
*
*/
UCLASS()
class GP4_GIT_API UBTTask_GetStartingLocation : public UBTTask_BlackboardBase
{
GENERATED_BODY()
public:
explicit UBTTask_GetStartingLocation(FObjectInitializer const& ObjectInitializer);
virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
};
Heal
Heal the Character by the Characters healing amount.
UBTTask_Heal.cpp
#include "BTTask_Heal.h"
#include "AIController.h"
#include "Runtime/Engine/Classes/Engine/World.h"
#include "Engine/LatentActionManager.h"
#include "BehaviorTree/BlackboardComponent.h"
UBTTask_Heal::UBTTask_Heal()
{
NodeName = TEXT("Heal Own Character");
}
EBTNodeResult::Type UBTTask_Heal::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
auto const* const AI = OwnerComp.GetAIOwner();
auto* const AIEnemy= Cast<ABaseEnemy>(AI->GetPawn());
AIEnemy->HealthComponent->HealCharacter(AIEnemy->HealthComponent->HealAmount);
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Type();
}
UBTTask_Heal.h
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/Tasks/BTTask_BlackboardBase.h"
#include "BTTask_Heal.generated.h"
/**
*
*/
UCLASS()
class GP4_GIT_API UBTTask_Heal : public UBTTask_BlackboardBase
{
GENERATED_BODY()
public:
UBTTask_Heal();
EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
};
Melee Attack
Attacking the character dealing damage depending on own character with a cooldown.
UBTTask_MeleeAttack.cpp
#include "BTTask_MeleeAttack.h"
#include "AIController.h"
#include "BaseAI.h"
#include "Runtime/Engine/Classes/Engine/World.h"
#include "Engine/LatentActionManager.h"
#include "BehaviorTree/BlackboardComponent.h"
UBTTask_MeleeAttack::UBTTask_MeleeAttack()
{
NodeName = TEXT("Melee Attack");
}
EBTNodeResult::Type UBTTask_MeleeAttack::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
auto const OutOfRange = !OwnerComp.GetBlackboardComponent()->GetValueAsBool(GetSelectedBlackboardKey());
if (OutOfRange)
{
//If not in range then finnish attack without damaging
bWindup = true;
bMeleeCooldown = false;
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Succeeded;
}
//If we are in range then get the ai character
auto const* const AI = OwnerComp.GetAIOwner();
auto* const AICharacter = Cast<ABaseAI>(AI->GetPawn());
if (bMeleeCooldown)
{
AICharacter->StartMeleeAttack(AICharacter->MeleeCooldown);
bMeleeCooldown = false;
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Succeeded;
}
if (AICharacter->isPossibleToMeleeAttack == true && bWindup)
{
AICharacter->isPossibleToMeleeAttack = false;
bWindup = false;
AICharacter->AnimationMeleeAttackWindupNotifer();
AICharacter->StartMeleeAttack(AICharacter->MeleeDelay);
AICharacter->isWalking = false;
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Succeeded;
}
UObject* UTarget = OwnerComp.GetBlackboardComponent()->GetValueAsObject("TargetActor");
auto* const ATarget = UTarget;
if (ATarget)
{
AActor* TargetActor = AICharacter->ParentTarget;
ABaseCharacter* TargetBaseCharacter = Cast<ABaseCharacter>(TargetActor);
if (TargetBaseCharacter && AICharacter->isPossibleToMeleeAttack && OutOfRange == false)
{
bMeleeCooldown = AICharacter->isPossibleToMeleeAttack;
bWindup = AICharacter->isPossibleToMeleeAttack;
AICharacter->isPossibleToMeleeAttack = false;
TargetBaseCharacter->HealthComponent->TakeDamage(AICharacter->FinalAttackDamage);
AICharacter->AnimationMeleeAttackNotifer();
AICharacter->isWalking = false;
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Type();
}
}
FinishLatentTask(OwnerComp, EBTNodeResult::Failed);
return EBTNodeResult::Type();
}
UBTTask_MeleeAttack.h
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/Tasks/BTTask_BlackboardBase.h"
#include "BTTask_MeleeAttack.generated.h"
/**
*
*/
UCLASS()
class GP4_GIT_API UBTTask_MeleeAttack : public UBTTask_BlackboardBase
{
GENERATED_BODY()
public:
UBTTask_MeleeAttack();
EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
private:
UPROPERTY(EditDefaultsOnly)
bool bWindup = true;
UPROPERTY(EditDefaultsOnly)
bool bMeleeCooldown = false;
};
Range Attack
Create a projectile at predetermined location on the character blueprint.
UBTTask_RangeAttack.cpp
#include "BTTask_RangeAttack.h"
#include "AIController.h"
#include "Runtime/Engine/Classes/Engine/World.h"
#include "Engine/LatentActionManager.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "Projectile.h"
#include "BaseCharacter.h"
#include "BaseAI.h"
UBTTask_RangeAttack::UBTTask_RangeAttack()
{
NodeName = TEXT("Range Attack");
}
EBTNodeResult::Type UBTTask_RangeAttack::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
auto const OutOfRange = !OwnerComp.GetBlackboardComponent()->GetValueAsBool(GetSelectedBlackboardKey());
if (OutOfRange)
{
//If not in range then finnish attack without damaging
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Type();
}
//If we are in range then get the ai character
auto const* const AI = OwnerComp.GetAIOwner();
auto* const AIBase = Cast<ABaseAI>(AI->GetPawn());
AIBase->AnimationRangeAttackNotifer();
AProjectile* projectile;
FActorSpawnParameters parameters;
parameters.Owner = AI->GetPawn();
projectile = GetWorld()->SpawnActor<AProjectile>(
AIBase->ProjectileSubClass,
AIBase->ProjectileSpawnPosition->GetComponentLocation(),
AIBase->ProjectileSpawnPosition->GetComponentRotation(),
parameters
);
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Type();
}
UBTTask_RangeAttack.h
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/Tasks/BTTask_BlackboardBase.h"
#include "BTTask_RangeAttack.generated.h"
class AProjectile;
/**
*
*/
UCLASS()
class GP4_GIT_API UBTTask_RangeAttack : public UBTTask_BlackboardBase
{
GENERATED_BODY()
public:
UBTTask_RangeAttack();
EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
};
Range Attack
Create projectiles in an arch around a predetermined location on the character blueprint.
UBTTask_MultiRangeAttack.cpp
#include "BTTask_MultiRangeAttack.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "AIController.h"
#include "ProjectileAOE.h"
#include "BaseCharacter.h"
#include "BaseAI.h"
UBTTask_MultiRangeAttack::UBTTask_MultiRangeAttack()
{
NodeName = TEXT("Multi Range Attack");
}
EBTNodeResult::Type UBTTask_MultiRangeAttack::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
auto const OutOfRange = !OwnerComp.GetBlackboardComponent()->GetValueAsBool(GetSelectedBlackboardKey());
if (OutOfRange)
{
//If not in range then finnish attack without damaging
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Succeeded;
}
//If we are in range then get the ai character
auto const* const AI = OwnerComp.GetAIOwner();
AProjectileAOE* projectile;
auto* const AIBaseCharacter = Cast<ABaseCharacter>(AI->GetPawn());
auto* const AIBase = Cast<ABaseAI>(AI->GetPawn());
AIBase->AnimationRangeAttackNotifer();
FActorSpawnParameters parameters;
parameters.Owner = AI->GetPawn();
for (auto i = 0; i < NrOfProjectiles; i++)
{
FRotator Rotation = AIBaseCharacter->ProjectileSpawnPosition->GetComponentRotation();
int32 RoationIncrease = 5 * i;
int32 RoationDecrease = 5 * NrOfProjectiles / 2;
int32 Roation = Rotation.Yaw + RoationIncrease - RoationDecrease;
Rotation.Yaw = Roation;
projectile = GetWorld()->SpawnActor<AProjectileAOE>(
AIBaseCharacter->AOEProjectileSubClass,
AIBaseCharacter->ProjectileSpawnPosition->GetComponentLocation(),
Rotation,
parameters
);
}
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
return EBTNodeResult::Type();
}
UBTTask_MultiRangeAttack.h
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/Tasks/BTTask_BlackboardBase.h"
#include "BTTask_MultiRangeAttack.generated.h"
/**
*
*/
UCLASS()
class GP4_GIT_API UBTTask_MultiRangeAttack : public UBTTask_BlackboardBase
{
GENERATED_BODY()
public:
UBTTask_MultiRangeAttack();
EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
int32 NrOfProjectiles = 5;
};
Behavior Trees
All the AIs incorporate a behavior tree that outlines a sequence of tasks and conditions.

Range Ally
Range Ally

Melee Ally

Melee Enemy

Range Enemy

Boss

Miscellaneous (Blueprints)
Blueprint that calculates an arc towards the ai:s target to launch a projectile towards.

Blueprint
Projectile Launching
