AgeOfWar minigame

This commit is contained in:
Oleg Petruny 2024-11-10 13:19:04 +01:00
parent f317cc566b
commit e7db6372d8
13 changed files with 240 additions and 9 deletions

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.

BIN
Content/Levels/Test/L_Test.umap (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

View File

@ -3,11 +3,29 @@
#include "AgeOfWarManager.h"
#include "Camera/CameraComponent.h"
#include "AgeOfWarUnit.h"
#include "MainGameModeBase.h"
#include "PlayerBase.h"
TMap<UClass*, FAgeOfWarUnitStats> AAgeOfWarManager::unitStats = {};
const FAgeOfWarUnitStats& AAgeOfWarManager::UnitGetStats(TSubclassOf<AAgeOfWarUnit> unitClass)
{
return unitStats[unitClass];
}
AAgeOfWarManager::AAgeOfWarManager()
{}
{
auto root = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
camera->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform);
basePlayer = static_cast<AAgeOfWarUnit*>(CreateDefaultSubobject(TEXT("BasePlayer"), AAgeOfWarUnit::StaticClass(), baseClass, true, false));
baseComputer = static_cast<AAgeOfWarUnit*>(CreateDefaultSubobject(TEXT("BaseComputer"), AAgeOfWarUnit::StaticClass(), baseClass, true, false));
}
void AAgeOfWarManager::Start(APlayerBase* playerPawn, FMinigameEndCallback delegate)
{
@ -17,11 +35,25 @@ void AAgeOfWarManager::Start(APlayerBase* playerPawn, FMinigameEndCallback deleg
AMinigame::Start(playerPawn, delegate);
player->LockPlayer(FPlayerLock::All());
player->SwitchToView(this);
FillUnitStats();
}
void AAgeOfWarManager::End()
{
unitStats.Empty();
player->ReturnPlayerView();
player->UnlockPlayer(FPlayerLock::All());
AMinigame::End();
}
void AAgeOfWarManager::UnitKill(AAgeOfWarUnit* unit)
{}
void AAgeOfWarManager::AddUnitStats(TSubclassOf<AAgeOfWarUnit> unitClass, FAgeOfWarUnitStats stats)
{
unitStats.Add(unitClass, stats);
}

View File

@ -12,8 +12,34 @@ class AAgeOfWarManager : public AMinigame
GENERATED_BODY()
public:
static const struct FAgeOfWarUnitStats& UnitGetStats(TSubclassOf<AAgeOfWarUnit> unitClass);
AAgeOfWarManager();
virtual void Start(class APlayerBase* playerPawn, FMinigameEndCallback delegate) override;
virtual void End() override;
void UnitKill(class AAgeOfWarUnit* unit);
protected:
UFUNCTION(BlueprintImplementableEvent)
void FillUnitStats();
UFUNCTION(BlueprintCallable)
static void AddUnitStats(TSubclassOf<AAgeOfWarUnit> unitClass, struct FAgeOfWarUnitStats stats);
static TMap<UClass*, struct FAgeOfWarUnitStats> unitStats;
UPROPERTY(EditAnywhere)
class UCameraComponent* camera;
UPROPERTY(EditDefaultsOnly)
class TSubclassOf<AAgeOfWarUnit> baseClass;
UPROPERTY(EditAnywhere)
class AAgeOfWarUnit* basePlayer;
UPROPERTY(EditAnywhere)
class AAgeOfWarUnit* baseComputer;
};

View File

@ -0,0 +1,84 @@
// Oleg Petruny proprietary.
#include "AgeOfWarUnit.h"
#include "AgeOfWarManager.h"
const FAgeOfWarUnitStats& AAgeOfWarUnit::GetStats()
{
if(!stats)
stats = &AAgeOfWarManager::UnitGetStats(GetClass());
if(ensureAlways(stats))
{
auto errorMsg = FString::Printf(TEXT("AgeOfWarManager instance doesn't contain %s class stats... Destroying actor"), &GetClass()->GetName());
UE_LOG(LogTemp, Log, TEXT("%s"), *errorMsg);
GEngine->AddOnScreenDebugMessage(-1, 20.0f, FColor::Red, errorMsg);
static FAgeOfWarUnitStats s{};
stats = &s;
Destroy();
}
return *stats;
}
void AAgeOfWarUnit::BeginPlay()
{
health = GetStats().health;
}
void AAgeOfWarUnit::EndPlay(const EEndPlayReason::Type EndPlayReason)
{}
void AAgeOfWarUnit::Tick(float deltaTime)
{
Super::Tick(deltaTime);
if(GetStats().moveSpeed <= 0)
return;
// move unit forward
auto moveStep = GetActorForwardVector() * GetStats().moveSpeed;
FHitResult hit;
this->AddActorWorldOffset(moveStep, true, &hit, ETeleportType::None);
// check if blocked
if(!hit.bBlockingHit)
return;
forwardUnit = Cast<AAgeOfWarUnit>(hit.GetActor());
if(!forwardUnit) // something is wrong, only block with units
{
Destroy();
return;
}
// iterate to attackable unit
for(int i = 1; forwardUnit->team == team && i < GetStats().attackDistance; i += forwardUnit->GetStats().unitSize)
forwardUnit = forwardUnit->forwardUnit;
// if forward unit is in the same team skip attack
if(forwardUnit->team == team)
return;
// attack the forward unit
if(lastAttackTimestamp + GetStats().attackRate - FPlatformTime::Seconds() < 0)
{
lastAttackTimestamp = FPlatformTime::Seconds();
forwardUnit->Damage(GetStats().attackDamage);
}
}
void AAgeOfWarUnit::Damage(const int32 damage)
{
health -= damage;
if(health > 0)
return;
if(IsValid(manager))
manager->UnitKill(this);
else
Destroy();
}

View File

@ -0,0 +1,74 @@
// Oleg Petruny proprietary.
#pragma once
#include "GameFramework/Actor.h"
#include "AgeOfWarUnit.generated.h"
USTRUCT(BlueprintType)
struct FAgeOfWarUnitStats
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FText name = FText::GetEmpty();
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 price = 100;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 health = 5;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float moveSpeed = 1.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 attackDamage = 1;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 attackDistance = 1;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float attackRate = 1.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 unitSize = 1;
};
UCLASS(Blueprintable, MinimalAPI, Abstract)
class AAgeOfWarUnit : public AActor
{
GENERATED_BODY()
public:
enum class UnitTeam
{
Player,
AI
};
UFUNCTION(BlueprintPure)
const FAgeOfWarUnitStats& GetStats();
class AAgeOfWarManager* manager = nullptr;
const FAgeOfWarUnitStats* stats = nullptr;
UnitTeam team;
protected:
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float deltaTime) override;
void Damage(const int32 damage);
AAgeOfWarUnit* forwardUnit = nullptr;
private:
int32 health;
FTimerHandle attackTimer;
double lastAttackTimestamp = 0;
};