From aa85f56a4c5f15b71ce090f8bdf3fbae4f00db22 Mon Sep 17 00:00:00 2001 From: Oleg Petruny Date: Fri, 22 Nov 2024 19:50:49 +0100 Subject: [PATCH] AgeOfWar minigame Co-authored-by: Oleg Petruny Co-committed-by: Oleg Petruny --- .../Lost_Edge/Config/DefaultEngine.ini | 5 + .../Blueprints/Items/BP_CompanionCube.uasset | 4 +- .../AgeOfWar/BP_Minigame_AgeOfWar.uasset | 4 +- .../AgeOfWar/UI_Minigame_AgeOfWar.uasset | 3 + .../BP_Minigame_AgeOfWarUnit_Base.uasset | 3 + ...BP_Minigame_AgeOfWarUnit_FirstMelee.uasset | 3 + ...BP_Minigame_AgeOfWarUnit_FirstRange.uasset | 3 + .../BP_Minigame_AgeOfWarUnit_FirstTank.uasset | 3 + .../Fishing/UI_Minigame_Fishing.uasset | 4 +- .../Lost_Edge/Content/Levels/Test/L_Test.umap | 4 +- .../Levels/Test/L_Test_BuiltData.uasset | 4 +- .../Lost_Edge/Private/CommonFunctions.cpp | 12 ++ .../Lost_Edge/Private/CommonFunctions.h | 2 + .../Private/Interactable/Interactable.cpp | 24 +-- .../Private/Interactable/Interactable.h | 2 +- .../Minigame/AgeOfWar/AgeOfWarManager.cpp | 72 +++++++- .../Minigame/AgeOfWar/AgeOfWarManager.h | 24 +++ .../Minigame/AgeOfWar/AgeOfWarUnit.cpp | 158 ++++++++++++++++++ .../Private/Minigame/AgeOfWar/AgeOfWarUnit.h | 99 +++++++++++ .../Minigame/CrossyRoad/CrossyRoadManager.cpp | 6 +- .../Minigame/SubwaySurf/SubwaySurfManager.cpp | 6 +- 21 files changed, 415 insertions(+), 30 deletions(-) create mode 100644 UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/UI_Minigame_AgeOfWar.uasset create mode 100644 UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_Base.uasset create mode 100644 UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_FirstMelee.uasset create mode 100644 UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_FirstRange.uasset create mode 100644 UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_FirstTank.uasset create mode 100644 UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarUnit.cpp create mode 100644 UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarUnit.h diff --git a/UnrealProject/Lost_Edge/Config/DefaultEngine.ini b/UnrealProject/Lost_Edge/Config/DefaultEngine.ini index fbd6426..c9b460d 100644 --- a/UnrealProject/Lost_Edge/Config/DefaultEngine.ini +++ b/UnrealProject/Lost_Edge/Config/DefaultEngine.ini @@ -139,6 +139,8 @@ 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="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="AgeOfWarUnitPlayer",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="Vehicle",Response=ECR_Ignore),(Channel="Interactable")),HelpMessage="Minigame object") ++Profiles=(Name="AgeOfWarUnitComputer",CollisionEnabled=QueryOnly,bCanModify=True,ObjectTypeName="Destructible",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),(Channel="Interactable")),HelpMessage="Minigame object") +DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="Interactable") -ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall") -ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn") @@ -150,6 +152,9 @@ ManualIPAddress= +ProfileRedirects=(OldName="StaticMeshComponent",NewName="BlockAllDynamic") +ProfileRedirects=(OldName="SkeletalMeshActor",NewName="PhysicsActor") +ProfileRedirects=(OldName="InvisibleActor",NewName="InvisibleWallDynamic") ++ProfileRedirects=(OldName="AgeOfWarUnitComputer",NewName="AgeOfWarUnitPlayerZone") ++ProfileRedirects=(OldName="AgeOfWarUnit",NewName="AgeOfWarUnitPlayer") ++ProfileRedirects=(OldName="AgeOfWarUnitPlayerZone",NewName="AgeOfWarUnitComputer") -CollisionChannelRedirects=(OldName="Static",NewName="WorldStatic") -CollisionChannelRedirects=(OldName="Dynamic",NewName="WorldDynamic") -CollisionChannelRedirects=(OldName="VehicleMovement",NewName="Vehicle") diff --git a/UnrealProject/Lost_Edge/Content/Blueprints/Items/BP_CompanionCube.uasset b/UnrealProject/Lost_Edge/Content/Blueprints/Items/BP_CompanionCube.uasset index b8610db..ba9951d 100644 --- a/UnrealProject/Lost_Edge/Content/Blueprints/Items/BP_CompanionCube.uasset +++ b/UnrealProject/Lost_Edge/Content/Blueprints/Items/BP_CompanionCube.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2b9660bb6e1de93ac49a75a29779ac8bbac2f4230b1aec0f7eca4604a8f79467 -size 23557 +oid sha256:1195d0ee2ffdfd23b58c5b83519c0c26bf91b3df3a623d52411462876b9d9848 +size 25381 diff --git a/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/BP_Minigame_AgeOfWar.uasset b/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/BP_Minigame_AgeOfWar.uasset index 9146144..8ae7155 100644 --- a/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/BP_Minigame_AgeOfWar.uasset +++ b/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/BP_Minigame_AgeOfWar.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f824f9463511401dd695e86e2d6552cd74f848042adb901442355d379a3e6015 -size 20104 +oid sha256:5e9165dea307bfecba98443cb3889799bc4f656fc85e226377392c4fd839cea0 +size 496980 diff --git a/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/UI_Minigame_AgeOfWar.uasset b/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/UI_Minigame_AgeOfWar.uasset new file mode 100644 index 0000000..08c3412 --- /dev/null +++ b/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/UI_Minigame_AgeOfWar.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bd73e8683b46355038b4921e52202d05b44eebfd571f83a1feb38656267e960d +size 212213 diff --git a/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_Base.uasset b/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_Base.uasset new file mode 100644 index 0000000..19d16fb --- /dev/null +++ b/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_Base.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9be205b5bf17894060db9e19a165ef429b0a0a01286c0e166db769dc45376b9b +size 42295 diff --git a/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_FirstMelee.uasset b/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_FirstMelee.uasset new file mode 100644 index 0000000..38b45f8 --- /dev/null +++ b/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_FirstMelee.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a6f29c6ad1559cd22960b40f851bb7873a0e923695c2fab06d02db94d7900e3a +size 23540 diff --git a/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_FirstRange.uasset b/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_FirstRange.uasset new file mode 100644 index 0000000..777ac8b --- /dev/null +++ b/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_FirstRange.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89f21d2809ef7f853839bd572a95c180b5c2668a3243197f9a74bcadc94d6d5d +size 25523 diff --git a/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_FirstTank.uasset b/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_FirstTank.uasset new file mode 100644 index 0000000..06efab6 --- /dev/null +++ b/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/AgeOfWar/Units/BP_Minigame_AgeOfWarUnit_FirstTank.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6a92537e1f82b2e1745b363b518751a61f9efefb223159701950f1f835e1b469 +size 23008 diff --git a/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/Fishing/UI_Minigame_Fishing.uasset b/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/Fishing/UI_Minigame_Fishing.uasset index 64dd046..d45693e 100644 --- a/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/Fishing/UI_Minigame_Fishing.uasset +++ b/UnrealProject/Lost_Edge/Content/Blueprints/Minigames/Fishing/UI_Minigame_Fishing.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0b21c235dd6368de617fd3183dcc5a5b150bbc193c80b4bdf6aba4a3f5b3d6b6 -size 486905 +oid sha256:306c27ad9488349c97e003ec5c4e49d5f3383bd33c407c89ee9dc25dd4039148 +size 486840 diff --git a/UnrealProject/Lost_Edge/Content/Levels/Test/L_Test.umap b/UnrealProject/Lost_Edge/Content/Levels/Test/L_Test.umap index 278e2c4..33667b3 100644 --- a/UnrealProject/Lost_Edge/Content/Levels/Test/L_Test.umap +++ b/UnrealProject/Lost_Edge/Content/Levels/Test/L_Test.umap @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:26ba9021d327e31a02433e566da5b6428681e17f2ae92ad100200f30c073dea3 -size 2257698 +oid sha256:6d6d75c266fe70db878a1a4c8ad461c4f31dd3c92662074f083295eff4bf0d13 +size 2265074 diff --git a/UnrealProject/Lost_Edge/Content/Levels/Test/L_Test_BuiltData.uasset b/UnrealProject/Lost_Edge/Content/Levels/Test/L_Test_BuiltData.uasset index 3bea8a6..216ce28 100644 --- a/UnrealProject/Lost_Edge/Content/Levels/Test/L_Test_BuiltData.uasset +++ b/UnrealProject/Lost_Edge/Content/Levels/Test/L_Test_BuiltData.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9bc37c40c0e26300a7832402eaed47bb71875dce9b428ba2e852c9c80aa98423 -size 19969242 +oid sha256:6aa7b92951a49c50d63d075885fd2b0c00041360b6721a5c84d2a16f68f8c562 +size 586263 diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CommonFunctions.cpp b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CommonFunctions.cpp index 6248b2e..3a5e4fa 100644 --- a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CommonFunctions.cpp +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CommonFunctions.cpp @@ -39,6 +39,18 @@ void UCommonFunctions::DestroyActorRecursively(AActor* actor) actor->Destroy(); } +TArray UCommonFunctions::GetRandomIntArray(int32 size, int32 min, int32 max) +{ + if(size <= 0) + return {}; + + TArray arr; + arr.Reserve(size); + for(int32 i = 0; i < size; ++i) + arr.Add(FMath::RandRange(min, max)); + return arr; +} + ALevelBase* UCommonFunctions::GetCurrentLevelScript(UObject* obj) diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CommonFunctions.h b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CommonFunctions.h index 903cead..b5c9b17 100644 --- a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CommonFunctions.h +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CommonFunctions.h @@ -21,6 +21,8 @@ public: UFUNCTION(BlueprintCallable, Category = Actor) static void DestroyActorRecursively(class AActor* actor); + UFUNCTION(BlueprintPure) + static TArray GetRandomIntArray(int32 size = 16, int32 min = 0, int32 max = 16); UFUNCTION(BlueprintCallable, Category = Level) diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Interactable/Interactable.cpp b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Interactable/Interactable.cpp index 832cae8..1094c03 100644 --- a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Interactable/Interactable.cpp +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Interactable/Interactable.cpp @@ -55,25 +55,25 @@ void AInteractable::BeginPlay() } } - GetComponents(meshes); - for(auto mesh : meshes) + GetComponents(collisions, true); + for(auto collision : collisions) { if(activatorTypes) { - mesh->SetCollisionProfileName(TEXT("Interactable")); + collision->SetCollisionProfileName(TEXT("Interactable")); } if(activatorTypes & static_cast(EActivatorType::Saw)) { - mesh->CustomDepthStencilValue = 128; - mesh->CustomDepthStencilWriteMask = ERendererStencilMask::ERSM_Default; - mesh->SetRenderCustomDepth(true); + collision->CustomDepthStencilValue = 128; + collision->CustomDepthStencilWriteMask = ERendererStencilMask::ERSM_Default; + collision->SetRenderCustomDepth(true); } if(activatorTypes & static_cast(EActivatorType::Use)) { - mesh->CustomDepthStencilWriteMask = ERendererStencilMask::ERSM_Default; - mesh->SetRenderCustomDepth(true); + collision->CustomDepthStencilWriteMask = ERendererStencilMask::ERSM_Default; + collision->SetRenderCustomDepth(true); } } @@ -120,8 +120,8 @@ void AInteractable::_Activate(EActivatorType type) if(activated & static_cast(EActivatorType::Use)) { - for(auto mesh : meshes) - mesh->SetCustomDepthStencilValue(132); + for(auto collision : collisions) + collision->SetCustomDepthStencilValue(132); } Activate(type); @@ -155,8 +155,8 @@ void AInteractable::_Deactivate(EActivatorType type) if(!(activated & static_cast(EActivatorType::Use))) { - for(auto mesh : meshes) - mesh->SetCustomDepthStencilValue(0); + for(auto collision : collisions) + collision->SetCustomDepthStencilValue(0); } Deactivate(type); diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Interactable/Interactable.h b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Interactable/Interactable.h index 33d4358..1b84e93 100644 --- a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Interactable/Interactable.h +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Interactable/Interactable.h @@ -58,7 +58,7 @@ protected: TMap modificators; class APlayerBase* player = nullptr; - TArray meshes; + TArray collisions; }; diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarManager.cpp b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarManager.cpp index e1976ad..659903b 100644 --- a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarManager.cpp +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarManager.cpp @@ -3,11 +3,34 @@ #include "AgeOfWarManager.h" +#include "Camera/CameraComponent.h" +#include "Components/ChildActorComponent.h" + +#include "AgeOfWarUnit.h" #include "MainGameModeBase.h" #include "PlayerBase.h" +TMap AAgeOfWarManager::unitStats = {}; + +const FAgeOfWarUnitStats& AAgeOfWarManager::UnitGetStats(TSubclassOf unitClass) +{ + check(unitStats.Contains(*unitClass)); + //if(!unitStats.Contains(*unitClass)) + //{ + // static FAgeOfWarUnitStats empty; + // return empty; + //} + + return unitStats[unitClass]; +} + AAgeOfWarManager::AAgeOfWarManager() -{} +{ + auto root = CreateDefaultSubobject(TEXT("Scene")); + + camera = CreateDefaultSubobject(TEXT("Camera")); + camera->SetupAttachment(root); +} void AAgeOfWarManager::Start(APlayerBase* playerPawn, FMinigameEndCallback delegate) { @@ -17,11 +40,58 @@ void AAgeOfWarManager::Start(APlayerBase* playerPawn, FMinigameEndCallback deleg AMinigame::Start(playerPawn, delegate); player->LockPlayer(FPlayerLock::All()); + player->SwitchToView(this); + + FillUnitStats(); + TArray units; + GetComponents(units); + for(auto& unit : units) + { + if(auto proxy = Cast(unit->GetChildActor())) + { + proxy->manager = this; + proxy->UpdateStats(); + } + } } void AAgeOfWarManager::End() { + for(auto& unit : spawnedUnits) + unit->Destroy(); + spawnedUnits.Empty(); + + unitStats.Empty(); + + player->ReturnPlayerView(); player->UnlockPlayer(FPlayerLock::All()); AMinigame::End(); } + +void AAgeOfWarManager::UnitKill(AAgeOfWarUnit* unit) +{ + OnUnitKill(unit); + spawnedUnits.Remove(unit); +} + +void AAgeOfWarManager::AddUnitStats(TSubclassOf unitClass, FAgeOfWarUnitStats stats) +{ + unitStats.Add(unitClass, stats); +} + +FAgeOfWarUnitStats AAgeOfWarManager::GetUnitStats(TSubclassOf unitClass) +{ + return UnitGetStats(unitClass); +} + +void AAgeOfWarManager::SpawnUnit(TSubclassOf unitClass, FTransform transform, bool computer) +{ + FActorSpawnParameters spawnParams{}; + spawnParams.Owner = this; + auto unit = GetWorld()->SpawnActor(*unitClass, transform, spawnParams); + unit->team = computer ? UnitTeam::AI : UnitTeam::Player; + unit->manager = this; + unit->UpdateStats(); + spawnedUnits.Add(unit); +} diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarManager.h b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarManager.h index b414c2f..dbcdcb9 100644 --- a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarManager.h +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarManager.h @@ -12,8 +12,32 @@ class AAgeOfWarManager : public AMinigame GENERATED_BODY() public: + static const struct FAgeOfWarUnitStats& UnitGetStats(TSubclassOf unitClass); + AAgeOfWarManager(); virtual void Start(class APlayerBase* playerPawn, FMinigameEndCallback delegate) override; virtual void End() override; + + void UnitKill(class AAgeOfWarUnit* unit); + UFUNCTION(BlueprintImplementableEvent) + void OnUnitKill(class AAgeOfWarUnit* unit); + +protected: + UFUNCTION(BlueprintImplementableEvent) + void FillUnitStats(); + UFUNCTION(BlueprintCallable) + static void AddUnitStats(TSubclassOf unitClass, struct FAgeOfWarUnitStats stats); + UFUNCTION(BlueprintPure) + static struct FAgeOfWarUnitStats GetUnitStats(TSubclassOf unitClass); + + UFUNCTION(BlueprintCallable) + void SpawnUnit(TSubclassOf unitClass, FTransform transform, bool computer = false); + + static TMap unitStats; + + UPROPERTY(EditAnywhere) + class UCameraComponent* camera; + + TSet spawnedUnits; }; diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarUnit.cpp b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarUnit.cpp new file mode 100644 index 0000000..88a4826 --- /dev/null +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarUnit.cpp @@ -0,0 +1,158 @@ +// Oleg Petruny proprietary. + + +#include "AgeOfWarUnit.h" + +#include "Components/StaticMeshComponent.h" + +#include "AgeOfWarManager.h" +#include + +namespace +{ + constexpr auto PlayerCollision = TEXT("AgeOfWarUnitPlayer"); + constexpr auto ComputerCollision = TEXT("AgeOfWarUnitComputer"); + constexpr auto TagNoAuto = TEXT("NoAuto"); +} + +const FAgeOfWarUnitStats& AAgeOfWarUnit::GetStats() +{ + if(!stats) + stats = &AAgeOfWarManager::UnitGetStats(GetClass()); + + return *stats; +} + +void AAgeOfWarUnit::UpdateStats() +{ + health = GetStats().health; + attackStartRange = GetStats().attackStartRange; + + switch(team) + { + case UnitTeam::AI: + root->SetCollisionProfileName(ComputerCollision); + allyblocker->SetCollisionProfileName(PlayerCollision); + break; + case UnitTeam::Player: + root->SetCollisionProfileName(PlayerCollision); + allyblocker->SetCollisionProfileName(ComputerCollision); + break; + default: + break; + } + allyblocker->SetBoxExtent(root->GetUnscaledBoxExtent(), false); + allyblocker->SetCollisionEnabled(ECollisionEnabled::NoCollision); + + OnUpdateStats(); +} + +void AAgeOfWarUnit::BeginPlay() +{ + if(manager) + { + UpdateStats(); + } + + Super::BeginPlay(); + + world = GetWorld(); +} + +void AAgeOfWarUnit::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + Super::EndPlay(EndPlayReason); +} + +AAgeOfWarUnit::AAgeOfWarUnit() +{ + root = CreateDefaultSubobject(TEXT("Collision")); + allyblocker = CreateDefaultSubobject(TEXT("AllyBlocker")); + allyblocker->SetupAttachment(root); + traceStart = CreateDefaultSubobject(TEXT("TraceStart")); + traceStart->SetupAttachment(root); + traceStart->AddRelativeLocation(FVector(0, 0, 200)); + + PrimaryActorTick.bCanEverTick = true; + PrimaryActorTick.bStartWithTickEnabled = true; +} + +void AAgeOfWarUnit::Tick(float deltaTime) +{ + Super::Tick(deltaTime); + + if(!manager || GetStats().moveSpeed <= 0) + return; + + // try move + FHitResult moveHit; + auto moveStep = GetActorForwardVector() * GetStats().moveSpeed; + this->AddActorWorldOffset(moveStep, true, &moveHit, ETeleportType::None); + if(moveHit.bBlockingHit) + allyblocker->SetCollisionEnabled(ECollisionEnabled::QueryOnly); + else + allyblocker->SetCollisionEnabled(ECollisionEnabled::NoCollision); + + // look for units forward + FHitResult hit; + auto startLocation = traceStart->GetComponentLocation(); + auto endLocation = startLocation + (GetActorRotation().Vector() * attackStartRange * (moveHit.bBlockingHit ? 5 : 1)); + world->LineTraceSingleByChannel( + hit, + startLocation, + endLocation, + ECollisionChannel::ECC_GameTraceChannel1 + ); + DrawDebugLine(GetWorld(), startLocation, endLocation, FColor::Red, false, deltaTime * 10, 0, 4.0f); + + // check if blocked + if(!hit.bBlockingHit) + return; + + forwardUnit = Cast(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().attackUnitDistance; 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); + } + GEngine->AddOnScreenDebugMessage(4, 5.0f, FColor::Yellow, FString::Printf(TEXT("Time %f"), lastAttackTimestamp + GetStats().attackRate - FPlatformTime::Seconds())); +} + +void AAgeOfWarUnit::Damage(const int32 damage) +{ + if(killed) + return; + + GEngine->AddOnScreenDebugMessage((int32)GetClass()->GetUniqueID(), 5.0f, FColor::Yellow, FString::Printf(TEXT("%d"), health)); + + health -= damage; + + if(health > 0) + return; + + killed = true; + + if(IsValid(manager)) + { + manager->UnitKill(this); + } + else + { + Destroy(); + } +} diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarUnit.h b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarUnit.h new file mode 100644 index 0000000..1184f8e --- /dev/null +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/AgeOfWar/AgeOfWarUnit.h @@ -0,0 +1,99 @@ +// 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 attackUnitDistance = 1; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + float attackStartRange = 100; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + float attackRate = 1.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + int32 unitSize = 1; + +}; + +UENUM(BlueprintType) +enum class UnitTeam : uint8 +{ + Player, + AI +}; + +UCLASS(Blueprintable, MinimalAPI, Abstract) +class AAgeOfWarUnit : public AActor +{ + GENERATED_BODY() + +public: + AAgeOfWarUnit(); + virtual void Tick(float deltaTime) override; + + UFUNCTION(BlueprintPure) + const FAgeOfWarUnitStats& GetStats(); + + UFUNCTION(BlueprintCallable) + void UpdateStats(); + + const FAgeOfWarUnitStats* stats = nullptr; + class AAgeOfWarManager* manager = nullptr; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + UnitTeam team; + +protected: + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + + UFUNCTION(BlueprintImplementableEvent) + void OnUpdateStats(); + + void Damage(const int32 damage); + + AAgeOfWarUnit* forwardUnit = nullptr; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + class UBoxComponent* root; + UPROPERTY(EditAnywhere, BlueprintReadWrite) + class UBoxComponent* allyblocker; + + UPROPERTY(EditAnywhere) + class USceneComponent* traceStart; + +private: + int32 health; + float attackStartRange; + FTimerHandle attackTimer; + double lastAttackTimestamp = 0; + + UWorld* world; + bool killed = false; +}; + diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/CrossyRoad/CrossyRoadManager.cpp b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/CrossyRoad/CrossyRoadManager.cpp index 1c6a8e7..c7794e6 100644 --- a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/CrossyRoad/CrossyRoadManager.cpp +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/CrossyRoad/CrossyRoadManager.cpp @@ -24,13 +24,13 @@ ACrossyRoadManager::ACrossyRoadManager() auto root = CreateDefaultSubobject(TEXT("Scene")); playerPos = CreateDefaultSubobject(TEXT("PlayerPos")); - playerPos->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform); + playerPos->SetupAttachment(root); camera = CreateDefaultSubobject(TEXT("Camera")); - camera->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform); + camera->SetupAttachment(root); mannequin = CreateDefaultSubobject(TEXT("Mannequin")); - mannequin->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform); + mannequin->SetupAttachment(root); } void ACrossyRoadManager::Start(APlayerBase* playerPawn, FMinigameEndCallback delegate) diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/SubwaySurf/SubwaySurfManager.cpp b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/SubwaySurf/SubwaySurfManager.cpp index 16b8f00..9b0746a 100644 --- a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/SubwaySurf/SubwaySurfManager.cpp +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Minigame/SubwaySurf/SubwaySurfManager.cpp @@ -24,13 +24,13 @@ ASubwaySurfManager::ASubwaySurfManager() auto root = CreateDefaultSubobject(TEXT("Scene")); playerPos = CreateDefaultSubobject(TEXT("PlayerPos")); - playerPos->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform); + playerPos->SetupAttachment(root); camera = CreateDefaultSubobject(TEXT("Camera")); - camera->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform); + camera->SetupAttachment(root); mannequin = CreateDefaultSubobject(TEXT("Mannequin")); - mannequin->AttachToComponent(root, FAttachmentTransformRules::KeepRelativeTransform); + mannequin->SetupAttachment(root); } void ASubwaySurfManager::Start(APlayerBase* playerPawn, FMinigameEndCallback delegate)