Minigame without AI

This commit is contained in:
Oleg Petruny 2024-11-17 22:20:05 +01:00
parent cbb8a5bc14
commit 579100f45c
17 changed files with 122 additions and 74 deletions

View File

@ -139,6 +139,7 @@ ManualIPAddress=
+Profiles=(Name="Vehicle",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Vehicle",CustomResponses=,HelpMessage="Vehicle object that blocks Vehicle, WorldStatic, and WorldDynamic. All other channels will be set to default.") +Profiles=(Name="Vehicle",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Vehicle",CustomResponses=,HelpMessage="Vehicle object that blocks Vehicle, WorldStatic, and WorldDynamic. All other channels will be set to default.")
+Profiles=(Name="UI",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility"),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ") +Profiles=(Name="UI",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility"),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="Interactable",CollisionEnabled=QueryAndPhysics,bCanModify=True,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Interactable")),HelpMessage="WorldDynamic objects derived from AInteractable.") +Profiles=(Name="Interactable",CollisionEnabled=QueryAndPhysics,bCanModify=True,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Interactable")),HelpMessage="WorldDynamic objects derived from AInteractable.")
+Profiles=(Name="AgeOfWarUnit",CollisionEnabled=QueryOnly,bCanModify=True,ObjectTypeName="Vehicle",CustomResponses=((Channel="WorldStatic",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Minigame object")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="Interactable") +DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="Interactable")
-ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall") -ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall")
-ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn") -ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn")

Binary file not shown.

View File

@ -55,25 +55,25 @@ void AInteractable::BeginPlay()
} }
} }
GetComponents(meshes); GetComponents(collisions, true);
for(auto mesh : meshes) for(auto collision : collisions)
{ {
if(activatorTypes) if(activatorTypes)
{ {
mesh->SetCollisionProfileName(TEXT("Interactable")); collision->SetCollisionProfileName(TEXT("Interactable"));
} }
if(activatorTypes & static_cast<uint8>(EActivatorType::Saw)) if(activatorTypes & static_cast<uint8>(EActivatorType::Saw))
{ {
mesh->CustomDepthStencilValue = 128; collision->CustomDepthStencilValue = 128;
mesh->CustomDepthStencilWriteMask = ERendererStencilMask::ERSM_Default; collision->CustomDepthStencilWriteMask = ERendererStencilMask::ERSM_Default;
mesh->SetRenderCustomDepth(true); collision->SetRenderCustomDepth(true);
} }
if(activatorTypes & static_cast<uint8>(EActivatorType::Use)) if(activatorTypes & static_cast<uint8>(EActivatorType::Use))
{ {
mesh->CustomDepthStencilWriteMask = ERendererStencilMask::ERSM_Default; collision->CustomDepthStencilWriteMask = ERendererStencilMask::ERSM_Default;
mesh->SetRenderCustomDepth(true); collision->SetRenderCustomDepth(true);
} }
} }
@ -120,8 +120,8 @@ void AInteractable::_Activate(EActivatorType type)
if(activated & static_cast<uint8>(EActivatorType::Use)) if(activated & static_cast<uint8>(EActivatorType::Use))
{ {
for(auto mesh : meshes) for(auto collision : collisions)
mesh->SetCustomDepthStencilValue(132); collision->SetCustomDepthStencilValue(132);
} }
Activate(type); Activate(type);
@ -155,8 +155,8 @@ void AInteractable::_Deactivate(EActivatorType type)
if(!(activated & static_cast<uint8>(EActivatorType::Use))) if(!(activated & static_cast<uint8>(EActivatorType::Use)))
{ {
for(auto mesh : meshes) for(auto collision : collisions)
mesh->SetCustomDepthStencilValue(0); collision->SetCustomDepthStencilValue(0);
} }
Deactivate(type); Deactivate(type);

View File

@ -58,7 +58,7 @@ protected:
TMap<EActivatorType, class UInteractableModificator*> modificators; TMap<EActivatorType, class UInteractableModificator*> modificators;
class APlayerBase* player = nullptr; class APlayerBase* player = nullptr;
TArray<UMeshComponent*> meshes; TArray<UPrimitiveComponent*> collisions;
}; };

View File

@ -4,6 +4,7 @@
#include "AgeOfWarManager.h" #include "AgeOfWarManager.h"
#include "Camera/CameraComponent.h" #include "Camera/CameraComponent.h"
#include "Components/ChildActorComponent.h"
#include "AgeOfWarUnit.h" #include "AgeOfWarUnit.h"
#include "MainGameModeBase.h" #include "MainGameModeBase.h"
@ -13,6 +14,8 @@ TMap<UClass*, FAgeOfWarUnitStats> AAgeOfWarManager::unitStats = {};
const FAgeOfWarUnitStats& AAgeOfWarManager::UnitGetStats(TSubclassOf<AAgeOfWarUnit> unitClass) const FAgeOfWarUnitStats& AAgeOfWarManager::UnitGetStats(TSubclassOf<AAgeOfWarUnit> unitClass)
{ {
check(unitStats.Contains(*unitClass));
return unitStats[unitClass]; return unitStats[unitClass];
} }
@ -21,10 +24,7 @@ AAgeOfWarManager::AAgeOfWarManager()
auto root = CreateDefaultSubobject<USceneComponent>(TEXT("Scene")); auto root = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera")); camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
camera->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform); camera->SetupAttachment(root);
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)
@ -38,6 +38,16 @@ void AAgeOfWarManager::Start(APlayerBase* playerPawn, FMinigameEndCallback deleg
player->SwitchToView(this); player->SwitchToView(this);
FillUnitStats(); FillUnitStats();
TArray<UChildActorComponent*> units;
GetComponents<UChildActorComponent>(units);
for(auto& unit : units)
{
if(auto proxy = Cast<AAgeOfWarUnit>(unit->GetChildActor()))
{
proxy->manager = this;
proxy->UpdateStats();
}
}
} }
void AAgeOfWarManager::End() void AAgeOfWarManager::End()
@ -50,10 +60,21 @@ void AAgeOfWarManager::End()
AMinigame::End(); AMinigame::End();
} }
void AAgeOfWarManager::UnitKill(AAgeOfWarUnit* unit)
{}
void AAgeOfWarManager::AddUnitStats(TSubclassOf<AAgeOfWarUnit> unitClass, FAgeOfWarUnitStats stats) void AAgeOfWarManager::AddUnitStats(TSubclassOf<AAgeOfWarUnit> unitClass, FAgeOfWarUnitStats stats)
{ {
unitStats.Add(unitClass, stats); unitStats.Add(unitClass, stats);
} }
FAgeOfWarUnitStats AAgeOfWarManager::GetUnitStats(TSubclassOf<AAgeOfWarUnit> unitClass)
{
return UnitGetStats(unitClass);
}
void AAgeOfWarManager::SpawnUnit(TSubclassOf<AAgeOfWarUnit> unitClass, FTransform transform, bool computer)
{
FActorSpawnParameters spawnParams{};
spawnParams.Owner = this;
auto unit = GetWorld()->SpawnActor<AAgeOfWarUnit>(*unitClass, transform, spawnParams);
unit->team = computer ? UnitTeam::AI : UnitTeam::Player;
unit->manager = this;
}

View File

@ -19,27 +19,23 @@ public:
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); UFUNCTION(BlueprintImplementableEvent)
void OnUnitKill(class AAgeOfWarUnit* unit);
protected: protected:
UFUNCTION(BlueprintImplementableEvent) UFUNCTION(BlueprintImplementableEvent)
void FillUnitStats(); void FillUnitStats();
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
static void AddUnitStats(TSubclassOf<AAgeOfWarUnit> unitClass, struct FAgeOfWarUnitStats stats); static void AddUnitStats(TSubclassOf<AAgeOfWarUnit> unitClass, struct FAgeOfWarUnitStats stats);
UFUNCTION(BlueprintPure)
static struct FAgeOfWarUnitStats GetUnitStats(TSubclassOf<AAgeOfWarUnit> unitClass);
UFUNCTION(BlueprintCallable)
void SpawnUnit(TSubclassOf<AAgeOfWarUnit> unitClass, FTransform transform, bool computer = false);
static TMap<UClass*, struct FAgeOfWarUnitStats> unitStats; static TMap<UClass*, struct FAgeOfWarUnitStats> unitStats;
UPROPERTY(EditAnywhere) UPROPERTY(EditAnywhere)
class UCameraComponent* camera; class UCameraComponent* camera;
UPROPERTY(EditDefaultsOnly)
class TSubclassOf<AAgeOfWarUnit> baseClass;
UPROPERTY(EditAnywhere)
class AAgeOfWarUnit* basePlayer;
UPROPERTY(EditAnywhere)
class AAgeOfWarUnit* baseComputer;
}; };

View File

@ -3,39 +3,55 @@
#include "AgeOfWarUnit.h" #include "AgeOfWarUnit.h"
#include "Components/StaticMeshComponent.h"
#include "AgeOfWarManager.h" #include "AgeOfWarManager.h"
#include <Components/BoxComponent.h>
const FAgeOfWarUnitStats& AAgeOfWarUnit::GetStats() const FAgeOfWarUnitStats& AAgeOfWarUnit::GetStats()
{ {
if(!stats) if(!stats)
stats = &AAgeOfWarManager::UnitGetStats(GetClass()); 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; return *stats;
} }
void AAgeOfWarUnit::BeginPlay() void AAgeOfWarUnit::UpdateStats()
{ {
health = GetStats().health; health = GetStats().health;
} }
void AAgeOfWarUnit::BeginPlay()
{
if(manager)
{
UpdateStats();
}
Super::BeginPlay();
}
void AAgeOfWarUnit::EndPlay(const EEndPlayReason::Type EndPlayReason) void AAgeOfWarUnit::EndPlay(const EEndPlayReason::Type EndPlayReason)
{} {
Super::EndPlay(EndPlayReason);
}
AAgeOfWarUnit::AAgeOfWarUnit()
{
//auto root = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
//
//collision = CreateDefaultSubobject<UBoxComponent>(TEXT("Collision"));
//collision->SetCollisionProfileName(TEXT("AgeOfWarUnit"));
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.bStartWithTickEnabled = true;
}
void AAgeOfWarUnit::Tick(float deltaTime) void AAgeOfWarUnit::Tick(float deltaTime)
{ {
Super::Tick(deltaTime); Super::Tick(deltaTime);
if(GetStats().moveSpeed <= 0) if(!manager || GetStats().moveSpeed <= 0)
return; return;
// move unit forward // move unit forward
@ -68,17 +84,20 @@ void AAgeOfWarUnit::Tick(float deltaTime)
lastAttackTimestamp = FPlatformTime::Seconds(); lastAttackTimestamp = FPlatformTime::Seconds();
forwardUnit->Damage(GetStats().attackDamage); forwardUnit->Damage(GetStats().attackDamage);
} }
GEngine->AddOnScreenDebugMessage(4, 5.0f, FColor::Yellow, FString::Printf(TEXT("Time %f"), lastAttackTimestamp + GetStats().attackRate - FPlatformTime::Seconds()));
} }
void AAgeOfWarUnit::Damage(const int32 damage) void AAgeOfWarUnit::Damage(const int32 damage)
{ {
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, FString::Printf(TEXT("Damage %d taken by %s"), damage, *GetClass()->GetName()));
health -= damage; health -= damage;
if(health > 0) if(health > 0)
return; return;
if(IsValid(manager)) if(IsValid(manager))
manager->UnitKill(this); manager->OnUnitKill(this);
else else
Destroy(); Destroy();
} }

View File

@ -37,35 +37,46 @@ struct FAgeOfWarUnitStats
}; };
UENUM(BlueprintType)
enum class UnitTeam : uint8
{
Player,
AI
};
UCLASS(Blueprintable, MinimalAPI, Abstract) UCLASS(Blueprintable, MinimalAPI, Abstract)
class AAgeOfWarUnit : public AActor class AAgeOfWarUnit : public AActor
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
enum class UnitTeam AAgeOfWarUnit();
{ virtual void Tick(float deltaTime) override;
Player,
AI
};
UFUNCTION(BlueprintPure) UFUNCTION(BlueprintPure)
const FAgeOfWarUnitStats& GetStats(); const FAgeOfWarUnitStats& GetStats();
class AAgeOfWarManager* manager = nullptr; UFUNCTION(BlueprintCallable)
void UpdateStats();
const FAgeOfWarUnitStats* stats = nullptr; const FAgeOfWarUnitStats* stats = nullptr;
class AAgeOfWarManager* manager = nullptr;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UnitTeam team; UnitTeam team;
protected: protected:
virtual void BeginPlay() override; virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float deltaTime) override;
void Damage(const int32 damage); void Damage(const int32 damage);
AAgeOfWarUnit* forwardUnit = nullptr; AAgeOfWarUnit* forwardUnit = nullptr;
private: private:
UPROPERTY(EditAnywhere)
class UBoxComponent* collision;
int32 health; int32 health;
FTimerHandle attackTimer; FTimerHandle attackTimer;
double lastAttackTimestamp = 0; double lastAttackTimestamp = 0;

View File

@ -24,13 +24,13 @@ ACrossyRoadManager::ACrossyRoadManager()
auto root = CreateDefaultSubobject<USceneComponent>(TEXT("Scene")); auto root = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
playerPos = CreateDefaultSubobject<USceneComponent>(TEXT("PlayerPos")); playerPos = CreateDefaultSubobject<USceneComponent>(TEXT("PlayerPos"));
playerPos->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform); playerPos->SetupAttachment(root);
camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera")); camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
camera->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform); camera->SetupAttachment(root);
mannequin = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mannequin")); mannequin = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mannequin"));
mannequin->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform); mannequin->SetupAttachment(root);
} }
void ACrossyRoadManager::Start(APlayerBase* playerPawn, FMinigameEndCallback delegate) void ACrossyRoadManager::Start(APlayerBase* playerPawn, FMinigameEndCallback delegate)

View File

@ -24,13 +24,13 @@ ASubwaySurfManager::ASubwaySurfManager()
auto root = CreateDefaultSubobject<USceneComponent>(TEXT("Scene")); auto root = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
playerPos = CreateDefaultSubobject<USceneComponent>(TEXT("PlayerPos")); playerPos = CreateDefaultSubobject<USceneComponent>(TEXT("PlayerPos"));
playerPos->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform); playerPos->SetupAttachment(root);
camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera")); camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
camera->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform); camera->SetupAttachment(root);
mannequin = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mannequin")); mannequin = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mannequin"));
mannequin->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform); mannequin->SetupAttachment(root);
} }
void ASubwaySurfManager::Start(APlayerBase* playerPawn, FMinigameEndCallback delegate) void ASubwaySurfManager::Start(APlayerBase* playerPawn, FMinigameEndCallback delegate)