Compare commits

..

3 Commits

Author SHA1 Message Date
Sara Montecino
4c88c7da5c Experimental commit -- no clue what's here 2024-01-02 19:40:23 -08:00
Sara Montecino
7ba7379699 Spawn enemies off map 2022-11-19 12:50:05 -08:00
Sara Montecino
770e33fce1 Add player2 HUD 2022-11-19 11:47:39 -08:00
24 changed files with 240 additions and 78 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.

Binary file not shown.

View File

@ -71,6 +71,13 @@ void ABasePawn::handle_hit(
// Update current health.
current_health -= damage_class_map[other_class];
}
handle_hit_internal(other_actor);
}
void ABasePawn::handle_hit_internal(AActor* other_actor)
{
// do nothing by default;
}
UPawnMovementComponent* ABasePawn::GetMovementComponent() const

View File

@ -75,6 +75,8 @@ protected:
const FHitResult& hit
);
virtual void handle_hit_internal(AActor* other_actor);
virtual UPawnMovementComponent* GetMovementComponent() const;
UPROPERTY(EditAnywhere, Category="Player")

View File

@ -4,6 +4,7 @@
#include "EnemyAIController.h"
#include "EngineUtils.h"
#include "DrawDebugHelpers.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Util.h"
#define LogInfo(Msg) Util::log_info(TEXT("AEnemyIController"), Msg)
@ -17,7 +18,7 @@ void AEnemyAIController::Tick(float delta_time)
{
case state_t::init:
president = get_president();
if (president)
if (UKismetSystemLibrary::IsValid(president))
{
current_state = state_t::wait;
}
@ -31,7 +32,7 @@ void AEnemyAIController::Tick(float delta_time)
}
break;
case state_t::target:
if (!president)
if (!UKismetSystemLibrary::IsValid(president))
{
current_state = state_t::init;
}
@ -39,26 +40,28 @@ void AEnemyAIController::Tick(float delta_time)
{
FVector target_location = president->get_location();
const ABasePawn* local_pawn = Cast<ABasePawn>(GetPawn());
if (local_pawn)
if (UKismetSystemLibrary::IsValid(local_pawn))
{
FVector current_location = local_pawn->get_location();
starting_location = current_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;
current_state = state_t::moving_attack;
}
else
{
// This will be cleaned up shortly.
current_state = state_t::dead;
}
}
break;
case state_t::moving:
case state_t::moving_attack:
case state_t::moving_retreat:
if (move_completed)
{
move_completed = false;
@ -73,6 +76,15 @@ void AEnemyAIController::Tick(float delta_time)
}
}
void AEnemyAIController::redirect_target()
{
if (current_state == moving_attack)
{
MoveToLocation(starting_location);
current_state = moving_retreat;
}
}
void AEnemyAIController::OnMoveCompleted(FAIRequestID request_id, const FPathFollowingResult& result)
{
move_completed = true;

View File

@ -18,6 +18,7 @@ class PRESIDENTSBRIGADE_API AEnemyAIController : public AAIController
public:
virtual void Tick(float delta_time) override;
void redirect_target();
protected:
virtual void OnMoveCompleted(FAIRequestID request_id, const FPathFollowingResult& result) override;
@ -42,7 +43,8 @@ private:
init,
wait,
target,
moving,
moving_attack,
moving_retreat,
dead
};
@ -67,4 +69,9 @@ private:
* Time spent in waiting.
*/
float waiting_time;
/**
* Starting location.
*/
FVector starting_location;
};

View File

@ -3,6 +3,11 @@
#include "EnemyPawn.h"
#include "Pickup.h"
#include "Util.h"
#include "EnemyAIController.h"
#define LogInfo(Msg) Util::log_info(TEXT("EnemyPawn"), Msg)
#define LogError(Msg) Util::log_error(TEXT("EnemyPawn"), Msg)
void AEnemyPawn::BeginPlay()
{
@ -33,3 +38,25 @@ void AEnemyPawn::destroy_self()
ABasePawn::destroy_self();
}
void AEnemyPawn::handle_hit_internal(AActor* other)
{
const AEnemyPawn* is_enemy = Cast<AEnemyPawn>(other);
if (is_enemy)
{
return;
}
const ABasePawn* other_pawn = Cast<ABasePawn>(other);
if (other_pawn)
{
AEnemyAIController* controller = Cast<AEnemyAIController>(GetController());
if (!controller)
{
LogError("EnemyAIController not used!");
return;
}
controller->redirect_target();
}
}

View File

@ -18,6 +18,7 @@ class PRESIDENTSBRIGADE_API AEnemyPawn : public ABasePawn
protected:
virtual void BeginPlay() override;
virtual void destroy_self() override;
virtual void handle_hit_internal(AActor* other_actor) override;
/**
* Pickup class to spawn on death.

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)
{
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,
GetActorLocation(),
location,
FRotator(0,0,0),
spawnParameters
);
ABasePawn* enemy = GetWorld()->SpawnActor<ABasePawn>(
pawn_class,
GetActorLocation(),
location,
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.

View File

@ -8,3 +8,7 @@ APresidentsBrigadeGameModeBase::APresidentsBrigadeGameModeBase()
{
}
void APresidentsBrigadeGameModeBase::PreInitializeComponents()
{
Super::PreInitializeComponents();
}

View File

@ -16,4 +16,6 @@ class PRESIDENTSBRIGADE_API APresidentsBrigadeGameModeBase : public AGameModeBas
public:
APresidentsBrigadeGameModeBase();
virtual void PreInitializeComponents() override;
};

View File

@ -19,6 +19,8 @@ xAdd art
x Car models
x Street shader
xAdd HUD UI for single player.
Make boosting fun
- Enemy car ricochets after hitting player/president
Add sounds
Add juice
Add muzzle on shoot