diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index 78a206a..4390a71 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -5,7 +5,7 @@ GameDefaultMap=/Game/Levels/Test/L_Test.L_Test EditorStartupMap=/Game/Levels/Test/L_Test.L_Test bUseSplitscreen=False GlobalDefaultGameMode=/Game/Blueprints/GameModes/BP_MainGameMode.BP_MainGameMode_C -GameInstanceClass=/Game/Blueprints/Other/BP_CustomGameInstance.BP_CustomGameInstance_C +GameInstanceClass=/Game/Blueprints/BP_CustomGameInstance.BP_CustomGameInstance_C [/Script/WindowsTargetPlatform.WindowsTargetSettings] DefaultGraphicsRHI=DefaultGraphicsRHI_DX12 diff --git a/Config/DefaultInput.ini b/Config/DefaultInput.ini index ca152e1..19855f7 100644 --- a/Config/DefaultInput.ini +++ b/Config/DefaultInput.ini @@ -78,6 +78,7 @@ DefaultViewportMouseCaptureMode=CapturePermanently_IncludingInitialMouseDown DefaultViewportMouseLockMode=LockOnCapture FOVScale=0.011110 DoubleClickTime=0.200000 ++ActionMappings=(ActionName="AnyKey",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=AnyKey) DefaultPlayerInputClass=/Script/EnhancedInput.EnhancedPlayerInput DefaultInputComponentClass=/Script/EnhancedInput.EnhancedInputComponent DefaultTouchInterface=/Engine/MobileResources/HUD/DefaultVirtualJoysticks.DefaultVirtualJoysticks diff --git a/Content/Blueprints/BP_CustomGameInstance.uasset b/Content/Blueprints/BP_CustomGameInstance.uasset new file mode 100644 index 0000000..005913a --- /dev/null +++ b/Content/Blueprints/BP_CustomGameInstance.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0de06017dc169ae344130998119b1fef2cea5199f48e6e024474df02958eb1dd +size 6180 diff --git a/Content/Blueprints/Characters/BP_Player.uasset b/Content/Blueprints/Characters/BP_Player.uasset index df20519..d247c0e 100644 --- a/Content/Blueprints/Characters/BP_Player.uasset +++ b/Content/Blueprints/Characters/BP_Player.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dbb801ad73a6c2185db8942117e3b658a1f4f932d5f5f6da2b6b967a7585bf42 -size 490439 +oid sha256:90fcefd43bc5ac2aa88805027849546be24f36ef62faa0274c6a763687ec1495 +size 490589 diff --git a/Content/Blueprints/GameModes/BP_MainGameMode.uasset b/Content/Blueprints/GameModes/BP_MainGameMode.uasset index c1ba1d7..a5c46c6 100644 Binary files a/Content/Blueprints/GameModes/BP_MainGameMode.uasset and b/Content/Blueprints/GameModes/BP_MainGameMode.uasset differ diff --git a/Content/Blueprints/Other/BP_CustomGameInstance.uasset b/Content/Blueprints/Other/BP_CustomGameInstance.uasset deleted file mode 100644 index 9a44e6f..0000000 Binary files a/Content/Blueprints/Other/BP_CustomGameInstance.uasset and /dev/null differ diff --git a/Content/Levels/Test/Actors/QuickTimeEventTest/BP_Test_QTEHold.uasset b/Content/Levels/Test/Actors/QuickTimeEventTest/BP_Test_QTEHold.uasset new file mode 100644 index 0000000..99c00db --- /dev/null +++ b/Content/Levels/Test/Actors/QuickTimeEventTest/BP_Test_QTEHold.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:822cd9f7904f60ae7660b7e6955cc79094d4313591f44089fc746356d6d5ac77 +size 61073 diff --git a/Content/Levels/Test/Actors/QuickTimeEventTest/BP_Test_QTEMulti.uasset b/Content/Levels/Test/Actors/QuickTimeEventTest/BP_Test_QTEMulti.uasset new file mode 100644 index 0000000..f38dec6 --- /dev/null +++ b/Content/Levels/Test/Actors/QuickTimeEventTest/BP_Test_QTEMulti.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0a57408effd911a48809e2423c06f6e23425b2af9f5fa0746dd365c5aeade55b +size 61238 diff --git a/Content/Levels/Test/Actors/QuickTimeEventTest/BP_Test_QTESingle.uasset b/Content/Levels/Test/Actors/QuickTimeEventTest/BP_Test_QTESingle.uasset new file mode 100644 index 0000000..1a5ffe4 --- /dev/null +++ b/Content/Levels/Test/Actors/QuickTimeEventTest/BP_Test_QTESingle.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:558c84fe46db65f5ab76797c6b5d649a52e30b5cdc114018c32738696abe00b6 +size 59913 diff --git a/Content/Levels/Test/L_Test.umap b/Content/Levels/Test/L_Test.umap index c102713..c573f40 100644 --- a/Content/Levels/Test/L_Test.umap +++ b/Content/Levels/Test/L_Test.umap @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94e0ccda50b0109428a8364a0e201c8853ceda986185538fe2b3a44070717b99 -size 2080437 +oid sha256:2e4b551c8a5619b92644fb1ef11c2b8302b7400e4cb1c53a4beb539e633239d4 +size 2094425 diff --git a/Content/Levels/Test/Sequences/Seq_TestCutscene.uasset b/Content/Levels/Test/Sequences/Seq_TestCutscene.uasset index fa3a336..b4fb5fa 100644 Binary files a/Content/Levels/Test/Sequences/Seq_TestCutscene.uasset and b/Content/Levels/Test/Sequences/Seq_TestCutscene.uasset differ diff --git a/Content/Levels/Test/Sequences/Seq_Test_Ball.uasset b/Content/Levels/Test/Sequences/Seq_Test_Ball.uasset new file mode 100644 index 0000000..dcfabe0 --- /dev/null +++ b/Content/Levels/Test/Sequences/Seq_Test_Ball.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:46b3c0ac81e300f45253aab6fccaac77d9e60826af2b4c2c8fedf488441808b8 +size 17474 diff --git a/Content/Levels/Test/Sequences/Seq_Test_Cutscene.uasset b/Content/Levels/Test/Sequences/Seq_Test_Cutscene.uasset new file mode 100644 index 0000000..0674be6 --- /dev/null +++ b/Content/Levels/Test/Sequences/Seq_Test_Cutscene.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f685556de20f533223fec1c179d9c1d23b1e6529589663e5186afd74f0b31f20 +size 28314 diff --git a/Content/Misc/ImportTest/M_ImportTest_BarelWood.uasset b/Content/Misc/ImportTest/M_ImportTest_BarelWood.uasset index 3393317..f52518a 100644 Binary files a/Content/Misc/ImportTest/M_ImportTest_BarelWood.uasset and b/Content/Misc/ImportTest/M_ImportTest_BarelWood.uasset differ diff --git a/Content/Misc/ImportTest/M_ImportTest_BarrelRings.uasset b/Content/Misc/ImportTest/M_ImportTest_BarrelRings.uasset index 46914ca..bdda9ad 100644 Binary files a/Content/Misc/ImportTest/M_ImportTest_BarrelRings.uasset and b/Content/Misc/ImportTest/M_ImportTest_BarrelRings.uasset differ diff --git a/Content/Misc/ImportTest/SM_ImportTest_Barrel.uasset b/Content/Misc/ImportTest/SM_ImportTest_Barrel.uasset index 56a1632..77ff968 100644 Binary files a/Content/Misc/ImportTest/SM_ImportTest_Barrel.uasset and b/Content/Misc/ImportTest/SM_ImportTest_Barrel.uasset differ diff --git a/Content/UI/BP_MainWidgetManager.uasset b/Content/UI/BP_MainWidgetManager.uasset index 47d2a79..d4d2dca 100644 --- a/Content/UI/BP_MainWidgetManager.uasset +++ b/Content/UI/BP_MainWidgetManager.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fece22575c825ac5fc7c3c5b557d8d7254eeb0c0df782ee0efb405d139fb73bf -size 7670 +oid sha256:e95c10c69373b3a62ba6d80f00db0455308691cf9c0e2afc92c52aa9f3054ab6 +size 7924 diff --git a/Content/UI/Blueprints/QuickTimeEvents/UI_QuickTimeEventHold.uasset b/Content/UI/Blueprints/QuickTimeEvents/UI_QuickTimeEventHold.uasset new file mode 100644 index 0000000..c8eacc9 --- /dev/null +++ b/Content/UI/Blueprints/QuickTimeEvents/UI_QuickTimeEventHold.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:30a837a7fe827490e8148ec663414b5e5612becc216c6544513e5eb2155bc073 +size 251965 diff --git a/Content/UI/Blueprints/QuickTimeEvents/UI_QuickTimeEventManager.uasset b/Content/UI/Blueprints/QuickTimeEvents/UI_QuickTimeEventManager.uasset new file mode 100644 index 0000000..ebf4a56 --- /dev/null +++ b/Content/UI/Blueprints/QuickTimeEvents/UI_QuickTimeEventManager.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:01f806c091882a3cfddb091d916edc13f67d8bfc1165d935099d5d46edbef7a3 +size 10666 diff --git a/Content/UI/Blueprints/QuickTimeEvents/UI_QuickTimeEventMultiPress.uasset b/Content/UI/Blueprints/QuickTimeEvents/UI_QuickTimeEventMultiPress.uasset new file mode 100644 index 0000000..8e2686b --- /dev/null +++ b/Content/UI/Blueprints/QuickTimeEvents/UI_QuickTimeEventMultiPress.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bbcf0e01d1d3cc1e40f61eb4b536c89359ea968a1c7d3b020a5a7627399bc416 +size 351912 diff --git a/Content/UI/Blueprints/QuickTimeEvents/UI_QuickTimeEventSinglePress.uasset b/Content/UI/Blueprints/QuickTimeEvents/UI_QuickTimeEventSinglePress.uasset new file mode 100644 index 0000000..483b989 --- /dev/null +++ b/Content/UI/Blueprints/QuickTimeEvents/UI_QuickTimeEventSinglePress.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0da81077ad80d95af826c0fa230c23912ef06f5822f6e1d5ce3df3cc366cadbc +size 232152 diff --git a/Source/Lost_Edge/Private/CommonFunctions.cpp b/Source/Lost_Edge/Private/CommonFunctions.cpp index 7309572..b106373 100644 --- a/Source/Lost_Edge/Private/CommonFunctions.cpp +++ b/Source/Lost_Edge/Private/CommonFunctions.cpp @@ -7,6 +7,7 @@ #include "Kismet/GameplayStatics.h" #include "UObject/Object.h" +#include "CustomGameInstanceBase.h" #include "Levels/LevelBase.h" #include "PlayerBase.h" @@ -42,17 +43,78 @@ void UCommonFunctions::DestroyActorRecursively(AActor* actor) ALevelBase* UCommonFunctions::GetCurrentLevelScript(UObject* obj) { - if(auto world = obj->GetWorld()) - if(auto level = world->GetCurrentLevel()) - if(auto script = level->GetLevelScriptActor()) - return Cast(script); + if(obj) + if(auto world = obj->GetWorld()) + if(auto level = world->GetCurrentLevel()) + if(auto script = level->GetLevelScriptActor()) + return Cast(script); return nullptr; } APlayerBase* UCommonFunctions::GetPlayer(UObject* obj) { - if(auto pc = UGameplayStatics::GetPlayerController(obj->GetWorld(), 0)) - if(auto pawn = pc->GetPawn()) - return Cast(pawn); + if(obj) + if(auto pc = UGameplayStatics::GetPlayerController(obj->GetWorld(), 0)) + if(auto pawn = pc->GetPawn()) + return Cast(pawn); return nullptr; } + + + +namespace SlowMotion +{ + FTimerHandle timer; + float targetDilation; + FWorldDilationChangedDelegate worldDilationChangedDelegate; +} + +void UCommonFunctions::EnterSlowMotion(float duration) +{ + if(SlowMotion::targetDilation == SlowMotion::slowDilation) + return; + + SlowMotion::targetDilation = SlowMotion::slowDilation; + + auto GI = UCustomGameInstanceBase::GetGameInstance(); + if(!GI) + return; + + auto world = GI->GetWorld(); + world->GetTimerManager().SetTimer(SlowMotion::timer, []() { SlowMotionTick(); }, 0.01f, true); // wrapped in lambda due to some template function class referencing +} + +void UCommonFunctions::ExitSlowMotion(float duration) +{ + if(SlowMotion::targetDilation == SlowMotion::normalDilation) + return; + + SlowMotion::targetDilation = SlowMotion::normalDilation; + + auto GI = UCustomGameInstanceBase::GetGameInstance(); + if(!GI) + return; + + auto world = GI->GetWorld(); + world->GetTimerManager().SetTimer(SlowMotion::timer, []() { SlowMotionTick(); }, 0.01f, true); +} + +FWorldDilationChangedDelegate& UCommonFunctions::GetWorldDilationChangedDelegate() +{ + return SlowMotion::worldDilationChangedDelegate; +} + +void UCommonFunctions::SlowMotionTick() +{ + const UWorld* world = UCustomGameInstanceBase::GetGameInstance()->GetWorld(); + const float currentDilation = UGameplayStatics::GetGlobalTimeDilation(world); + float newDilation = FMath::FInterpTo(currentDilation, SlowMotion::targetDilation, 1, SlowMotion::interpolationSpeed); + + UGameplayStatics::SetGlobalTimeDilation(world, newDilation); + SlowMotion::worldDilationChangedDelegate.Broadcast(newDilation); + if(FMath::IsNearlyEqual(newDilation, SlowMotion::targetDilation, UE_KINDA_SMALL_NUMBER)) + { + UGameplayStatics::SetGlobalTimeDilation(world, SlowMotion::targetDilation); + world->GetTimerManager().ClearTimer(SlowMotion::timer); + } +} diff --git a/Source/Lost_Edge/Private/CommonFunctions.h b/Source/Lost_Edge/Private/CommonFunctions.h index bfb0136..40c5160 100644 --- a/Source/Lost_Edge/Private/CommonFunctions.h +++ b/Source/Lost_Edge/Private/CommonFunctions.h @@ -6,6 +6,8 @@ #include "CommonFunctions.generated.h" +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWorldDilationChangedDelegate, float, newDilation); + UCLASS() class UCommonFunctions : public UBlueprintFunctionLibrary { @@ -26,4 +28,23 @@ public: UFUNCTION(BlueprintCallable, Category = Player) static class APlayerBase* GetPlayer(class UObject* obj); + + UFUNCTION(BlueprintCallable, Category = World) + static void EnterSlowMotion(float duration = 1.0f); + + UFUNCTION(BlueprintCallable, Category = World) + static void ExitSlowMotion(float duration = 1.0f); + + static FWorldDilationChangedDelegate& GetWorldDilationChangedDelegate(); + +private: + static void SlowMotionTick(); + }; + +namespace SlowMotion +{ + constexpr float normalDilation = 1.0f; + constexpr float slowDilation = 0.2f; + constexpr float interpolationSpeed = 0.1f; +} diff --git a/Source/Lost_Edge/Private/Levels/Level3.cpp b/Source/Lost_Edge/Private/Levels/Level3.cpp index de192b4..b80c2f3 100644 --- a/Source/Lost_Edge/Private/Levels/Level3.cpp +++ b/Source/Lost_Edge/Private/Levels/Level3.cpp @@ -14,8 +14,6 @@ void ALevel3::BeginPlay() { - AMainGameModeBase::leadLevel = this; - ALevelBase::BeginPlay(); CallNextState(); diff --git a/Source/Lost_Edge/Private/Levels/Level4.cpp b/Source/Lost_Edge/Private/Levels/Level4.cpp index 23192d8..b9f2b62 100644 --- a/Source/Lost_Edge/Private/Levels/Level4.cpp +++ b/Source/Lost_Edge/Private/Levels/Level4.cpp @@ -14,8 +14,6 @@ void ALevel4::BeginPlay() { - AMainGameModeBase::leadLevel = this; - ALevelBase::BeginPlay(); CallNextState(); diff --git a/Source/Lost_Edge/Private/Levels/Level5.cpp b/Source/Lost_Edge/Private/Levels/Level5.cpp index cf03d92..cfe7740 100644 --- a/Source/Lost_Edge/Private/Levels/Level5.cpp +++ b/Source/Lost_Edge/Private/Levels/Level5.cpp @@ -14,8 +14,6 @@ void ALevel5::BeginPlay() { - AMainGameModeBase::leadLevel = this; - ALevelBase::BeginPlay(); CallNextState(); diff --git a/Source/Lost_Edge/Private/Levels/LevelBase.cpp b/Source/Lost_Edge/Private/Levels/LevelBase.cpp index abad90f..10acc8f 100644 --- a/Source/Lost_Edge/Private/Levels/LevelBase.cpp +++ b/Source/Lost_Edge/Private/Levels/LevelBase.cpp @@ -18,7 +18,7 @@ void ALevelBase::BeginPlay() { - AMainGameModeBase::leadLevel = this; + AMainGameModeBase::leadLevel = TStrongObjectPtr{ this }; if(auto world = GetWorld()) { diff --git a/Source/Lost_Edge/Private/MainGameModeBase.cpp b/Source/Lost_Edge/Private/MainGameModeBase.cpp index 86138ba..1e8056c 100644 --- a/Source/Lost_Edge/Private/MainGameModeBase.cpp +++ b/Source/Lost_Edge/Private/MainGameModeBase.cpp @@ -13,20 +13,23 @@ #include "DialogueManager.h" #include "Levels/LevelBase.h" #include "QuestManager.h" +#include "QuickTimeEvent.h" #include "Widgets/WidgetsManager.h" -UWidgetsManager* AMainGameModeBase::_widgetsManager = nullptr; -UCutsceneManager* AMainGameModeBase::_cutsceneManager = nullptr; -UDialogueManager* AMainGameModeBase::_dialogueManager = nullptr; -UQuestManager* AMainGameModeBase::_questManager = nullptr; -ALevelBase* AMainGameModeBase::leadLevel = nullptr; +TStrongObjectPtr AMainGameModeBase::_widgetsManager = nullptr; +TStrongObjectPtr AMainGameModeBase::_cutsceneManager = nullptr; +TStrongObjectPtr AMainGameModeBase::_quickTimeEventManager = nullptr; +TStrongObjectPtr AMainGameModeBase::_dialogueManager = nullptr; +TStrongObjectPtr AMainGameModeBase::_questManager = nullptr; +TStrongObjectPtr AMainGameModeBase::leadLevel = nullptr; void AMainGameModeBase::StartPlay() { - _widgetsManager = NewObject(this, widgetManagerClass); - _cutsceneManager = NewObject(this); - _dialogueManager = NewObject(this); - _questManager = NewObject(this); + _widgetsManager = TStrongObjectPtr{ NewObject(this, widgetManagerClass) }; + _cutsceneManager = TStrongObjectPtr{ NewObject(this) }; + _quickTimeEventManager = TStrongObjectPtr{ NewObject(this) }; + _dialogueManager = TStrongObjectPtr{ NewObject(this) }; + _questManager = TStrongObjectPtr{ NewObject(this) }; AGameModeBase::StartPlay(); @@ -58,16 +61,21 @@ bool AMainGameModeBase::SetPause(APlayerController* PC, FCanUnpause CanUnpauseDe UWidgetsManager* AMainGameModeBase::GetWidgetsManager() { - return _widgetsManager; + return _widgetsManager.Get(); } UCutsceneManager* AMainGameModeBase::GetCutsceneManager() { - return _cutsceneManager; + return _cutsceneManager.Get(); +} + +UQuickTimeEventManager* AMainGameModeBase::GetQuickTimeEventManager() +{ + return _quickTimeEventManager.Get(); } UDialogueManager* AMainGameModeBase::GetDialogueManager() { - return _dialogueManager; + return _dialogueManager.Get(); } void AMainGameModeBase::CallNextLevelState() diff --git a/Source/Lost_Edge/Private/MainGameModeBase.h b/Source/Lost_Edge/Private/MainGameModeBase.h index 503e960..80d0661 100644 --- a/Source/Lost_Edge/Private/MainGameModeBase.h +++ b/Source/Lost_Edge/Private/MainGameModeBase.h @@ -23,6 +23,8 @@ public: UFUNCTION(BlueprintPure) static class UCutsceneManager* GetCutsceneManager(); UFUNCTION(BlueprintPure) + static class UQuickTimeEventManager* GetQuickTimeEventManager(); + UFUNCTION(BlueprintPure) static class UDialogueManager* GetDialogueManager(); UFUNCTION(BlueprintCallable) @@ -32,7 +34,7 @@ public: void SwitchCameraMode(); - static class ALevelBase* leadLevel; + static TStrongObjectPtr leadLevel; FQuestsUpdateDelegate questsUpdateDelegate; @@ -41,8 +43,9 @@ protected: TSubclassOf widgetManagerClass; private: - static class UWidgetsManager* _widgetsManager; - static class UCutsceneManager* _cutsceneManager; - static class UDialogueManager* _dialogueManager; - static class UQuestManager* _questManager; + static TStrongObjectPtr _widgetsManager; + static TStrongObjectPtr _cutsceneManager; + static TStrongObjectPtr _quickTimeEventManager; + static TStrongObjectPtr _dialogueManager; + static TStrongObjectPtr _questManager; }; diff --git a/Source/Lost_Edge/Private/PlayerBase.cpp b/Source/Lost_Edge/Private/PlayerBase.cpp index 79780ed..07dda52 100644 --- a/Source/Lost_Edge/Private/PlayerBase.cpp +++ b/Source/Lost_Edge/Private/PlayerBase.cpp @@ -12,6 +12,7 @@ #include "Kismet/GameplayStatics.h" #include "Kismet/KismetMathLibrary.h" + #include "CustomGameInstanceBase.h" #include "CustomGameUserSettings.h" #include "Interactable/Activators/InteractableActivator.h" @@ -87,8 +88,6 @@ void APlayerBase::BeginPlay() playerController = Cast(GetController()); if(playerController) { - inputComponent = Cast(playerController->InputComponent);; - if(auto inputSubsystem = ULocalPlayer::GetSubsystem(playerController->GetLocalPlayer())) { if(auto GI = Cast(GetWorld()->GetGameInstance())) @@ -100,11 +99,30 @@ void APlayerBase::BeginPlay() } } } + + inputComponent = Cast(playerController->InputComponent); + if(inputComponent) + { + ((UInputComponent*)inputComponent)->BindAction(TEXT("AnyKey"), IE_Pressed, this, &APlayerBase::OnAnyKeyPressed); + ((UInputComponent*)inputComponent)->BindAction(TEXT("AnyKey"), IE_Released, this, &APlayerBase::OnAnyKeyReleased); + } } LoadInteractablesActivators(); } +void APlayerBase::OnAnyKeyPressed(FKey key) +{ + if(onAnyKeyPressedDelegate.IsBound()) + onAnyKeyPressedDelegate.Broadcast(key); +} + +void APlayerBase::OnAnyKeyReleased(FKey key) +{ + if(onAnyKeyReleasedDelegate.IsBound()) + onAnyKeyReleasedDelegate.Broadcast(key); +} + bool APlayerBase::IsMoving() { return bIsMoving; diff --git a/Source/Lost_Edge/Private/PlayerBase.h b/Source/Lost_Edge/Private/PlayerBase.h index 69d7028..8c3590c 100644 --- a/Source/Lost_Edge/Private/PlayerBase.h +++ b/Source/Lost_Edge/Private/PlayerBase.h @@ -8,6 +8,8 @@ enum class EActivatorType : uint8; +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPlayerAnyKeyPressedDelegate, FKey, key); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPlayerAnyKeyReleasedDelegate, FKey, key); DECLARE_DYNAMIC_MULTICAST_DELEGATE(FPlayerMovedDelegate); USTRUCT(BlueprintType) @@ -63,6 +65,9 @@ public: FPlayerMovedDelegate OnPlayerMoved; FVector moveVector; + FPlayerAnyKeyPressedDelegate onAnyKeyPressedDelegate; + FPlayerAnyKeyReleasedDelegate onAnyKeyReleasedDelegate; + class UEnhancedInputComponent* inputComponent = nullptr; class AActor* leftPocketItem = nullptr; @@ -71,6 +76,9 @@ public: protected: virtual void BeginPlay() override; + void OnAnyKeyPressed(FKey key); + void OnAnyKeyReleased(FKey key); + UFUNCTION(BlueprintCallable, Category = CameraMode) void SwitchToCameraPawn(); diff --git a/Source/Lost_Edge/Private/QuickTimeEvent.cpp b/Source/Lost_Edge/Private/QuickTimeEvent.cpp new file mode 100644 index 0000000..333f9d3 --- /dev/null +++ b/Source/Lost_Edge/Private/QuickTimeEvent.cpp @@ -0,0 +1,182 @@ +// Oleg Petruny proprietary. + + +#include "QuickTimeEvent.h" + +#include "Kismet/GameplayStatics.h" + +#include "CommonFunctions.h" +#include "MainGameModeBase.h" +#include "PlayerBase.h" +#include "Widgets/WidgetsManager.h" + +int32 Event::counter = 0; + +Event::Event() +{ + _id = counter++; +} + +Event::Event(EQuickTimeEventType type, FKey& key, FQuickTimeEventEndCallback& callback, bool sequence) + : Event() +{ + this->type = type; + this->key = key; + this->callback = callback; + this->sequence = sequence; +} + +inline int32 Event::GetId() +{ + return _id; +} + +void UQuickTimeEventManager::ShowQuickTimeEvent(FQuickTimeEventEnqueProperties properties) +{ + UE_LOG(LogTemp, Log, TEXT("ShowQuickTimeEvent Start")); + OnFirstEventInit(); + FScopeLock lock1(&_lock); + CreateEvent(properties, false); + UE_LOG(LogTemp, Log, TEXT("ShowQuickTimeEvent End")); +} + +void UQuickTimeEventManager::EnqueQuickTimeEvent(FQuickTimeEventEnqueProperties properties) +{ + UE_LOG(LogTemp, Log, TEXT("EnqueQuickTimeEvent Start")); + OnFirstEventInit(); + { + FScopeLock lock1(&_lock); + _nextEvents.Enqueue(properties); + } + ShowNextEvent(); + UE_LOG(LogTemp, Log, TEXT("EnqueQuickTimeEvent End")); +} + +void UQuickTimeEventManager::ShowNextEvent() +{ + UE_LOG(LogTemp, Log, TEXT("ShowNextEvent Start")); + FScopeLock lock1(&_lock); + FQuickTimeEventEnqueProperties properties; + _nextEvents.Dequeue(properties); + CreateEvent(properties, true); + UE_LOG(LogTemp, Log, TEXT("ShowNextEvent End")); +} + +void UQuickTimeEventManager::OnEventEnd(int32 id, EQuickTimeEventResult result) +{ + UE_LOG(LogTemp, Log, TEXT("OnEventEnd Start")); + FScopeLock lock1(&_lock); + Event event; + if(!_events.RemoveAndCopyValue(id, event)) + return; + + GetWorld()->GetTimerManager().ClearTimer(event.timer); + + if(event.callback.IsBound()) + event.callback.Execute(result); + + if(event.sequence && !_nextEvents.IsEmpty()) + { + ShowNextEvent(); + UE_LOG(LogTemp, Log, TEXT("OnEventEnd End")); + return; + } + + if(_events.IsEmpty()) + { + if(auto player = UCommonFunctions::GetPlayer(this)) + { + player->onAnyKeyPressedDelegate.RemoveDynamic(this, &UQuickTimeEventManager::OnInputPressed); + player->onAnyKeyReleasedDelegate.RemoveDynamic(this, &UQuickTimeEventManager::OnInputReleased); + } + UCommonFunctions::ExitSlowMotion(); + } + UE_LOG(LogTemp, Log, TEXT("OnEventEnd End")); +} + +void UQuickTimeEventManager::OnInput(const FKey& key, bool released) +{ + for(auto eventMapping : _events) + { + if(eventMapping.Value.key == key) + { + EQuickTimeEventResult result = EQuickTimeEventResult::Success; + + if(auto WM = AMainGameModeBase::GetWidgetsManager()) + { + result = WM->ProcessQuickTimeEvent(eventMapping.Key, released); + + switch(result) + { + case EQuickTimeEventResult::FailedKey: // its not a failed key, but special state to do nothing (eg. holding event) + return; + default: + // the result is success or failed time and widget is self removed + break; + } + } + + OnEventEnd(eventMapping.Key, result); + return; + } + } + + if(released) + return; + + if(auto WM = AMainGameModeBase::GetWidgetsManager()) + { + while(_events.Num() > 0) + { + WM->RemoveQuickTimeEvent(_events.begin()->Key); + OnEventEnd(_events.begin()->Key, EQuickTimeEventResult::FailedKey); + } + } + else + { + while(_events.Num() > 0) + OnEventEnd(_events.begin()->Key, EQuickTimeEventResult::FailedKey); + } +} + +void UQuickTimeEventManager::OnInputPressed(FKey key) +{ + OnInput(key, false); +} + +void UQuickTimeEventManager::OnInputReleased(FKey key) +{ + OnInput(key, true); +} + +void UQuickTimeEventManager::OnFirstEventInit() +{ + if(_events.IsEmpty()) + { + if(auto player = UCommonFunctions::GetPlayer(this)) + { + GetWorld()->GetTimerManager().SetTimerForNextTick([manager = this, player = player]() + { + player->onAnyKeyPressedDelegate.AddDynamic(manager, &UQuickTimeEventManager::OnInputPressed); + player->onAnyKeyReleasedDelegate.AddDynamic(manager, &UQuickTimeEventManager::OnInputReleased); + }); + } + UCommonFunctions::EnterSlowMotion(); + } +} + +void UQuickTimeEventManager::CreateEvent(FQuickTimeEventEnqueProperties& properties, bool sequence) +{ + Event event{ properties.type, properties.key, properties.callback, sequence }; + GetWorld()->GetTimerManager().SetTimer(event.timer, [id = event.GetId(), manager = this]() + { + EQuickTimeEventResult result = EQuickTimeEventResult::FailedTime; + if(auto WM = AMainGameModeBase::GetWidgetsManager()) + result = WM->RemoveQuickTimeEvent(id); + manager->OnEventEnd(id, result); + }, properties.duration, false); + _events.Add(event.GetId(), event); + + if(auto WM = AMainGameModeBase::GetWidgetsManager()) + WM->ShowQuickTimeEvent(event.GetId(), properties); +} diff --git a/Source/Lost_Edge/Private/QuickTimeEvent.h b/Source/Lost_Edge/Private/QuickTimeEvent.h new file mode 100644 index 0000000..bdc0006 --- /dev/null +++ b/Source/Lost_Edge/Private/QuickTimeEvent.h @@ -0,0 +1,95 @@ +// Oleg Petruny proprietary. + +#pragma once + +#include "UObject/Object.h" + +#include "QuickTimeEvent.generated.h" + +UENUM(BlueprintType) +enum class EQuickTimeEventType : uint8 +{ + SinglePress, + MultiPress, + Hold +}; + +UENUM(BlueprintType) +enum class EQuickTimeEventResult : uint8 +{ + Success, + FailedTime, + FailedKey +}; + +DECLARE_DYNAMIC_DELEGATE_OneParam(FQuickTimeEventEndCallback, EQuickTimeEventResult, result); + +USTRUCT(BlueprintType) +struct FQuickTimeEventEnqueProperties +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + EQuickTimeEventType type = EQuickTimeEventType::SinglePress; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + FKey key = EKeys::F; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + float duration = 1.0f; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + FVector2D anchor = FVector2D::Unit45Deg; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + FQuickTimeEventEndCallback callback; +}; + +struct Event +{ +public: + Event(); + Event(EQuickTimeEventType type, FKey& key, FQuickTimeEventEndCallback& callback, bool sequence); + + inline int32 GetId(); + + EQuickTimeEventType type; + FKey key; + FTimerHandle timer; + FQuickTimeEventEndCallback callback; + bool sequence; + +private: + int32 _id; + static int32 counter; +}; + +UCLASS(Blueprintable, BlueprintType) +class UQuickTimeEventManager : public UObject +{ + GENERATED_BODY() + +public: + UFUNCTION(BlueprintCallable) + void ShowQuickTimeEvent(FQuickTimeEventEnqueProperties properties); + + UFUNCTION(BlueprintCallable) + void EnqueQuickTimeEvent(FQuickTimeEventEnqueProperties properties); + +protected: + void ShowNextEvent(); + void OnEventEnd(int32 id, EQuickTimeEventResult result); + + void OnInput(const FKey& key, bool released); + UFUNCTION() + void OnInputPressed(FKey key); + UFUNCTION() + void OnInputReleased(FKey key); + + void OnFirstEventInit(); + void CreateEvent(FQuickTimeEventEnqueProperties& properties, bool sequence); + + TQueue _nextEvents; + TMap _events; + FCriticalSection _lock; +}; diff --git a/Source/Lost_Edge/Private/Widgets/AdvanceButton.cpp b/Source/Lost_Edge/Private/Widgets/AdvanceButton.cpp deleted file mode 100644 index 564c4d0..0000000 --- a/Source/Lost_Edge/Private/Widgets/AdvanceButton.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// Oleg Petruny proprietary. - - -#include "AdvanceButton.h" - -#include "Components/ButtonSlot.h" - -//FReply SAdvanceButton::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) -//{ -// if(!hitboxTexture) -// return SButton::OnMouseMove(MyGeometry, MouseEvent); -// -// FVector2D locPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()); -// locPos /= MyGeometry.GetLocalSize(); -// int width = hitboxTexture->GetPlatformData()->SizeX; -// locPos.X *= width; -// locPos.Y *= hitboxTexture->GetPlatformData()->SizeY; -// long pixelIndex = (locPos.Y * width) + locPos.X; -// -// FColor* imageData = static_cast((hitboxTexture->GetPlatformData()->Mips[0]).BulkData.Lock(LOCK_READ_ONLY)); -// bool hovered = imageData && imageData[pixelIndex].A <= hitboxTextureAlphaThreshold; -// hitboxTexture->GetPlatformData()->Mips[0].BulkData.Unlock(); -// -// if(hovered != bIsHovered) -// { -// bIsHovered = hovered; -// if(bIsHovered) -// SButton::OnMouseEnter(MyGeometry, MouseEvent); -// else -// SButton::OnMouseLeave(MouseEvent); -// } -// -// return SButton::OnMouseMove(MyGeometry, MouseEvent); -//} -// -//void UAdvanceButton::SynchronizeProperties() -//{ -// Super::SynchronizeProperties(); -// (static_cast(MyButton.Get()))->hitboxTexture = hitboxTexture; -// (static_cast(MyButton.Get()))->hitboxTextureAlphaThreshold = hitboxTextureAlphaThreshold; -//} -// -//TSharedRef UAdvanceButton::RebuildWidget() -//{ -// TSharedPtr advanceButton = SNew(SAdvanceButton) -// .OnClicked(BIND_UOBJECT_DELEGATE(FOnClicked, SlateHandleClicked)) -// .OnPressed(BIND_UOBJECT_DELEGATE(FSimpleDelegate, SlateHandlePressed)) -// .OnReleased(BIND_UOBJECT_DELEGATE(FSimpleDelegate, SlateHandleReleased)) -// .OnHovered_UObject(this, &ThisClass::SlateHandleHovered) -// .OnUnhovered_UObject(this, &ThisClass::SlateHandleUnhovered) -// .ButtonStyle(&WidgetStyle) -// .ClickMethod(ClickMethod) -// .TouchMethod(TouchMethod) -// .IsFocusable(IsFocusable); -// -// advanceButton->hitboxTexture = hitboxTexture; -// advanceButton->hitboxTextureAlphaThreshold = hitboxTextureAlphaThreshold; -// MyButton = advanceButton; -// -// if(GetChildrenCount() > 0) -// Cast(GetContentSlot())->BuildSlot(MyButton.ToSharedRef()); -// -// return MyButton.ToSharedRef(); -//} \ No newline at end of file diff --git a/Source/Lost_Edge/Private/Widgets/AdvanceButton.h b/Source/Lost_Edge/Private/Widgets/AdvanceButton.h deleted file mode 100644 index d2d8a5b..0000000 --- a/Source/Lost_Edge/Private/Widgets/AdvanceButton.h +++ /dev/null @@ -1,51 +0,0 @@ -// Oleg Petruny proprietary. - -#pragma once - -#include "Components/Button.h" - -#include "AdvanceButton.generated.h" - -class SAdvanceButton : public SButton -{ -public: - //virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override - //{ - // if(!bIsHovered) return FReply::Unhandled(); - // return SButton::OnMouseButtonDown(MyGeometry, MouseEvent); - //} - //virtual FReply OnMouseButtonDoubleClick(const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent) override - //{ - // if(!bIsHovered) return FReply::Unhandled(); - // return SButton::OnMouseButtonDoubleClick(InMyGeometry, InMouseEvent); - //} - //virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; - //virtual void OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override - //{ - // if(hitboxTexture) return; - // return SButton::OnMouseEnter(MyGeometry, MouseEvent); - //} - //virtual TSharedPtr GetToolTip() override - //{ - // return (bIsHovered ? SWidget::GetToolTip() : nullptr); - //} - // - //UTexture2D* hitboxTexture = nullptr; - //uint8 hitboxTextureAlphaThreshold = 0; -}; - -UCLASS() -class UAdvanceButton : public UButton -{ - GENERATED_BODY() - // - //public: - // virtual void SynchronizeProperties() override; - // virtual TSharedRef RebuildWidget() override; - // - // UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "AdvanceButton") - // UTexture2D* hitboxTexture = nullptr; - // - // UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "AdvanceButton", meta = (ClampMin = "0.0", ClampMax = "255.0", UIMin = "0.0", UIMax = "255.0")) - // int hitboxTextureAlphaThreshold = 0; -}; diff --git a/Source/Lost_Edge/Private/Widgets/QuickTimeEventWidget.cpp b/Source/Lost_Edge/Private/Widgets/QuickTimeEventWidget.cpp new file mode 100644 index 0000000..b34b551 --- /dev/null +++ b/Source/Lost_Edge/Private/Widgets/QuickTimeEventWidget.cpp @@ -0,0 +1,58 @@ +// Oleg Petruny proprietary. + + +#include "QuickTimeEventWidget.h" + +#include "Animation/WidgetAnimation.h" + +#include "QuickTimeEvent.h" +#include "QuickTimeEventWidgetManager.h" + +void UQuickTimeEventWidget::NativeConstruct() +{ + FWidgetAnimationDynamicEvent onTimerFinish; + onTimerFinish.BindDynamic(this, &UQuickTimeEventWidget::RemoveEvent); + BindToAnimationFinished(eventAnimation, onTimerFinish); + + FWidgetAnimationDynamicEvent onRemove; + onRemove.BindDynamic(this, &UQuickTimeEventWidget::RemoveFromManager); + BindToAnimationFinished(removeAnimation, onRemove); + + return Super::NativeConstruct(); +} + +void UQuickTimeEventWidget::Show() +{ + SetVisibility(ESlateVisibility::Visible); + const float playbackSpeed = eventAnimation->GetEndTime() / duration; + + PlayAnimation(eventAnimation, 0, 1, EUMGSequencePlayMode::Forward, playbackSpeed, false); +} + +void UQuickTimeEventWidget::RemoveFromManager() +{ + manager->RemoveEvent(id); +} + +EQuickTimeEventResult UQuickTimeEventWidget::_Process(const bool released) +{ + Process(released); + + return result; +} + +EQuickTimeEventResult UQuickTimeEventWidget::_ProcessBeforeRemoving() +{ + ProcessBeforeRemoving(); + + return result; +} + +void UQuickTimeEventWidget::RemoveEvent() +{ + if(removing) + return; + + removing = true; + PlayAnimation(removeAnimation, 0, 1, EUMGSequencePlayMode::Forward, 1, false); +} diff --git a/Source/Lost_Edge/Private/Widgets/QuickTimeEventWidget.h b/Source/Lost_Edge/Private/Widgets/QuickTimeEventWidget.h new file mode 100644 index 0000000..6a07915 --- /dev/null +++ b/Source/Lost_Edge/Private/Widgets/QuickTimeEventWidget.h @@ -0,0 +1,54 @@ +// Oleg Petruny proprietary. + +#pragma once + +#include "Widgets/ResolutionResponsiveUserWidget.h" + +#include "QuickTimeEventWidget.generated.h" + +enum class EQuickTimeEventResult : uint8; + +UCLASS(Blueprintable, Abstract) +class UQuickTimeEventWidget : public UResolutionResponsiveUserWidget +{ + GENERATED_BODY() + +public: + void Show(); + + UFUNCTION(BlueprintCallable) + void RemoveEvent(); + + UFUNCTION(BlueprintImplementableEvent, BlueprintCallable) + void Process(const bool released); + EQuickTimeEventResult _Process(const bool released); + + UFUNCTION(BlueprintImplementableEvent, BlueprintCallable) + void ProcessBeforeRemoving(); + EQuickTimeEventResult _ProcessBeforeRemoving(); + + + UPROPERTY(meta = (BindWidget)) + class UTextBlock* keyText; + + int32 id; + class UQuickTimeEventWidgetManager* manager; + float duration; + +protected: + virtual void NativeConstruct() override; + + UFUNCTION() + void RemoveFromManager(); + + UPROPERTY(Transient, meta = (BindWidgetAnim)) + class UWidgetAnimation* eventAnimation; + + UPROPERTY(Transient, meta = (BindWidgetAnim)) + class UWidgetAnimation* removeAnimation; + + UPROPERTY(BlueprintReadWrite) + EQuickTimeEventResult result = EQuickTimeEventResult::FailedKey; // special state to do nothing; + + bool removing = false; +}; diff --git a/Source/Lost_Edge/Private/Widgets/QuickTimeEventWidgetManager.cpp b/Source/Lost_Edge/Private/Widgets/QuickTimeEventWidgetManager.cpp new file mode 100644 index 0000000..9316c7a --- /dev/null +++ b/Source/Lost_Edge/Private/Widgets/QuickTimeEventWidgetManager.cpp @@ -0,0 +1,77 @@ +// Oleg Petruny proprietary. + + +#include "QuickTimeEventWidgetManager.h" + +#include "Animation/UMGSequencePlayer.h" +#include "Animation/WidgetAnimation.h" +#include "Blueprint/WidgetTree.h" +#include "Components/CanvasPanel.h" +#include "Components/CanvasPanelSlot.h" +#include "Components/TextBlock.h" + +#include "CommonFunctions.h" +#include "QuickTimeEvent.h" +#include "Widgets/QuickTimeEventWidget.h" + +void UQuickTimeEventWidgetManager::ShowEvent(const int32 id, const struct FQuickTimeEventEnqueProperties& properties) +{ + FScopeLock Lock(&mappingLock); + + if(eventsMap.Contains(id) || !eventWidgetClasses.Contains(properties.type)) + return; + + auto eventWidget = WidgetTree->ConstructWidget(eventWidgetClasses[properties.type]); + eventWidget->SetVisibility(ESlateVisibility::Hidden); + eventWidget->keyText->SetText(UCommonFunctions::GetKeyDisplayName(properties.key)); + eventWidget->id = id; + eventWidget->manager = this; + eventWidget->duration = properties.duration; + ((UCanvasPanelSlot*)canvas->AddChild(eventWidget))->SetAnchors({ (float)properties.anchor.X, (float)properties.anchor.Y }); + eventWidget->Show(); + + eventsMap.Add(id, eventWidget); +} + +EQuickTimeEventResult UQuickTimeEventWidgetManager::RemoveEvent(const int32 id) +{ + FScopeLock Lock(&mappingLock); + + if(!eventsMap.Contains(id)) + return EQuickTimeEventResult::FailedTime; + + UQuickTimeEventWidget* eventWidget; + eventsMap.RemoveAndCopyValue(id, eventWidget); + auto result = eventWidget->_ProcessBeforeRemoving(); + eventWidget->RemoveEvent(); + return result; +} + +EQuickTimeEventResult UQuickTimeEventWidgetManager::AnimateEvent(const int32 id, const bool released) +{ + FScopeLock Lock(&mappingLock); + + if(!eventsMap.Contains(id)) + return EQuickTimeEventResult::FailedTime; + + return eventsMap[id]->_Process(released); +} + +void UQuickTimeEventWidgetManager::UpdateAnimation(UWidget* widget, float newSpeed) +{ + if(auto eventWidget = Cast(widget)) + { + for(auto player : eventWidget->ActiveSequencePlayers) + { + if(player->GetAnimation()->GetDisplayLabel() != TEXT("eventAnimation")) + continue; + + newSpeed *= player->GetAnimation()->GetEndTime() / eventWidget->duration; + player->SetPlaybackSpeed(newSpeed); + } + + return; + } + + Super::UpdateAnimation(widget, newSpeed); +} diff --git a/Source/Lost_Edge/Private/Widgets/QuickTimeEventWidgetManager.h b/Source/Lost_Edge/Private/Widgets/QuickTimeEventWidgetManager.h new file mode 100644 index 0000000..ded4f4a --- /dev/null +++ b/Source/Lost_Edge/Private/Widgets/QuickTimeEventWidgetManager.h @@ -0,0 +1,37 @@ +// Oleg Petruny proprietary. + +#pragma once + +#include "Widgets/WorldDilationResponsiveUserWidget.h" + +#include "QuickTimeEventWidgetManager.generated.h" + +enum class EInputAnimatedWidgetAnimation : uint8; +enum class EQuickTimeEventType : uint8; +enum class EQuickTimeEventResult : uint8; +class UQuickTimeEventWidget; + +UCLASS(Blueprintable, Abstract) +class UQuickTimeEventWidgetManager : public UWorldDilationResponsiveUserWidget +{ + GENERATED_BODY() + + friend UQuickTimeEventWidget; + +public: + void ShowEvent(const int32 id, const struct FQuickTimeEventEnqueProperties& properties); + EQuickTimeEventResult RemoveEvent(const int32 id); + EQuickTimeEventResult AnimateEvent(const int32 id, const bool released); + +protected: + virtual void UpdateAnimation(UWidget* widget, float newSpeed) override; + + UPROPERTY(EditDefaultsOnly) + TMap> eventWidgetClasses; + + UPROPERTY(meta = (BindWidget)) + class UCanvasPanel* canvas; + + TMap eventsMap; + FCriticalSection mappingLock; +}; diff --git a/Source/Lost_Edge/Private/Widgets/WidgetsManager.cpp b/Source/Lost_Edge/Private/Widgets/WidgetsManager.cpp index 095caaf..53bfa79 100644 --- a/Source/Lost_Edge/Private/Widgets/WidgetsManager.cpp +++ b/Source/Lost_Edge/Private/Widgets/WidgetsManager.cpp @@ -22,6 +22,7 @@ #include "Widgets/InventoryWidget.h" #include "Widgets/JournalWidget.h" #include "Widgets/MainMenu/MainMenuWidget.h" +#include "Widgets/QuickTimeEventWidgetManager.h" void UWidgetsManager::Init() { @@ -52,6 +53,7 @@ void UWidgetsManager::Init() if(auto instance = CreateWidget(PC, interactableHintWidgetManagerClass)) { interactableHintWidgetManager = instance; + interactableHintWidgetManager->SetVisibility(ESlateVisibility::Visible); interactableHintWidgetManager->AddToViewport(); } if(auto instance = CreateWidget(PC, cutsceneSkipWidgetClass)) @@ -60,6 +62,12 @@ void UWidgetsManager::Init() cutsceneSkipWidget->SetVisibility(ESlateVisibility::Hidden); cutsceneSkipWidget->AddToViewport(); } + if(auto instance = CreateWidget(PC, quickTimeEventWidgetManagerClass)) + { + quickTimeEventWidgetManager = instance; + quickTimeEventWidgetManager->SetVisibility(ESlateVisibility::Visible); + quickTimeEventWidgetManager->AddToViewport(); + } if(auto instance = CreateWidget(PC, dialogueRowWidgetManagerClass)) { dialogueRowWidgetManager = instance; @@ -183,6 +191,23 @@ void UWidgetsManager::AnimateCutsceneWidget(const EInputAnimatedWidgetAnimation +void UWidgetsManager::ShowQuickTimeEvent(const int32 id, const struct FQuickTimeEventEnqueProperties& properties) +{ + quickTimeEventWidgetManager->ShowEvent(id, properties); +} + +EQuickTimeEventResult UWidgetsManager::RemoveQuickTimeEvent(const int32 id) +{ + return quickTimeEventWidgetManager->RemoveEvent(id); +} + +EQuickTimeEventResult UWidgetsManager::ProcessQuickTimeEvent(const int32 id, const bool released) +{ + return quickTimeEventWidgetManager->AnimateEvent(id, released); +} + + + void UWidgetsManager::SetInputDialogueWidget(const FKey key, const FText desc, FDialogueSkipDelegate& delegate) { dialogueRowWidgetManager->SetInput(key, desc, delegate); diff --git a/Source/Lost_Edge/Private/Widgets/WidgetsManager.h b/Source/Lost_Edge/Private/Widgets/WidgetsManager.h index e49fb2b..e23034e 100644 --- a/Source/Lost_Edge/Private/Widgets/WidgetsManager.h +++ b/Source/Lost_Edge/Private/Widgets/WidgetsManager.h @@ -7,6 +7,7 @@ #include "WidgetsManager.generated.h" enum class EInputAnimatedWidgetAnimation : uint8; +enum class EQuickTimeEventResult : uint8; UCLASS(Blueprintable) class UWidgetsManager : public UObject @@ -34,6 +35,10 @@ public: void DisableCutsceneWidget(); void AnimateCutsceneWidget(const EInputAnimatedWidgetAnimation animation); + void ShowQuickTimeEvent(const int32 id, const struct FQuickTimeEventEnqueProperties& properties); + EQuickTimeEventResult RemoveQuickTimeEvent(const int32 id); + EQuickTimeEventResult ProcessQuickTimeEvent(const int32 id, const bool released); + void SetInputDialogueWidget(const FKey key, const FText desc, class FDialogueSkipDelegate& delegate); void ShowDialogueWidget(const struct FDialogueRow& dialogue); void HideDialogueWidget(const struct FDialogueRow& dialogue); @@ -68,6 +73,10 @@ protected: TSubclassOf cutsceneSkipWidgetClass; // never hidden class UCutsceneSkipWidget* cutsceneSkipWidget = nullptr; + UPROPERTY(EditDefaultsOnly) + TSubclassOf quickTimeEventWidgetManagerClass; // never hidden + class UQuickTimeEventWidgetManager* quickTimeEventWidgetManager = nullptr; + UPROPERTY(EditDefaultsOnly) TSubclassOf dialogueRowWidgetManagerClass; // hidden in cutscene class UDialogueRowWidgetManager* dialogueRowWidgetManager = nullptr; diff --git a/Source/Lost_Edge/Private/Widgets/WorldDilationResponsiveUserWidget.cpp b/Source/Lost_Edge/Private/Widgets/WorldDilationResponsiveUserWidget.cpp new file mode 100644 index 0000000..1216c89 --- /dev/null +++ b/Source/Lost_Edge/Private/Widgets/WorldDilationResponsiveUserWidget.cpp @@ -0,0 +1,81 @@ +// Oleg Petruny proprietary. + + +#include "WorldDilationResponsiveUserWidget.h" + +#include "Animation/UMGSequencePlayer.h" +#include "Animation/WidgetAnimation.h" +#include "Components/PanelWidget.h" + +#include "CommonFunctions.h" + +bool UWorldDilationResponsiveUserWidget::Initialize() +{ + UCommonFunctions::GetWorldDilationChangedDelegate().AddDynamic(this, &UWorldDilationResponsiveUserWidget::UpdateAnimations); + + return UUserWidget::Initialize(); +} + +void UWorldDilationResponsiveUserWidget::BeginDestroy() +{ + UCommonFunctions::GetWorldDilationChangedDelegate().RemoveDynamic(this, &UWorldDilationResponsiveUserWidget::UpdateAnimations); + + UUserWidget::BeginDestroy(); +} + +void UWorldDilationResponsiveUserWidget::UpdateAnimations(float newSpeed) +{ + UpdateAnimation(GetRootWidget(), newSpeed); + + if(auto root = Cast(GetRootWidget())) + { + if(root->GetChildrenCount() == 0) + return; + + // recursion would be simplier... + TArray path{ 0 }; + UWidget* widget = root->GetChildAt(0); + while(widget != root) + { + UpdateAnimation(widget, newSpeed); + + if(path.Num() < maxDepth) + { + if(auto panel = Cast(widget)) + { + if(panel->GetChildrenCount()) + { + path.Add(0); + widget = panel->GetChildAt(0); + continue; + } + } + } + + while(path.Num()) + { + auto panel = widget->GetParent(); + int32& i = path[path.Num() - 1]; + if(++i < panel->GetChildrenCount()) + { + widget = panel->GetChildAt(i); + break; + } + else + { + path.RemoveAt(path.Num() - 1, EAllowShrinking::No); + widget = panel; + } + } + } + } +} + +void UWorldDilationResponsiveUserWidget::UpdateAnimation(UWidget* widget, float newSpeed) +{ + if(auto userWidget = Cast(widget)) + { + for(auto player : userWidget->ActiveSequencePlayers) + player->SetPlaybackSpeed(newSpeed); + } +} diff --git a/Source/Lost_Edge/Private/Widgets/WorldDilationResponsiveUserWidget.h b/Source/Lost_Edge/Private/Widgets/WorldDilationResponsiveUserWidget.h new file mode 100644 index 0000000..243df6e --- /dev/null +++ b/Source/Lost_Edge/Private/Widgets/WorldDilationResponsiveUserWidget.h @@ -0,0 +1,25 @@ +// Oleg Petruny proprietary. + +#pragma once + +#include "Blueprint/UserWidget.h" + +#include "WorldDilationResponsiveUserWidget.generated.h" + +UCLASS() +class UWorldDilationResponsiveUserWidget : public UUserWidget +{ + GENERATED_BODY() + +public: + virtual bool Initialize() override; + virtual void BeginDestroy() override; + +protected: + UFUNCTION() + void UpdateAnimations(float newSpeed); + virtual void UpdateAnimation(UWidget* widget, float newSpeed); + + UPROPERTY(EditDefaultsOnly) + int32 maxDepth = 2; +};