AgeOfWar minigame

This commit is contained in:
Oleg Petruny 2024-11-10 13:19:04 +01:00
parent a3eca9d441
commit cbb8a5bc14
12 changed files with 238 additions and 7 deletions

Binary file not shown.

View File

@ -3,11 +3,29 @@
#include "AgeOfWarManager.h" #include "AgeOfWarManager.h"
#include "Camera/CameraComponent.h"
#include "AgeOfWarUnit.h"
#include "MainGameModeBase.h" #include "MainGameModeBase.h"
#include "PlayerBase.h" #include "PlayerBase.h"
TMap<UClass*, FAgeOfWarUnitStats> AAgeOfWarManager::unitStats = {};
const FAgeOfWarUnitStats& AAgeOfWarManager::UnitGetStats(TSubclassOf<AAgeOfWarUnit> unitClass)
{
return unitStats[unitClass];
}
AAgeOfWarManager::AAgeOfWarManager() 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) void AAgeOfWarManager::Start(APlayerBase* playerPawn, FMinigameEndCallback delegate)
{ {
@ -17,11 +35,25 @@ void AAgeOfWarManager::Start(APlayerBase* playerPawn, FMinigameEndCallback deleg
AMinigame::Start(playerPawn, delegate); AMinigame::Start(playerPawn, delegate);
player->LockPlayer(FPlayerLock::All()); player->LockPlayer(FPlayerLock::All());
player->SwitchToView(this);
FillUnitStats();
} }
void AAgeOfWarManager::End() void AAgeOfWarManager::End()
{ {
unitStats.Empty();
player->ReturnPlayerView();
player->UnlockPlayer(FPlayerLock::All()); player->UnlockPlayer(FPlayerLock::All());
AMinigame::End(); 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() GENERATED_BODY()
public: public:
static const struct FAgeOfWarUnitStats& UnitGetStats(TSubclassOf<AAgeOfWarUnit> unitClass);
AAgeOfWarManager(); AAgeOfWarManager();
virtual void Start(class APlayerBase* playerPawn, FMinigameEndCallback delegate) override; virtual void Start(class APlayerBase* playerPawn, FMinigameEndCallback delegate) override;
virtual void End() 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;
};