UI interactable cleanup, Cutscene system and UI
This commit is contained in:
parent
a52d2aaa4a
commit
ce84cc2a9f
Binary file not shown.
BIN
Content/Input/Actions/IA_CutsceneSkip.uasset
Normal file
BIN
Content/Input/Actions/IA_CutsceneSkip.uasset
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Input/IMC_Cutscene.uasset
Normal file
BIN
Content/Input/IMC_Cutscene.uasset
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Levels/Test/Sequences/Seq_TestCutscene.uasset
Normal file
BIN
Content/Levels/Test/Sequences/Seq_TestCutscene.uasset
Normal file
Binary file not shown.
BIN
Content/Misc/Materials/PostProcess/M_PP_Inverse.uasset
Normal file
BIN
Content/Misc/Materials/PostProcess/M_PP_Inverse.uasset
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/UI/Blueprints/UI_CutsceneSkip.uasset
Normal file
BIN
Content/UI/Blueprints/UI_CutsceneSkip.uasset
Normal file
Binary file not shown.
@ -1,6 +1,6 @@
|
||||
{
|
||||
"FileVersion": 3,
|
||||
"EngineAssociation": "5.4",
|
||||
"EngineAssociation": "{42CC8720-4DDD-EF11-BECE-CEBF292119D8}",
|
||||
"Category": "",
|
||||
"Description": "",
|
||||
"Modules": [
|
||||
|
@ -6,15 +6,10 @@ public class Lost_Edge : ModuleRules {
|
||||
public Lost_Edge(ReadOnlyTargetRules Target) : base(Target) {
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "OpenCV" }); // "OpenCVHelper"
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "OpenCV" });
|
||||
|
||||
//PrivateIncludePaths.AddRange(new string[] { "OpenCV/Private" });
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(new string[] { "EnhancedInput", "UMG", "RHI", "RenderCore", "Lost_EdgeShaders", "TextureCompressor" }); // "Slate", "SlateCore"
|
||||
// Uncomment if you are using online features
|
||||
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
|
||||
|
||||
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
|
||||
PrivateDependencyModuleNames.AddRange(new string[] { "EnhancedInput", "UMG", "RHI", "RenderCore", "Lost_EdgeShaders", "TextureCompressor",
|
||||
"LevelSequence", "MovieScene" }); // "Slate", "SlateCore"
|
||||
|
||||
// UE_LOG(LogTemp, Log, TEXT("capture: %s"), (capture ? TEXT("true") : TEXT("false")));
|
||||
// GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("1"));
|
||||
|
169
Source/Lost_Edge/Private/CutsceneManager.cpp
Normal file
169
Source/Lost_Edge/Private/CutsceneManager.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
// Oleg Petruny proprietary.
|
||||
|
||||
|
||||
#include "CutsceneManager.h"
|
||||
|
||||
#include "EnhancedInputComponent.h"
|
||||
#include "InputMappingContext.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "LevelSequence.h"
|
||||
#include "LevelSequencePlayer.h"
|
||||
|
||||
#include "CustomGameInstanceBase.h"
|
||||
#include "MainGameModeBase.h"
|
||||
#include "PlayerBase.h"
|
||||
#include "Widgets/CutsceneSkipWidget.h"
|
||||
#include "Widgets/InputAnimatedWidgetInterface.h"
|
||||
#include "Widgets/WidgetsManager.h"
|
||||
|
||||
UCutsceneManager::UCutsceneManager()
|
||||
{
|
||||
_inputContext = { FSoftObjectPath{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/IMC_Cutscene.IMC_Cutscene'") } };
|
||||
if(auto world = GetWorld())
|
||||
{
|
||||
if(auto GI = Cast<UCustomGameInstanceBase>(world->GetGameInstance()))
|
||||
{
|
||||
GI->inputContexts.Add(_inputContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UCutsceneManager::EnqueueSequence(ULevelSequence* sequence, FCutsceneEndCallback endCallback)
|
||||
{
|
||||
if(!sequence)
|
||||
return;
|
||||
|
||||
if(_nextSequences.IsEmpty() && !_sequencePlayer) // most first sequence, so widgets and binds don't exist
|
||||
{
|
||||
if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
|
||||
{
|
||||
_lastPlayer = Cast<APlayerBase>(PC->GetPawn());
|
||||
if(_lastPlayer)
|
||||
{
|
||||
_lastPlayer->LockPlayer({ .walk = true, .jump = true, .run = true, .interaction = true, .camera = true });
|
||||
|
||||
auto& mapping = _inputContext.LoadSynchronous()->GetMapping(0);
|
||||
int32 handler1 = _lastPlayer->inputComponent->BindAction(mapping.Action, ETriggerEvent::Started, this, &UCutsceneManager::OnInputHold).GetHandle();
|
||||
int32 handler2 = _lastPlayer->inputComponent->BindAction(mapping.Action, ETriggerEvent::Completed, this, &UCutsceneManager::OnInputUnhold).GetHandle();
|
||||
_handlers = { handler1, handler2 };
|
||||
|
||||
if(auto WM = AMainGameModeBase::GetWidgetsManager())
|
||||
{
|
||||
WM->HideWidgets();
|
||||
static FSkipCutsceneDelegate skipCutsceneDelegate;
|
||||
if(!skipCutsceneDelegate.IsBound())
|
||||
skipCutsceneDelegate.BindDynamic(this, &UCutsceneManager::SkipSequence);
|
||||
WM->EnableCutsceneWidget(mapping.Key.GetDisplayName(false), skipCutsceneDelegate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_nextSequences.Enqueue(sequence);
|
||||
_endCallbacks.Enqueue(endCallback);
|
||||
|
||||
PlayNextSequence();
|
||||
}
|
||||
|
||||
void UCutsceneManager::PlayNextSequence()
|
||||
{
|
||||
if(_sequencePlayer)
|
||||
{
|
||||
if(_sequencePlayer->IsPlaying())
|
||||
return;
|
||||
else
|
||||
_sequencePlayer->MarkAsGarbage();
|
||||
}
|
||||
|
||||
ULevelSequence* sequence;
|
||||
_nextSequences.Dequeue(sequence);
|
||||
_sequencePlayer = ULevelSequencePlayer::CreateLevelSequencePlayer(GetWorld(), sequence, FMovieSceneSequencePlaybackSettings{}, _sequencePlayerActor);
|
||||
_sequencePlayer->OnStop.AddDynamic(this, &UCutsceneManager::OnSequenceEnd);
|
||||
_sequencePlayer->Play();
|
||||
}
|
||||
|
||||
void UCutsceneManager::SkipSequence()
|
||||
{
|
||||
if(!_sequencePlayer || !_sequencePlayer->IsPlaying())
|
||||
return;
|
||||
|
||||
_lastlySkipped = true;
|
||||
_sequencePlayer->GoToEndAndStop();
|
||||
}
|
||||
|
||||
void UCutsceneManager::ClearQueue()
|
||||
{
|
||||
if(!_nextSequences.IsEmpty())
|
||||
_nextSequences.Empty();
|
||||
if(!_endCallbacks.IsEmpty())
|
||||
_endCallbacks.Empty();
|
||||
}
|
||||
|
||||
void UCutsceneManager::LockCallback(bool lock)
|
||||
{
|
||||
_lockCallback = lock;
|
||||
}
|
||||
|
||||
void UCutsceneManager::OnSequenceEnd()
|
||||
{
|
||||
if(_lockCallback)
|
||||
return;
|
||||
|
||||
_sequencePlayer->MarkAsGarbage();
|
||||
_sequencePlayer = nullptr;
|
||||
|
||||
FCutsceneEndCallback callback;
|
||||
_endCallbacks.Dequeue(callback);
|
||||
if(callback.IsBound())
|
||||
callback.Execute();
|
||||
|
||||
if(!_nextSequences.IsEmpty())
|
||||
{
|
||||
PlayNextSequence();
|
||||
if(_lastlySkipped)
|
||||
{
|
||||
_lastlySkipped = false;
|
||||
if(_holding)
|
||||
{
|
||||
OnInputHold();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(auto WM = AMainGameModeBase::GetWidgetsManager())
|
||||
{
|
||||
WM->DisableCutsceneWidget();
|
||||
WM->ShowWidgets();
|
||||
}
|
||||
|
||||
if(_lastPlayer)
|
||||
{
|
||||
_lastPlayer->UnlockPlayer({ .walk = true, .jump = true, .run = true, .interaction = true, .camera = true });
|
||||
|
||||
_lastPlayer->inputComponent->RemoveBindingByHandle(_handlers.Key);
|
||||
_lastPlayer->inputComponent->RemoveBindingByHandle(_handlers.Value);
|
||||
|
||||
_lastPlayer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void UCutsceneManager::OnInputHold()
|
||||
{
|
||||
_holding = true;
|
||||
|
||||
if(auto WM = AMainGameModeBase::GetWidgetsManager())
|
||||
{
|
||||
WM->AnimateCutsceneWidget(EInputAnimatedWidgetAnimation::Hold);
|
||||
}
|
||||
}
|
||||
|
||||
void UCutsceneManager::OnInputUnhold()
|
||||
{
|
||||
_holding = false;
|
||||
|
||||
if(auto WM = AMainGameModeBase::GetWidgetsManager())
|
||||
{
|
||||
WM->AnimateCutsceneWidget(EInputAnimatedWidgetAnimation::Unhold);
|
||||
}
|
||||
}
|
48
Source/Lost_Edge/Private/CutsceneManager.h
Normal file
48
Source/Lost_Edge/Private/CutsceneManager.h
Normal file
@ -0,0 +1,48 @@
|
||||
// Oleg Petruny proprietary.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UObject/Object.h"
|
||||
|
||||
#include "CutsceneManager.generated.h"
|
||||
|
||||
DECLARE_DYNAMIC_DELEGATE(FCutsceneEndCallback);
|
||||
|
||||
UCLASS(BlueprintType)
|
||||
class UCutsceneManager : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UCutsceneManager();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void EnqueueSequence(class ULevelSequence* sequence, FCutsceneEndCallback endCallback);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void SkipSequence();
|
||||
|
||||
void ClearQueue();
|
||||
void LockCallback(bool lock);
|
||||
|
||||
private:
|
||||
void PlayNextSequence();
|
||||
UFUNCTION()
|
||||
void OnSequenceEnd();
|
||||
|
||||
void OnInputHold();
|
||||
void OnInputUnhold();
|
||||
|
||||
class ULevelSequencePlayer* _sequencePlayer = nullptr;
|
||||
class ALevelSequenceActor* _sequencePlayerActor = nullptr;
|
||||
TQueue<class ULevelSequence*> _nextSequences;
|
||||
TQueue<FCutsceneEndCallback> _endCallbacks;
|
||||
|
||||
class APlayerBase* _lastPlayer = nullptr;
|
||||
TSoftObjectPtr<class UInputMappingContext> _inputContext;
|
||||
TPair<int32, int32> _handlers;
|
||||
|
||||
bool _lockCallback = false;
|
||||
bool _lastlySkipped = false;
|
||||
bool _holding = false;
|
||||
};
|
@ -5,7 +5,7 @@
|
||||
#include "Components/SceneComponent.h"
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#include "../Interactable.h"
|
||||
#include "Interactable/Interactable.h"
|
||||
|
||||
#include "InteractableActivator.generated.h"
|
||||
|
||||
|
@ -5,10 +5,10 @@
|
||||
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
#include "../MainGameModeBase.h"
|
||||
#include "../PlayerBase.h"
|
||||
#include "../Widgets/WidgetsManager.h"
|
||||
#include "MainGameModeBase.h"
|
||||
#include "Modificators/InteractableModificator.h"
|
||||
#include "PlayerBase.h"
|
||||
#include "Widgets/WidgetsManager.h"
|
||||
|
||||
int32 AInteractable::GetActivatedFlags()
|
||||
{
|
||||
@ -90,7 +90,7 @@ void AInteractable::_Activate(EActivatorType type)
|
||||
|| !activationLockers.IsEmpty())
|
||||
return;
|
||||
|
||||
if(auto WM = AMainGameModeBase::GetWidgetManager())
|
||||
if(auto WM = AMainGameModeBase::GetWidgetsManager())
|
||||
{
|
||||
for(const auto& modificator : modificators)
|
||||
{
|
||||
@ -119,7 +119,7 @@ void AInteractable::_Deactivate(EActivatorType type)
|
||||
|| !activationLockers.IsEmpty())
|
||||
return;
|
||||
|
||||
if(auto WM = AMainGameModeBase::GetWidgetManager())
|
||||
if(auto WM = AMainGameModeBase::GetWidgetsManager())
|
||||
{
|
||||
for(const auto& modificator : modificators)
|
||||
{
|
||||
|
@ -7,8 +7,9 @@
|
||||
|
||||
#include "Interactable.generated.h"
|
||||
|
||||
#define INTERACTABLE_DEBUG
|
||||
//#define INTERACTABLE_DEBUG
|
||||
//#define INTERACTABLE_ACTIVATOR_DEBUG
|
||||
//#define INTERACTABLE_MODIFICATOR_DEBUG
|
||||
|
||||
UENUM(BlueprintType, meta = (Bitflags, UseEnumValuesAsMaskValuesInEditor = "true"))
|
||||
enum class EActivatorType : uint8
|
||||
|
@ -51,6 +51,6 @@ void UActivateInteractableModificator::Unbind_Implementation()
|
||||
|
||||
void UActivateInteractableModificator::ActivateInteractable()
|
||||
{
|
||||
AMainGameModeBase::GetWidgetManager()->AnimateInteractionHint(this, 0, EInteractableHintWidgetAnimation::Click);
|
||||
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::Click);
|
||||
OnActivated.Broadcast();
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "EditInteractableModificator.h"
|
||||
|
||||
#include "../Interactable.h"
|
||||
#include "Interactable/Interactable.h"
|
||||
|
||||
UEditInteractableModificator::UEditInteractableModificator(const FObjectInitializer& ObjectInitializer)
|
||||
: UInteractableModificator(ObjectInitializer)
|
||||
|
@ -31,11 +31,10 @@ public:
|
||||
virtual void Unbind_Implementation() {}
|
||||
|
||||
protected:
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
UPROPERTY(EditDefaultsOnly, NoClear)
|
||||
TSoftObjectPtr<class UInputMappingContext> inputMapping;
|
||||
|
||||
UPROPERTY(EditAnywhere, meta = (Bitmask, BitmaskEnum = "EActivatorType"))
|
||||
UPROPERTY(EditDefaultsOnly, NoClear, meta = (Bitmask, BitmaskEnum = "EActivatorType"))
|
||||
int32 activatorTypes = 0;
|
||||
|
||||
};
|
||||
|
@ -99,30 +99,30 @@ void UMoveInteractableModificator::TurnOnHolding()
|
||||
holding = true;
|
||||
ProcessState();
|
||||
distance = (player->GetCameraLocation() - actor->GetActorLocation()).Length();
|
||||
AMainGameModeBase::GetWidgetManager()->AnimateInteractionHint(this, 0, EInteractableHintWidgetAnimation::Hold);
|
||||
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::Hold);
|
||||
OnHolding.Broadcast();
|
||||
}
|
||||
void UMoveInteractableModificator::TurnOffHolding()
|
||||
{
|
||||
holding = false;
|
||||
ProcessState();
|
||||
AMainGameModeBase::GetWidgetManager()->AnimateInteractionHint(this, 0, EInteractableHintWidgetAnimation::Unhold);
|
||||
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::Unhold);
|
||||
}
|
||||
|
||||
void UMoveInteractableModificator::TurnOnRotating()
|
||||
{
|
||||
rotating = true;
|
||||
player->cameraLocked = true;
|
||||
player->LockPlayer({ .camera = true });
|
||||
ProcessState();
|
||||
AMainGameModeBase::GetWidgetManager()->AnimateInteractionHint(this, 1, EInteractableHintWidgetAnimation::Hold);
|
||||
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 1, EInputAnimatedWidgetAnimation::Hold);
|
||||
OnRotating.Broadcast();
|
||||
}
|
||||
void UMoveInteractableModificator::TurnOffRotating()
|
||||
{
|
||||
rotating = false;
|
||||
player->cameraLocked = false;
|
||||
player->UnlockPlayer({ .camera = true });
|
||||
ProcessState();
|
||||
AMainGameModeBase::GetWidgetManager()->AnimateInteractionHint(this, 1, EInteractableHintWidgetAnimation::Unhold);
|
||||
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 1, EInputAnimatedWidgetAnimation::Unhold);
|
||||
}
|
||||
|
||||
void UMoveInteractableModificator::ProcessState()
|
||||
@ -150,10 +150,24 @@ void UMoveInteractableModificator::UpdatePosition()
|
||||
auto camLoc = player->GetCameraLocation();
|
||||
auto dir = player->GetCameraDirection();
|
||||
auto newLoc = camLoc + dir * distance;
|
||||
//auto oldLoc = actor->GetActorLocation();
|
||||
auto oldLoc = actor->GetActorLocation();
|
||||
//auto interpLoc = FMath::VInterpTo(oldLoc, newLoc, GetWorld()->GetDeltaSeconds(), 20.0f);
|
||||
//auto interpLoc = FMath::Lerp(oldLoc, newLoc, 0.5f);
|
||||
actor->SetActorLocation(newLoc, true, nullptr, ETeleportType::None);
|
||||
FHitResult hit;
|
||||
actor->SetActorLocation(newLoc, true, &hit, ETeleportType::None);
|
||||
|
||||
static bool indicating = false;
|
||||
if(hit.bBlockingHit && !indicating)
|
||||
{
|
||||
indicating = true;
|
||||
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::TurnOnIndication);
|
||||
}
|
||||
else if(!hit.bBlockingHit && indicating)
|
||||
{
|
||||
indicating = false;
|
||||
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::TurnOffIndication);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void UMoveInteractableModificator::Zooming(const FInputActionValue& value)
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "SawInteractableModificator.h"
|
||||
|
||||
#include "../Interactable.h"
|
||||
#include "Interactable/Interactable.h"
|
||||
|
||||
USawInteractableModificator::USawInteractableModificator(const FObjectInitializer& ObjectInitializer)
|
||||
: UInteractableModificator(ObjectInitializer)
|
||||
|
@ -9,39 +9,53 @@
|
||||
#include "UObject/ScriptInterface.h"
|
||||
|
||||
#include "CustomGameInstanceBase.h"
|
||||
#include "CutsceneManager.h"
|
||||
#include "Widgets/WidgetsManager.h"
|
||||
|
||||
UWidgetsManager* AMainGameModeBase::_widgetsManager = nullptr;
|
||||
UCutsceneManager* AMainGameModeBase::_cutsceneManager = nullptr;
|
||||
|
||||
void AMainGameModeBase::StartPlay()
|
||||
{
|
||||
_widgetsManager = NewObject<UWidgetsManager>(this, widgetManagerClass);
|
||||
_cutsceneManager = NewObject<UCutsceneManager>(this);
|
||||
|
||||
AGameModeBase::StartPlay();
|
||||
|
||||
_widgetsManager = NewObject<UWidgetsManager>(this, widgetManagerClass);
|
||||
_widgetsManager->Init();
|
||||
}
|
||||
|
||||
void AMainGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||
{
|
||||
_cutsceneManager->LockCallback(true);
|
||||
_cutsceneManager->ClearQueue();
|
||||
}
|
||||
|
||||
bool AMainGameModeBase::SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate)
|
||||
{
|
||||
if(_widgetsManager)
|
||||
{
|
||||
if(IsPaused())
|
||||
{
|
||||
_widgetsManager->HideOverlayWidgets();
|
||||
_widgetsManager->HideWidgets();
|
||||
}
|
||||
else
|
||||
{
|
||||
_widgetsManager->ShowOverlayWidgets();
|
||||
_widgetsManager->ShowWidgets();
|
||||
}
|
||||
}
|
||||
|
||||
return AGameModeBase::SetPause(PC, CanUnpauseDelegate);
|
||||
}
|
||||
|
||||
UWidgetsManager* AMainGameModeBase::GetWidgetManager()
|
||||
UWidgetsManager* AMainGameModeBase::GetWidgetsManager()
|
||||
{
|
||||
return _widgetsManager;
|
||||
}
|
||||
UCutsceneManager* AMainGameModeBase::GetCutsceneManager()
|
||||
{
|
||||
return _cutsceneManager;
|
||||
}
|
||||
|
||||
void AMainGameModeBase::SwitchCameraMode()
|
||||
{
|
||||
@ -72,6 +86,6 @@ void AMainGameModeBase::SwitchCameraMode()
|
||||
|
||||
if(_widgetsManager)
|
||||
{
|
||||
_widgetsManager->UpdateOverlayWidgetsOwner();
|
||||
_widgetsManager->UpdateWidgetsOwner();
|
||||
}
|
||||
}
|
||||
|
@ -14,11 +14,15 @@ class AMainGameModeBase : public AGameModeBase
|
||||
|
||||
public:
|
||||
virtual void StartPlay() override;
|
||||
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
||||
virtual bool SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate = FCanUnpause()) override;
|
||||
|
||||
void SwitchCameraMode();
|
||||
|
||||
static class UWidgetsManager* GetWidgetManager();
|
||||
UFUNCTION(BlueprintCallable)
|
||||
static class UWidgetsManager* GetWidgetsManager();
|
||||
UFUNCTION(BlueprintCallable)
|
||||
static class UCutsceneManager* GetCutsceneManager();
|
||||
|
||||
protected:
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
@ -26,4 +30,5 @@ protected:
|
||||
|
||||
private:
|
||||
static class UWidgetsManager* _widgetsManager;
|
||||
static class UCutsceneManager* _cutsceneManager;
|
||||
};
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "CustomGameInstanceBase.h"
|
||||
#include "CustomGameUserSettings.h"
|
||||
#include "Interactable/Activators/InteractableActivator.h"
|
||||
#include "Interactable/Interactable.h"
|
||||
#include "Interactable/Modificators/InteractableModificator.h"
|
||||
#include "MainGameModeBase.h"
|
||||
|
||||
@ -87,26 +88,22 @@ void APlayerBase::BeginPlay()
|
||||
LoadInteractablesActivators();
|
||||
}
|
||||
|
||||
APlayerBase* APlayerBase::LockCamera(UWorld* world, bool locked)
|
||||
void APlayerBase::LockPlayer(FPlayerLock lock)
|
||||
{
|
||||
if(auto PC = UGameplayStatics::GetPlayerController(world, 0))
|
||||
{
|
||||
if(auto pawn = Cast<APlayerBase>(PC->GetPawn()))
|
||||
{
|
||||
pawn->cameraLocked = locked;
|
||||
return pawn;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
walkLocked += lock.walk;
|
||||
jumpLocked += lock.jump;
|
||||
runLocked += lock.run;
|
||||
interactionLocked += lock.interaction;
|
||||
cameraLocked += lock.camera;
|
||||
}
|
||||
|
||||
void APlayerBase::AttachToCamera(AActor* actor)
|
||||
void APlayerBase::UnlockPlayer(FPlayerLock lock)
|
||||
{
|
||||
if(!actor)
|
||||
return;
|
||||
|
||||
actor->AttachToComponent(camera, FAttachmentTransformRules::KeepWorldTransform);
|
||||
walkLocked -= lock.walk;
|
||||
jumpLocked -= lock.jump;
|
||||
runLocked -= lock.run;
|
||||
interactionLocked -= lock.interaction;
|
||||
cameraLocked -= lock.camera;
|
||||
}
|
||||
|
||||
FVector APlayerBase::GetCameraDirection()
|
||||
@ -142,7 +139,7 @@ void APlayerBase::MoveCamera(FVector2D value)
|
||||
|
||||
void APlayerBase::MoveCharacter(FVector2D value)
|
||||
{
|
||||
if(moveLocked)
|
||||
if(walkLocked)
|
||||
return;
|
||||
|
||||
moveVector = GetActorRightVector() * value.X;
|
||||
|
@ -2,16 +2,27 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Character.h"
|
||||
|
||||
#include "Interactable/Interactable.h"
|
||||
|
||||
#include "PlayerBase.generated.h"
|
||||
|
||||
enum class EActivatorType : uint8;
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FPlayerMovedDelegate);
|
||||
|
||||
UCLASS()
|
||||
USTRUCT(BlueprintType)
|
||||
struct FPlayerLock
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
uint8 walk : 1;
|
||||
uint8 jump : 1;
|
||||
uint8 run : 1;
|
||||
uint8 interaction : 1;
|
||||
uint8 camera : 1;
|
||||
};
|
||||
|
||||
UCLASS(Blueprintable, BlueprintType)
|
||||
class APlayerBase : public ACharacter
|
||||
{
|
||||
GENERATED_BODY()
|
||||
@ -22,21 +33,18 @@ public:
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
|
||||
|
||||
static APlayerBase* LockCamera(UWorld* world, bool locked);
|
||||
void AttachToCamera(AActor* actor);
|
||||
FVector GetCameraLocation();
|
||||
FVector GetCameraDirection();
|
||||
bool IsMoving() { return isMoving; }
|
||||
void LockPlayer(const FPlayerLock lock);
|
||||
void UnlockPlayer(const FPlayerLock lock);
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FPlayerMovedDelegate OnPlayerMoved;
|
||||
FVector moveVector;
|
||||
|
||||
class UEnhancedInputComponent* inputComponent;
|
||||
UPROPERTY(EditAnywhere)
|
||||
bool interactionLocked = false;
|
||||
UPROPERTY(EditAnywhere)
|
||||
bool cameraLocked = false;
|
||||
|
||||
|
||||
protected:
|
||||
virtual void BeginPlay() override;
|
||||
@ -61,12 +69,16 @@ protected:
|
||||
UPROPERTY(EditAnywhere)
|
||||
float runSpeedMultiplier = 4;
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
bool moveLocked = false;
|
||||
UPROPERTY(EditAnywhere)
|
||||
bool jumpLocked = false;
|
||||
UPROPERTY(EditAnywhere)
|
||||
bool runLocked = false;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
uint8 walkLocked = 0;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
uint8 jumpLocked = 0;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
uint8 runLocked = 0;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
uint8 interactionLocked = 0;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
uint8 cameraLocked = 0;
|
||||
|
||||
APlayerCameraManager* cameraManager;
|
||||
class UCameraComponent* camera;
|
||||
@ -80,8 +92,8 @@ protected:
|
||||
|
||||
private:
|
||||
void LoadInteractablesActivators();
|
||||
void InteractableActivated(AInteractable* interactable, EActivatorType type);
|
||||
void InteractableDeactivated(AInteractable* interactable, EActivatorType type);
|
||||
void InteractableActivated(class AInteractable* interactable, EActivatorType type);
|
||||
void InteractableDeactivated(class AInteractable* interactable, EActivatorType type);
|
||||
|
||||
FVector oldLocation;
|
||||
FRotator rotationInput;
|
||||
|
27
Source/Lost_Edge/Private/Widgets/CutsceneSkipWidget.h
Normal file
27
Source/Lost_Edge/Private/Widgets/CutsceneSkipWidget.h
Normal file
@ -0,0 +1,27 @@
|
||||
// Oleg Petruny proprietary.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "InputAnimatedWidgetInterface.h"
|
||||
#include "ResolutionResponsiveUserWidget.h"
|
||||
|
||||
#include "CutsceneSkipWidget.generated.h"
|
||||
|
||||
DECLARE_DYNAMIC_DELEGATE(FSkipCutsceneDelegate);
|
||||
|
||||
UCLASS(Blueprintable)
|
||||
class UCutsceneSkipWidget : public UResolutionResponsiveUserWidget, public IInputAnimatedWidgetInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
FSkipCutsceneDelegate skipCutsceneDelegate;
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
class UTextBlock* keyText;
|
||||
|
||||
protected:
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void SkipCutscene() { skipCutsceneDelegate.Execute(); }
|
||||
|
||||
};
|
@ -0,0 +1,65 @@
|
||||
// Oleg Petruny proprietary.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UObject/Interface.h"
|
||||
|
||||
#include "InputAnimatedWidgetInterface.generated.h"
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EInputAnimatedWidgetAnimation : uint8
|
||||
{
|
||||
Click,
|
||||
Hold,
|
||||
Unhold,
|
||||
TurnOnIndication,
|
||||
TurnOffIndication
|
||||
};
|
||||
|
||||
UINTERFACE(MinimalAPI, Blueprintable)
|
||||
class UInputAnimatedWidgetInterface : public UInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
|
||||
class IInputAnimatedWidgetInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "InputAnimatedWidget")
|
||||
void OnClick();
|
||||
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "InputAnimatedWidget")
|
||||
void OnHold();
|
||||
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "InputAnimatedWidget")
|
||||
void OnUnhold();
|
||||
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "InputAnimatedWidget")
|
||||
void OnTurnOnIndication();
|
||||
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "InputAnimatedWidget")
|
||||
void OnTurnOffIndication();
|
||||
|
||||
// Unsafe C++ shortcut
|
||||
void RunAnimation(const EInputAnimatedWidgetAnimation animation)
|
||||
{
|
||||
switch(animation)
|
||||
{
|
||||
case EInputAnimatedWidgetAnimation::Click:
|
||||
Execute_OnClick(this->_getUObject());
|
||||
break;
|
||||
case EInputAnimatedWidgetAnimation::Hold:
|
||||
Execute_OnHold(this->_getUObject());
|
||||
break;
|
||||
case EInputAnimatedWidgetAnimation::Unhold:
|
||||
Execute_OnUnhold(this->_getUObject());
|
||||
break;
|
||||
case EInputAnimatedWidgetAnimation::TurnOnIndication:
|
||||
Execute_OnTurnOnIndication(this->_getUObject());
|
||||
break;
|
||||
case EInputAnimatedWidgetAnimation::TurnOffIndication:
|
||||
Execute_OnTurnOffIndication(this->_getUObject());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
@ -1,4 +0,0 @@
|
||||
// Oleg Petruny proprietary.
|
||||
|
||||
|
||||
#include "InteractableHintWidget.h"
|
@ -2,34 +2,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "InputAnimatedWidgetInterface.h"
|
||||
#include "ResolutionResponsiveUserWidget.h"
|
||||
|
||||
#include "InteractableHintWidget.generated.h"
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EInteractableHintWidgetAnimation : uint8
|
||||
{
|
||||
Click,
|
||||
Hold,
|
||||
Unhold
|
||||
};
|
||||
|
||||
UCLASS(Blueprintable)
|
||||
class UInteractableHintWidget : public UResolutionResponsiveUserWidget
|
||||
class UInteractableHintWidget : public UResolutionResponsiveUserWidget, public IInputAnimatedWidgetInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintImplementableEvent)
|
||||
void OnClick();
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent)
|
||||
void OnHold();
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent)
|
||||
void OnUnhold();
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
class UTextBlock* keyText;
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
|
@ -12,10 +12,16 @@
|
||||
#include "Widgets/InteractableHintWidget.h"
|
||||
|
||||
|
||||
void UInteractableHintWidgetManager::Append(const class UInteractableModificator* modificator)
|
||||
void UInteractableHintWidgetManager::Append(const UInteractableModificator* modificator)
|
||||
{
|
||||
FScopeLock Lock(&hintsLock);
|
||||
|
||||
if(!modificator)
|
||||
{
|
||||
hints->SetVisibility(ESlateVisibility::Visible);
|
||||
return;
|
||||
}
|
||||
|
||||
if(hintsMap.Contains(modificator))
|
||||
return;
|
||||
|
||||
@ -46,10 +52,16 @@ void UInteractableHintWidgetManager::Append(const class UInteractableModificator
|
||||
hintsMap.Add(modificator, { count - mappings.Num() + skipped, mappings.Num() - skipped });
|
||||
}
|
||||
|
||||
void UInteractableHintWidgetManager::Remove(const class UInteractableModificator* modificator)
|
||||
void UInteractableHintWidgetManager::Remove(const UInteractableModificator* modificator)
|
||||
{
|
||||
FScopeLock Lock(&hintsLock);
|
||||
|
||||
if(!modificator)
|
||||
{
|
||||
hints->SetVisibility(ESlateVisibility::Hidden);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!hintsMap.Contains(modificator))
|
||||
return;
|
||||
|
||||
@ -66,8 +78,8 @@ void UInteractableHintWidgetManager::Remove(const class UInteractableModificator
|
||||
hintsMap.Remove(modificator);
|
||||
}
|
||||
|
||||
void UInteractableHintWidgetManager::AnimateInteractionHint(const class UInteractableModificator* modificator, const int32 index,
|
||||
const EInteractableHintWidgetAnimation animation)
|
||||
void UInteractableHintWidgetManager::AnimateInteractionHint(const UInteractableModificator* modificator, const int32 index,
|
||||
const EInputAnimatedWidgetAnimation animation)
|
||||
{
|
||||
FScopeLock Lock(&hintsLock);
|
||||
|
||||
@ -76,18 +88,5 @@ void UInteractableHintWidgetManager::AnimateInteractionHint(const class UInterac
|
||||
|
||||
auto& indexAndCount = hintsMap[modificator];
|
||||
auto hint = Cast<UInteractableHintWidget>(hints->GetChildAt(indexAndCount.Key + index));
|
||||
switch(animation)
|
||||
{
|
||||
case EInteractableHintWidgetAnimation::Click:
|
||||
hint->OnClick();
|
||||
break;
|
||||
case EInteractableHintWidgetAnimation::Hold:
|
||||
hint->OnHold();
|
||||
break;
|
||||
case EInteractableHintWidgetAnimation::Unhold:
|
||||
hint->OnUnhold();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
hint->RunAnimation(animation);
|
||||
}
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include "InteractableHintWidgetManager.generated.h"
|
||||
|
||||
enum class EInputAnimatedWidgetAnimation : uint8;
|
||||
|
||||
UCLASS(Blueprintable)
|
||||
class UInteractableHintWidgetManager : public UUserWidget
|
||||
{
|
||||
@ -14,7 +16,7 @@ class UInteractableHintWidgetManager : public UUserWidget
|
||||
public:
|
||||
void Append(const class UInteractableModificator* modificator);
|
||||
void Remove(const class UInteractableModificator* modificator);
|
||||
void AnimateInteractionHint(const class UInteractableModificator* modificator, const int32 index, const EInteractableHintWidgetAnimation animation);
|
||||
void AnimateInteractionHint(const class UInteractableModificator* modificator, const int32 index, const EInputAnimatedWidgetAnimation animation);
|
||||
|
||||
protected:
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "WidgetsManager.h"
|
||||
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "Components/TextBlock.h"
|
||||
#include "Engine/World.h"
|
||||
#include "InputMappingContext.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
@ -13,6 +14,7 @@
|
||||
#include "Interactable/Interactable.h"
|
||||
#include "Interactable/Modificators/InteractableModificator.h"
|
||||
#include "InteractableHintWidgetManager.h"
|
||||
#include "Widgets/CutsceneSkipWidget.h"
|
||||
|
||||
void UWidgetsManager::Init()
|
||||
{
|
||||
@ -37,66 +39,73 @@ void UWidgetsManager::Init()
|
||||
if(auto instance = CreateWidget<UInteractableHintWidgetManager>(PC, interactableHintWidgetManagerClass))
|
||||
{
|
||||
interactableHintWidgetManager = instance;
|
||||
instance->AddToViewport();
|
||||
interactableHintWidgetManager->AddToViewport();
|
||||
}
|
||||
if(auto instance = CreateWidget<UCutsceneSkipWidget>(PC, cutsceneSkipWidgetClass))
|
||||
{
|
||||
cutsceneSkipWidget = instance;
|
||||
cutsceneSkipWidget->SetVisibility(ESlateVisibility::Hidden);
|
||||
cutsceneSkipWidget->AddToViewport();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UWidgetsManager::HideOverlayWidgets()
|
||||
void UWidgetsManager::HideWidgets()
|
||||
{
|
||||
for(auto& widget : overlayWidgetsInstances)
|
||||
{
|
||||
if(widget.IsValid())
|
||||
{
|
||||
widget->SetVisibility(ESlateVisibility::Hidden);
|
||||
}
|
||||
}
|
||||
|
||||
if(interactableHintWidgetManager)
|
||||
interactableHintWidgetManager->Remove(nullptr);
|
||||
}
|
||||
|
||||
void UWidgetsManager::ShowOverlayWidgets()
|
||||
void UWidgetsManager::ShowWidgets()
|
||||
{
|
||||
for(auto& widget : overlayWidgetsInstances)
|
||||
{
|
||||
if(widget.IsValid())
|
||||
{
|
||||
widget->SetVisibility(ESlateVisibility::Visible);
|
||||
}
|
||||
}
|
||||
|
||||
if(interactableHintWidgetManager)
|
||||
interactableHintWidgetManager->Append(nullptr);
|
||||
}
|
||||
|
||||
void UWidgetsManager::UpdateOverlayWidgetsOwner()
|
||||
void UWidgetsManager::UpdateWidgetsOwner()
|
||||
{
|
||||
if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
|
||||
{
|
||||
for(auto& widget : permaOverlayWidgetsInstances)
|
||||
{
|
||||
if(widget.IsValid())
|
||||
{
|
||||
widget->SetOwningPlayer(PC);
|
||||
}
|
||||
}
|
||||
for(auto& widget : overlayWidgetsInstances)
|
||||
{
|
||||
if(widget.IsValid())
|
||||
{
|
||||
widget->SetOwningPlayer(PC);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UWidgetsManager::ShowInteractionHints(const UInteractableModificator* modificator)
|
||||
{
|
||||
if(interactableHintWidgetManager.IsValid())
|
||||
if(interactableHintWidgetManager)
|
||||
interactableHintWidgetManager->Append(modificator);
|
||||
}
|
||||
void UWidgetsManager::HideInteractionHints(const UInteractableModificator* modificator)
|
||||
{
|
||||
if(interactableHintWidgetManager.IsValid())
|
||||
if(interactableHintWidgetManager)
|
||||
interactableHintWidgetManager->Remove(modificator);
|
||||
}
|
||||
void UWidgetsManager::AnimateInteractionHint(const class UInteractableModificator* modificator, const int32 index, const EInteractableHintWidgetAnimation animation)
|
||||
void UWidgetsManager::AnimateInteractionHint(const UInteractableModificator* modificator, const int32 index, const EInputAnimatedWidgetAnimation animation)
|
||||
{
|
||||
if(interactableHintWidgetManager.IsValid())
|
||||
if(interactableHintWidgetManager)
|
||||
interactableHintWidgetManager->AnimateInteractionHint(modificator, index, animation);
|
||||
}
|
||||
|
||||
void UWidgetsManager::EnableCutsceneWidget(FText keyText, FSkipCutsceneDelegate& skipCutsceneDelegate)
|
||||
{
|
||||
cutsceneSkipWidget->keyText->SetText(keyText);
|
||||
cutsceneSkipWidget->skipCutsceneDelegate = skipCutsceneDelegate;
|
||||
cutsceneSkipWidget->SetVisibility(ESlateVisibility::Visible);
|
||||
}
|
||||
void UWidgetsManager::DisableCutsceneWidget()
|
||||
{
|
||||
cutsceneSkipWidget->SetVisibility(ESlateVisibility::Hidden);
|
||||
}
|
||||
void UWidgetsManager::AnimateCutsceneWidget(const EInputAnimatedWidgetAnimation animation)
|
||||
{
|
||||
cutsceneSkipWidget->RunAnimation(animation);
|
||||
}
|
||||
|
@ -2,12 +2,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/Object.h"
|
||||
|
||||
#include "WidgetsManager.generated.h"
|
||||
|
||||
enum class EInteractableHintWidgetAnimation : uint8;
|
||||
enum class EInputAnimatedWidgetAnimation : uint8;
|
||||
|
||||
UCLASS(Blueprintable)
|
||||
class UWidgetsManager : public UObject
|
||||
@ -17,24 +16,32 @@ class UWidgetsManager : public UObject
|
||||
public:
|
||||
void Init();
|
||||
|
||||
void HideOverlayWidgets();
|
||||
void ShowOverlayWidgets();
|
||||
void UpdateOverlayWidgetsOwner();
|
||||
void ShowWidgets();
|
||||
void HideWidgets();
|
||||
void UpdateWidgetsOwner();
|
||||
|
||||
void ShowInteractionHints(const class UInteractableModificator* modificator);
|
||||
void HideInteractionHints(const class UInteractableModificator* modificator);
|
||||
void AnimateInteractionHint(const class UInteractableModificator* modificator, const int32 index, const EInteractableHintWidgetAnimation animation);
|
||||
void AnimateInteractionHint(const class UInteractableModificator* modificator, const int32 index, const EInputAnimatedWidgetAnimation animation);
|
||||
|
||||
void EnableCutsceneWidget(FText keyText, class FSkipCutsceneDelegate& skipCutsceneDelegate);
|
||||
void DisableCutsceneWidget();
|
||||
void AnimateCutsceneWidget(const EInputAnimatedWidgetAnimation animation);
|
||||
|
||||
protected:
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TSet<TSubclassOf<class UUserWidget>> permaOverlayWidgets; // never hidden
|
||||
TArray<TWeakObjectPtr<class UUserWidget>> permaOverlayWidgetsInstances;
|
||||
TArray<class UUserWidget*> permaOverlayWidgetsInstances;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TSet<TSubclassOf<class UUserWidget>> overlayWidgets; // hidden in pause
|
||||
TArray<TWeakObjectPtr<class UUserWidget>> overlayWidgetsInstances;
|
||||
TArray<class UUserWidget*> overlayWidgetsInstances;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TSubclassOf<class UInteractableHintWidgetManager> interactableHintWidgetManagerClass;
|
||||
TWeakObjectPtr<class UInteractableHintWidgetManager> interactableHintWidgetManager;
|
||||
class UInteractableHintWidgetManager* interactableHintWidgetManager = nullptr;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TSubclassOf<class UCutsceneSkipWidget> cutsceneSkipWidgetClass;
|
||||
class UCutsceneSkipWidget* cutsceneSkipWidget = nullptr;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user