Spawn enemies off map

This commit is contained in:
Sara Montecino 2022-11-19 12:50:05 -08:00
parent 770e33fce1
commit 7ba7379699
14 changed files with 169 additions and 71 deletions

View File

@ -94,7 +94,7 @@ DoubleClickTime=0.200000
+ActionMappings=(ActionName="Shoot",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=LeftMouseButton)
+ActionMappings=(ActionName="Shoot",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Gamepad_RightTrigger)
+ActionMappings=(ActionName="Boost",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=RightMouseButton)
+ActionMappings=(ActionName="Boost",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Gamepad_RightShoulder)
+ActionMappings=(ActionName="Boost",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Gamepad_LeftTrigger)
+AxisMappings=(AxisName="MoveForward",Scale=1.000000,Key=W)
+AxisMappings=(AxisName="MoveForward",Scale=-1.000000,Key=S)
+AxisMappings=(AxisName="MoveRight",Scale=1.000000,Key=D)

BIN
Content/EnemyMarker.uasset Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -9,7 +9,10 @@ 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;
level_location = TUniquePtr<LevelLocation>(new LevelLocation());
spawn_delay_s = 5.0f;
max_spawn_count = 5;
}
// Called when the game starts or when spawned
@ -27,6 +30,10 @@ void AEnemySpawner::BeginPlay()
void AEnemySpawner::Tick(float delta_s)
{
Super::Tick(delta_s);
if (!level_location->is_initialized())
{
level_location->initialize(GetWorld(), marker_class);
}
spawn_wait_s += delta_s;
if (next_spawn_threshold_s == 0)
@ -35,23 +42,30 @@ void AEnemySpawner::Tick(float delta_s)
}
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
);
const int spawn_count = random.RandRange(0, max_spawn_count);
for (int i = 0; i < spawn_count; i++)
{
const FVector location = level_location->get_random_mark();
FActorSpawnParameters spawnParameters;
spawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
spawnParameters.Owner = this;
AAIController* controller = GetWorld()->SpawnActor<AAIController>(
controller_class,
location,
FRotator(0,0,0),
spawnParameters
);
ABasePawn* enemy = GetWorld()->SpawnActor<ABasePawn>(
pawn_class,
location,
FRotator(0,0,0),
spawnParameters
);
controller->Possess(enemy);
}
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

@ -6,6 +6,7 @@
#include "GameFramework/Actor.h"
#include "BasePawn.h"
#include "AIController.h"
#include "LevelLocation.h"
#include "EnemySpawner.generated.h"
UCLASS()
@ -41,8 +42,25 @@ protected:
UPROPERTY(EditAnywhere, Category = "Enemy")
TSubclassOf<AAIController> controller_class;
/**
* Enemy spawn location marker.
*/
UPROPERTY(EditAnywhere, Category = "Enemy")
UClass* marker_class;
/**
* Max number of enemies to spawn in one cycle.
*/
UPROPERTY(EditAnywhere, Category = "Enemy")
int max_spawn_count;
private:
/**
* Level location.
*/
TUniquePtr<LevelLocation> level_location;
/**
* Random number stream.
*/

View File

@ -0,0 +1,73 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "LevelLocation.h"
#include "EngineUtils.h"
#include "Util.h"
#define LogError(Msg) Util::log_error(TEXT("LevelLocation"), Msg)
LevelLocation::LevelLocation()
{
}
LevelLocation::~LevelLocation()
{
}
bool LevelLocation::is_initialized() const
{
return initialized;
}
/**
* Initialize this class with a list of locations derived from the current world.
*/
void LevelLocation::initialize(UWorld *world, const UClass *marker_class)
{
initialized = true;
/*
* Find all the markers in the world.
*/
for (TActorIterator<AActor> iterator(world); iterator; ++iterator)
{
AActor* actor = *iterator;
if (actor)
{
UClass* actor_class = actor->GetClass();
if (actor_class == marker_class)
{
locations.Add(actor->GetActorLocation());
}
}
}
if (locations.Num() == 0)
{
LogError("No markers");
}
/*
* Initialize random stream.
*/
random.Initialize(FMath::Rand());
}
/**
* Get world location of randomly selected mark.
*
* @return World location vector of mark.
*/
FVector LevelLocation::get_random_mark() const
{
if (locations.Num() == 0)
{
LogError("No markers");
return FVector();
}
const int index = random.RandRange(0, locations.Num() - 1);
return locations[index];
}

View File

@ -0,0 +1,35 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
/**
*
*/
class PRESIDENTSBRIGADE_API LevelLocation
{
public:
LevelLocation();
~LevelLocation();
void initialize(UWorld *world, const UClass *marker_class);
FVector get_random_mark() const;
bool is_initialized() const;
private:
/**
* True when initialized.
*/
bool initialized = false;
/**
* Random number stream.
*/
FRandomStream random;
/**
* List of locations.
*/
TArray<FVector> locations;
};

View File

@ -8,6 +8,11 @@
#define LogInfo(Msg) Util::log_info(TEXT("APresidentAIController"), Msg)
#define LogError(Msg) Util::log_error(TEXT("APresidentAIController"), Msg)
APresidentAIController::APresidentAIController()
{
level_location = TUniquePtr<LevelLocation>(new LevelLocation());
}
void APresidentAIController::BeginPlay()
{
Super::BeginPlay();
@ -31,7 +36,7 @@ void APresidentAIController::Tick(float delta)
const FVector offset(1.0, 1.0, 0);
starting_location = GetPawn()->GetActorLocation() + offset;
target_location = starting_location;
marker_locations = get_markers();
level_location->initialize(GetWorld(), marker_class);
// Update state.
current_state = state_t::idle;
@ -47,7 +52,7 @@ void APresidentAIController::Tick(float delta)
}
else
{
target_location = is_home ? get_random_mark() : starting_location;
target_location = is_home ? level_location->get_random_mark() : starting_location;
MoveToLocation(target_location);
current_state = state_t::moving;
}
@ -80,50 +85,3 @@ void APresidentAIController::OnMoveCompleted(FAIRequestID request_id, const FPat
{
move_completed = true;
}
/**
* Helper function to load all the markers in the level.
*/
TArray<FVector> APresidentAIController::get_markers() const
{
TArray<FVector> locations;
for (TActorIterator<AActor> iterator(GetWorld()); iterator; ++iterator)
{
AActor* actor = *iterator;
if (actor && actor != this)
{
UClass* actor_class = actor->GetClass();
if (actor_class == marker_class)
{
locations.Add(actor->GetActorLocation());
}
}
}
if (locations.Num() == 0)
{
LogError("No markers");
}
return locations;
}
/**
* Helper function for returning world location of randomly selected mark.
*
* @return World location vector of mark.
*/
FVector APresidentAIController::get_random_mark() const
{
if (marker_locations.Num() == 0)
{
LogError("No markers");
return FVector();
}
const int index = random.RandRange(0, marker_locations.Num() - 1);
return marker_locations[index];
}

View File

@ -4,6 +4,7 @@
#include "CoreMinimal.h"
#include "AIController.h"
#include "LevelLocation.h"
#include "PresidentAIController.generated.h"
/**
@ -15,6 +16,8 @@ class PRESIDENTSBRIGADE_API APresidentAIController : public AAIController
GENERATED_BODY()
public:
APresidentAIController();
virtual void Tick(float delta) override;
protected:
@ -34,13 +37,10 @@ private:
waiting
};
TArray<FVector> get_markers() const;
FVector get_random_mark() const;
/**
* List of marker locations.
* Level location tracker.
*/
TArray<FVector> marker_locations;
TUniquePtr<LevelLocation> level_location;
/**
* Random number stream.