Add enemies

This commit is contained in:
Sara Montecino 2022-11-11 16:44:16 -08:00
parent 99214f6a05
commit 1a864c9a73
20 changed files with 360 additions and 58 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/EnemyMaterial.uasset Executable file

Binary file not shown.

BIN
Content/EnemySpawner_BP.uasset Executable file

Binary file not shown.

Binary file not shown.

BIN
Content/PresidentPawn.uasset Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -7,9 +7,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine", "Engine", "{94A6C6
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Games", "Games", "{8E2F6A87-1826-34F4-940C-CC23A48F9FE4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PresidentsBrigade", "Intermediate\ProjectFiles\PresidentsBrigade.vcxproj", "{2FAC355B-B731-475C-8E0B-842BE82A5759}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PresidentsBrigade", "Intermediate\ProjectFiles\PresidentsBrigade.vcxproj", "{97946AF8-2BBD-45DF-B560-04E9007DCB1A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UE4", "Intermediate\ProjectFiles\UE4.vcxproj", "{74354AC2-E071-4234-87C9-5842B773C170}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UE4", "Intermediate\ProjectFiles\UE4.vcxproj", "{7B9D3087-59A5-43EF-B77B-4DBA855467B6}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Visualizers", "Visualizers", "{1CCEC849-CC72-4C59-8C36-2F7C38706D4C}"
ProjectSection(SolutionItems) = preProject
@ -35,53 +35,53 @@ Global
Shipping|Win64 = Shipping|Win64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2FAC355B-B731-475C-8E0B-842BE82A5759}.DebugGame Editor|Android.ActiveCfg = Invalid|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.DebugGame Editor|Win32.ActiveCfg = Invalid|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.DebugGame Editor|Win64.ActiveCfg = DebugGame_Editor|x64
{2FAC355B-B731-475C-8E0B-842BE82A5759}.DebugGame Editor|Win64.Build.0 = DebugGame_Editor|x64
{2FAC355B-B731-475C-8E0B-842BE82A5759}.DebugGame|Android.ActiveCfg = Android_DebugGame|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.DebugGame|Android.Build.0 = Android_DebugGame|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.DebugGame|Win32.ActiveCfg = DebugGame|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.DebugGame|Win32.Build.0 = DebugGame|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.DebugGame|Win64.ActiveCfg = DebugGame|x64
{2FAC355B-B731-475C-8E0B-842BE82A5759}.DebugGame|Win64.Build.0 = DebugGame|x64
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Development Editor|Android.ActiveCfg = Invalid|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Development Editor|Win32.ActiveCfg = Invalid|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Development Editor|Win64.ActiveCfg = Development_Editor|x64
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Development Editor|Win64.Build.0 = Development_Editor|x64
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Development|Android.ActiveCfg = Android_Development|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Development|Android.Build.0 = Android_Development|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Development|Win32.ActiveCfg = Development|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Development|Win32.Build.0 = Development|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Development|Win64.ActiveCfg = Development|x64
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Development|Win64.Build.0 = Development|x64
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Shipping|Android.ActiveCfg = Android_Shipping|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Shipping|Android.Build.0 = Android_Shipping|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Shipping|Win32.ActiveCfg = Shipping|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Shipping|Win32.Build.0 = Shipping|Win32
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Shipping|Win64.ActiveCfg = Shipping|x64
{2FAC355B-B731-475C-8E0B-842BE82A5759}.Shipping|Win64.Build.0 = Shipping|x64
{74354AC2-E071-4234-87C9-5842B773C170}.DebugGame Editor|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{74354AC2-E071-4234-87C9-5842B773C170}.DebugGame Editor|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{74354AC2-E071-4234-87C9-5842B773C170}.DebugGame Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{74354AC2-E071-4234-87C9-5842B773C170}.DebugGame|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{74354AC2-E071-4234-87C9-5842B773C170}.DebugGame|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{74354AC2-E071-4234-87C9-5842B773C170}.DebugGame|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{74354AC2-E071-4234-87C9-5842B773C170}.Development Editor|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{74354AC2-E071-4234-87C9-5842B773C170}.Development Editor|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{74354AC2-E071-4234-87C9-5842B773C170}.Development Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{74354AC2-E071-4234-87C9-5842B773C170}.Development|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{74354AC2-E071-4234-87C9-5842B773C170}.Development|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{74354AC2-E071-4234-87C9-5842B773C170}.Development|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{74354AC2-E071-4234-87C9-5842B773C170}.Shipping|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{74354AC2-E071-4234-87C9-5842B773C170}.Shipping|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{74354AC2-E071-4234-87C9-5842B773C170}.Shipping|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.DebugGame Editor|Android.ActiveCfg = Invalid|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.DebugGame Editor|Win32.ActiveCfg = Invalid|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.DebugGame Editor|Win64.ActiveCfg = DebugGame_Editor|x64
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.DebugGame Editor|Win64.Build.0 = DebugGame_Editor|x64
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.DebugGame|Android.ActiveCfg = Android_DebugGame|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.DebugGame|Android.Build.0 = Android_DebugGame|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.DebugGame|Win32.ActiveCfg = DebugGame|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.DebugGame|Win32.Build.0 = DebugGame|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.DebugGame|Win64.ActiveCfg = DebugGame|x64
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.DebugGame|Win64.Build.0 = DebugGame|x64
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Development Editor|Android.ActiveCfg = Invalid|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Development Editor|Win32.ActiveCfg = Invalid|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Development Editor|Win64.ActiveCfg = Development_Editor|x64
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Development Editor|Win64.Build.0 = Development_Editor|x64
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Development|Android.ActiveCfg = Android_Development|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Development|Android.Build.0 = Android_Development|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Development|Win32.ActiveCfg = Development|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Development|Win32.Build.0 = Development|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Development|Win64.ActiveCfg = Development|x64
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Development|Win64.Build.0 = Development|x64
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Shipping|Android.ActiveCfg = Android_Shipping|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Shipping|Android.Build.0 = Android_Shipping|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Shipping|Win32.ActiveCfg = Shipping|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Shipping|Win32.Build.0 = Shipping|Win32
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Shipping|Win64.ActiveCfg = Shipping|x64
{97946AF8-2BBD-45DF-B560-04E9007DCB1A}.Shipping|Win64.Build.0 = Shipping|x64
{7B9D3087-59A5-43EF-B77B-4DBA855467B6}.DebugGame Editor|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{7B9D3087-59A5-43EF-B77B-4DBA855467B6}.DebugGame Editor|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{7B9D3087-59A5-43EF-B77B-4DBA855467B6}.DebugGame Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{7B9D3087-59A5-43EF-B77B-4DBA855467B6}.DebugGame|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{7B9D3087-59A5-43EF-B77B-4DBA855467B6}.DebugGame|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{7B9D3087-59A5-43EF-B77B-4DBA855467B6}.DebugGame|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{7B9D3087-59A5-43EF-B77B-4DBA855467B6}.Development Editor|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{7B9D3087-59A5-43EF-B77B-4DBA855467B6}.Development Editor|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{7B9D3087-59A5-43EF-B77B-4DBA855467B6}.Development Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{7B9D3087-59A5-43EF-B77B-4DBA855467B6}.Development|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{7B9D3087-59A5-43EF-B77B-4DBA855467B6}.Development|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{7B9D3087-59A5-43EF-B77B-4DBA855467B6}.Development|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{7B9D3087-59A5-43EF-B77B-4DBA855467B6}.Shipping|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{7B9D3087-59A5-43EF-B77B-4DBA855467B6}.Shipping|Win32.ActiveCfg = BuiltWithUnrealBuildTool|Win32
{7B9D3087-59A5-43EF-B77B-4DBA855467B6}.Shipping|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{74354AC2-E071-4234-87C9-5842B773C170} = {94A6C6F3-99B3-346E-9557-ABF9D4064DBD}
{2FAC355B-B731-475C-8E0B-842BE82A5759} = {8E2F6A87-1826-34F4-940C-CC23A48F9FE4}
{7B9D3087-59A5-43EF-B77B-4DBA855467B6} = {94A6C6F3-99B3-346E-9557-ABF9D4064DBD}
{97946AF8-2BBD-45DF-B560-04E9007DCB1A} = {8E2F6A87-1826-34F4-940C-CC23A48F9FE4}
EndGlobalSection
EndGlobal

View File

@ -19,13 +19,17 @@ ABasePawn::ABasePawn(const FObjectInitializer &object_initializer):
collision = object_initializer.CreateDefaultSubobject<UBoxComponent>(this, FName("Collision"));
collision->SetupAttachment(RootComponent);
collision->SetCollisionProfileName(FName("Pawn"));
collision->SetCanEverAffectNavigation(false);
player_mesh = object_initializer.CreateDefaultSubobject<UStaticMeshComponent>(this, FName("PlayerMesh"));
player_mesh->SetupAttachment(collision);
player_mesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
player_mesh->SetCanEverAffectNavigation(false);
movement_component = object_initializer.CreateDefaultSubobject<UFloatingPawnMovement>(this, FName("MovementComponent"));
movement_component->UpdatedComponent = collision;
PrimaryActorTick.bCanEverTick = true;
// Set defaults.
@ -42,6 +46,7 @@ void ABasePawn::BeginPlay()
*/
collision->OnComponentHit.AddDynamic(this, &ABasePawn::handle_hit);
/*
* Set base state.
*/
@ -70,6 +75,11 @@ UPawnMovementComponent* ABasePawn::GetMovementComponent() const
return movement_component;
}
FVector ABasePawn::get_location() const
{
return collision->GetComponentLocation();
}
// Called every frame
void ABasePawn::Tick(float DeltaTime)
{

View File

@ -18,6 +18,8 @@ public:
// Sets default values for this pawn's properties
ABasePawn(const FObjectInitializer &object_initializer);
FVector get_location() const;
// Called every frame
virtual void Tick(float DeltaTime) override;
virtual void handle_move_right(float axis);

View File

@ -0,0 +1,102 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "EnemyAIController.h"
#include "EngineUtils.h"
#include "DrawDebugHelpers.h"
#include "Util.h"
#define LogInfo(Msg) Util::log_info(TEXT("AEnemyIController"), Msg)
#define LogError(Msg) Util::log_error(TEXT("AEnemyIController"), Msg)
void AEnemyAIController::Tick(float delta_time)
{
Super::Tick(delta_time);
switch(current_state)
{
case state_t::init:
president = get_president();
if (president)
{
current_state = state_t::wait;
}
break;
case state_t::wait:
waiting_time += delta_time;
if (waiting_time > wait_threshold)
{
waiting_time = 0;
current_state = state_t::target;
}
break;
case state_t::target:
if (!president)
{
current_state = state_t::init;
}
else
{
FVector target_location = president->get_location();
FVector current_location = Cast<ABasePawn>(GetPawn())->get_location();
FVector between = target_location - current_location;
between = FVector(between.X, between.Y, 0);
between.Normalize();
FVector extended = (between * overshoot_multiplier) + target_location;
MoveToLocation(extended);
current_state = state_t::moving;
}
break;
case state_t::moving:
if (move_completed)
{
move_completed = false;
current_state = state_t::wait;
}
break;
default:
/*
* Do nothing.
*/
break;
}
}
void AEnemyAIController::OnMoveCompleted(FAIRequestID request_id, const FPathFollowingResult& result)
{
move_completed = true;
}
/**
* Helper function to find president in level.
*/
ABasePawn* AEnemyAIController::get_president() const
{
ABasePawn* found = nullptr;
for (TActorIterator<AActor> iterator(GetWorld()); iterator; ++iterator)
{
AActor* actor = *iterator;
if (actor && actor != this)
{
UClass* actor_class = actor->GetClass();
if (actor_class == (*president_class))
{
if (found)
{
LogError("Multiple presidents found!");
break;
}
found = Cast<ABasePawn>(actor);
}
}
}
if (!found)
{
LogError("No president found!");
}
return found;
}

View File

@ -0,0 +1,69 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "AIController.h"
#include "BasePawn.h"
#include "EnemyAIController.generated.h"
/**
*
*/
UCLASS()
class PRESIDENTSBRIGADE_API AEnemyAIController : public AAIController
{
GENERATED_BODY()
public:
virtual void Tick(float delta_time) override;
protected:
virtual void OnMoveCompleted(FAIRequestID request_id, const FPathFollowingResult& result) override;
/**
* President class to find in level.
*/
UPROPERTY(EditAnywhere, Category = "Enemy")
TSubclassOf<ABasePawn> president_class;
UPROPERTY(EditAnywhere, Category = "Movement")
float wait_threshold;
UPROPERTY(EditAnywhere, Category = "Movement")
float overshoot_multiplier;
private:
/**
* State.
*/
enum state_t : uint8
{
init,
wait,
target,
moving,
};
ABasePawn* get_president() const;
/**
* Current state.
*/
state_t current_state;
/**
* President that this enemy is targeting.
*/
ABasePawn* president;
/**
* True when last submitted move has completed.
*/
bool move_completed;
/**
* Time spent in waiting.
*/
float waiting_time;
};

View File

@ -0,0 +1,59 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "EnemySpawner.h"
// Sets default values
AEnemySpawner::AEnemySpawner()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
spawn_delay_s = 5.0f;
}
// Called when the game starts or when spawned
void AEnemySpawner::BeginPlay()
{
Super::BeginPlay();
/*
* Initialize random stream.
*/
random.Initialize(FMath::Rand());
}
// Called every frame
void AEnemySpawner::Tick(float delta_s)
{
Super::Tick(delta_s);
spawn_wait_s += delta_s;
if (next_spawn_threshold_s == 0)
{
next_spawn_threshold_s = spawn_delay_s + random.GetFraction();
}
else if (spawn_wait_s > next_spawn_threshold_s)
{
FActorSpawnParameters spawnParameters;
spawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
spawnParameters.Owner = this;
AAIController* controller = GetWorld()->SpawnActor<AAIController>(
controller_class,
GetActorLocation(),
FRotator(0,0,0),
spawnParameters
);
ABasePawn* enemy = GetWorld()->SpawnActor<ABasePawn>(
pawn_class,
GetActorLocation(),
FRotator(0,0,0),
spawnParameters
);
controller->Possess(enemy);
spawn_wait_s = 0;
next_spawn_threshold_s = spawn_delay_s + random.GetFraction();
}
}

View File

@ -0,0 +1,60 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "BasePawn.h"
#include "AIController.h"
#include "EnemySpawner.generated.h"
UCLASS()
class PRESIDENTSBRIGADE_API AEnemySpawner : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AEnemySpawner();
// Called every frame
virtual void Tick(float DeltaTime) override;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
/**
* Delay between spawning each enemy in seconds.
*/
UPROPERTY(EditAnywhere, Category = "Enemy")
float spawn_delay_s;
/**
* Enemy pawn class.
*/
UPROPERTY(EditAnywhere, Category = "Enemy")
TSubclassOf<ABasePawn> pawn_class;
/**
* Enemy controller class.
*/
UPROPERTY(EditAnywhere, Category = "Enemy")
TSubclassOf<AAIController> controller_class;
private:
/**
* Random number stream.
*/
FRandomStream random;
/**
* Threshold in seconds to wait before spawning.
*/
float next_spawn_threshold_s;
/**
* Current wait time in seconds.
*/
float spawn_wait_s;
};

View File

@ -1,14 +1,14 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "BaseAIController.h"
#include "PresidentAIController.h"
#include "EngineUtils.h"
#include "Util.h"
#define LogInfo(Msg) Util::log_info(TEXT("ABaseAIController"), Msg)
#define LogError(Msg) Util::log_error(TEXT("ABasePawn"), Msg)
#define LogInfo(Msg) Util::log_info(TEXT("APresidentAIController"), Msg)
#define LogError(Msg) Util::log_error(TEXT("APresidentAIController"), Msg)
void ABaseAIController::BeginPlay()
void APresidentAIController::BeginPlay()
{
Super::BeginPlay();
@ -18,7 +18,7 @@ void ABaseAIController::BeginPlay()
random.Initialize(FMath::Rand());
}
void ABaseAIController::Tick(float delta)
void APresidentAIController::Tick(float delta)
{
Super::Tick(delta);
@ -76,7 +76,7 @@ void ABaseAIController::Tick(float delta)
}
}
void ABaseAIController::OnMoveCompleted(FAIRequestID request_id, const FPathFollowingResult& result)
void APresidentAIController::OnMoveCompleted(FAIRequestID request_id, const FPathFollowingResult& result)
{
move_completed = true;
}
@ -85,7 +85,7 @@ void ABaseAIController::OnMoveCompleted(FAIRequestID request_id, const FPathFoll
/**
* Helper function to load all the markers in the level.
*/
TArray<FVector> ABaseAIController::get_markers() const
TArray<FVector> APresidentAIController::get_markers() const
{
TArray<FVector> locations;
for (TActorIterator<AActor> iterator(GetWorld()); iterator; ++iterator)
@ -115,7 +115,7 @@ TArray<FVector> ABaseAIController::get_markers() const
*
* @return World location vector of mark.
*/
FVector ABaseAIController::get_random_mark() const
FVector APresidentAIController::get_random_mark() const
{
if (marker_locations.Num() == 0)
{

View File

@ -4,13 +4,13 @@
#include "CoreMinimal.h"
#include "AIController.h"
#include "BaseAIController.generated.h"
#include "PresidentAIController.generated.h"
/**
*
*/
UCLASS()
class PRESIDENTSBRIGADE_API ABaseAIController : public AAIController
class PRESIDENTSBRIGADE_API APresidentAIController : public AAIController
{
GENERATED_BODY()

View File

@ -6,9 +6,9 @@ xAdd presidents car
x Moves to markers on map
x Randomly chooses a marker
x Randomly moves after some time
Add enemy cars
Comes from off screen
Attacks president car
xAdd enemy cars
xComes from off screen
xAttacks president car
Add dash
Add netcode
Add player damage