Dialogue system, Quest system

This commit is contained in:
Oleg Petruny 2024-07-17 22:39:05 +02:00
parent 55820fee9f
commit a432dcbbf7
56 changed files with 999 additions and 44 deletions

2
.editorconfig Normal file
View File

@ -0,0 +1,2 @@
[*.{c, cpp, h, hpp, cs}]
trim_trailing_whitespace = true

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.

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,6 @@
{
"FileVersion": 3,
"EngineAssociation": "{42CC8720-4DDD-EF11-BECE-CEBF292119D8}",
"EngineAssociation": "5.4",
"Category": "",
"Description": "",
"Modules": [
@ -369,6 +369,14 @@
"Name": "FlatNodes",
"Enabled": true,
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/b719437f3fb54c259b34227363df8cab"
},
{
"Name": "VisualStudioTools",
"Enabled": true,
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/362651520df94e4fa65492dbcba44ae2",
"SupportedTargetPlatforms": [
"Win64"
]
}
],
"TargetPlatforms": [

View File

@ -28,12 +28,15 @@ UCutsceneManager::UCutsceneManager()
}
}
void UCutsceneManager::EnqueueSequence(ULevelSequence* sequence, FCutsceneEndCallback endCallback)
void UCutsceneManager::EnqueueSequence(TSoftObjectPtr<class ULevelSequence> sequence, FCutsceneEndCallback endCallback)
{
if(!sequence)
if(!sequence.LoadSynchronous())
return;
if(_nextSequences.IsEmpty() && !_sequencePlayer) // most first sequence, so widgets and binds don't exist
FScopeLock lock1(&_sequencesLock);
FScopeLock lock2(&_callbacksLock);
if(_endCallbacks.IsEmpty()) // most first sequence, so widgets and binds don't exist
{
if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
{
@ -53,7 +56,7 @@ void UCutsceneManager::EnqueueSequence(ULevelSequence* sequence, FCutsceneEndCal
static FSkipCutsceneDelegate skipCutsceneDelegate;
if(!skipCutsceneDelegate.IsBound())
skipCutsceneDelegate.BindDynamic(this, &UCutsceneManager::SkipSequence);
WM->EnableCutsceneWidget(mapping.Key.GetDisplayName(false), skipCutsceneDelegate);
WM->EnableCutsceneWidget(skipCutsceneDelegate);
}
}
}
@ -75,9 +78,11 @@ void UCutsceneManager::PlayNextSequence()
_sequencePlayer->MarkAsGarbage();
}
ULevelSequence* sequence;
FScopeLock lock(&_sequencesLock);
TSoftObjectPtr<ULevelSequence> sequence;
_nextSequences.Dequeue(sequence);
_sequencePlayer = ULevelSequencePlayer::CreateLevelSequencePlayer(GetWorld(), sequence, FMovieSceneSequencePlaybackSettings{}, _sequencePlayerActor);
_sequencePlayer = ULevelSequencePlayer::CreateLevelSequencePlayer(GetWorld(), sequence.LoadSynchronous(), FMovieSceneSequencePlaybackSettings{}, _sequencePlayerActor);
_sequencePlayer->OnStop.AddDynamic(this, &UCutsceneManager::OnSequenceEnd);
_sequencePlayer->Play();
}
@ -93,6 +98,8 @@ void UCutsceneManager::SkipSequence()
void UCutsceneManager::ClearQueue()
{
FScopeLock lock1(&_sequencesLock);
FScopeLock lock2(&_callbacksLock);
if(!_nextSequences.IsEmpty())
_nextSequences.Empty();
if(!_endCallbacks.IsEmpty())
@ -112,6 +119,8 @@ void UCutsceneManager::OnSequenceEnd()
_sequencePlayer->MarkAsGarbage();
_sequencePlayer = nullptr;
FScopeLock lock(&_callbacksLock);
FCutsceneEndCallback callback;
_endCallbacks.Dequeue(callback);
if(callback.IsBound())

View File

@ -17,12 +17,15 @@ public:
UCutsceneManager();
UFUNCTION(BlueprintCallable)
void EnqueueSequence(class ULevelSequence* sequence, FCutsceneEndCallback endCallback);
void EnqueueSequence(TSoftObjectPtr<class ULevelSequence> sequence, FCutsceneEndCallback endCallback);
UFUNCTION(BlueprintCallable)
void SkipSequence();
UFUNCTION(BlueprintCallable)
void ClearQueue();
UFUNCTION(BlueprintCallable)
void LockCallback(bool lock);
private:
@ -35,8 +38,10 @@ private:
class ULevelSequencePlayer* _sequencePlayer = nullptr;
class ALevelSequenceActor* _sequencePlayerActor = nullptr;
TQueue<class ULevelSequence*> _nextSequences;
TQueue<TSoftObjectPtr<class ULevelSequence>> _nextSequences;
FCriticalSection _sequencesLock;
TQueue<FCutsceneEndCallback> _endCallbacks;
FCriticalSection _callbacksLock;
class APlayerBase* _lastPlayer = nullptr;
TSoftObjectPtr<class UInputMappingContext> _inputContext;

View File

@ -0,0 +1,262 @@
// Oleg Petruny proprietary.
#include "DialogueManager.h"
#include "Components/AudioComponent.h"
#include "Engine/DataTable.h"
#include "EnhancedInputComponent.h"
#include "InputMappingContext.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetMathLibrary.h"
#include "Sound/SoundWave.h"
#include "CustomGameInstanceBase.h"
#include "MainGameModeBase.h"
#include "PlayerBase.h"
#include "Widgets/DialogueSkipWidget.h"
#include "Widgets/InputAnimatedWidgetInterface.h"
#include "Widgets/WidgetsManager.h"
UDialogueManager::UDialogueManager()
{
_inputContext = { FSoftObjectPath{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/IMC_Dialogue.IMC_Dialogue'") } };
if(auto world = GetWorld())
{
if(auto GI = Cast<UCustomGameInstanceBase>(world->GetGameInstance()))
{
GI->inputContexts.Add(_inputContext);
}
}
}
void UDialogueManager::PlayDialogue(FDialogueEnqueProperties properties, FDialogueEndCallback endCallback)
{
if(!properties.dialogue)
return;
if(properties.playMode == EDialoguePlayMode::Random)
{
TArray<FName> rows = properties.dialogue.LoadSynchronous()->GetRowNames();
properties.rowName = rows[FMath::RandRange(0, rows.Num() - 1)];
}
FDialogueRow* row = reinterpret_cast<FDialogueRow*>(properties.dialogue.LoadSynchronous()->FindRowUnchecked(properties.rowName));
if(!row)
return;
FTimerHandle timer;
int32 timerId;
_timersLock.Lock();
timerId = _timers.Num();
_timers.Add(timer);
_timersLock.Unlock();
UGameplayStatics::PlaySound2D(this, row->wave.LoadSynchronous());
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->ShowDialogueWidget(*row);
}
auto func = [properties = properties,
timerId = timerId,
_timersLock = &_timersLock,
_timers = &_timers,
endCallback = endCallback]()
{
FDialogueRow* row = reinterpret_cast<FDialogueRow*>(properties.dialogue.LoadSynchronous()->FindRowUnchecked(properties.rowName));
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->HideDialogueWidget(*row);
}
_timersLock->Lock();
_timers->RemoveAt(timerId);
_timersLock->Unlock();
endCallback.Execute();
};
float duration = row->wave ? row->wave->GetDuration() : row->duration;
GetWorld()->GetTimerManager().SetTimer(timer, func, duration, false);
}
void UDialogueManager::EnqueDialogue(FDialogueEnqueProperties properties, FDialogueEndCallback endCallback)
{
if(!properties.dialogue.LoadSynchronous())
return;
FScopeLock lock1(&_dialoguesLock);
FScopeLock lock2(&_callbacksLock);
if(_endCallbacks.IsEmpty()) // most first dialogue, so widgets and binds don't exist
{
if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
{
_lastPlayer = Cast<APlayerBase>(PC->GetPawn());
if(_lastPlayer)
{
auto& mapping = _inputContext.LoadSynchronous()->GetMapping(0);
_inputHandler = _lastPlayer->inputComponent->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &UDialogueManager::OnInputPress).GetHandle();
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
static FDialogueSkipDelegate skipDialogueDelegate;
if(!skipDialogueDelegate.IsBound())
{
skipDialogueDelegate.BindDynamic(this, &UDialogueManager::SkipDialogue);
WM->SetInputDialogueWidget(mapping.Key, mapping.Action->ActionDescription, skipDialogueDelegate);
}
}
}
}
}
_nextDialogues.Enqueue(properties);
_endCallbacks.Enqueue(endCallback);
PlayNextDialogue();
}
void UDialogueManager::PlayNextDialogue()
{
_dialoguesLock.Lock();
auto properties = _nextDialogues.Peek();
TArray<FName> rows = properties->dialogue.LoadSynchronous()->GetRowNames();
if(rows.Num() == 0)
{
FDialogueEndCallback callback;
if(_endCallbacks.Dequeue(callback))
callback.Execute();
_nextDialogues.Pop();
return;
}
if(properties->playMode == EDialoguePlayMode::Random)
{
properties->rowName = rows[FMath::RandRange(0, rows.Num() - 1)];
}
FDialogueRow* row = reinterpret_cast<FDialogueRow*>(properties->dialogue.LoadSynchronous()->FindRowUnchecked(properties->rowName));
if(!row)
{
FDialogueEndCallback callback;
_endCallbacks.Dequeue(callback);
callback.Execute();
_nextDialogues.Pop();
return;
}
if(properties->playMode == EDialoguePlayMode::Sequential)
{
if(!properties->rowName.ToString().IsNumeric())
{
_nextDialogues.Pop();
FDialogueEndCallback callback;
if(_endCallbacks.Dequeue(callback))
callback.Execute();
return;
}
}
if(row->wave.LoadSynchronous())
leadDialogueAudio = UGameplayStatics::SpawnSound2D(this, row->wave.LoadSynchronous());
else
leadDialogueAudio = nullptr;
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->ShowDialogueWidget(*row);
}
FTimerHandle timer;
int32 timerId;
const float duration = row->wave ? row->wave->GetDuration() : row->duration;
GetWorld()->GetTimerManager().SetTimer(timer, [&]() { OnDialogueEnd(); }, duration, false);
_timersLock.Lock();
timerId = _timers.Num();
_timers.Add(timer);
_timersLock.Unlock();
leadDialogueTimerId = timerId;
leadDialogueProperties = properties;
_dialoguesLock.Unlock();
}
void UDialogueManager::SkipDialogue()
{
if(_timers.Num() == 0 || leadDialogueTimerId < 0)
return;
_timersLock.Lock();
GetWorld()->GetTimerManager().ClearTimer(_timers[leadDialogueTimerId]);
_timers.RemoveAt(leadDialogueTimerId);
leadDialogueTimerId = -1;
_timersLock.Unlock();
if(leadDialogueAudio)
leadDialogueAudio->Stop();
OnDialogueEnd();
}
void UDialogueManager::ClearQueue()
{
if(!_nextDialogues.IsEmpty())
_nextDialogues.Empty();
if(!_endCallbacks.IsEmpty())
_endCallbacks.Empty();
}
void UDialogueManager::LockCallback(bool lock)
{
_lockCallback = lock;
}
void UDialogueManager::OnDialogueEnd()
{
_dialoguesLock.Lock();
FDialogueRow* row = reinterpret_cast<FDialogueRow*>(leadDialogueProperties->dialogue.LoadSynchronous()->FindRowUnchecked(leadDialogueProperties->rowName));
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->HideDialogueWidget(*row);
}
if(leadDialogueProperties->playMode == EDialoguePlayMode::Sequential)
{
if(leadDialogueProperties->rowName.ToString().IsNumeric())
{
leadDialogueProperties->rowName = FName(FString::FromInt(FCString::Atoi(*(leadDialogueProperties->rowName.ToString())) + 1));
}
}
_dialoguesLock.Unlock();
if(!_endCallbacks.IsEmpty())
PlayNextDialogue();
_dialoguesLock.Lock();
if(_endCallbacks.IsEmpty() && _lastPlayer)
{
_lastPlayer->inputComponent->RemoveBindingByHandle(_inputHandler);
_lastPlayer = nullptr;
}
_dialoguesLock.Unlock();
}
void UDialogueManager::OnInputPress()
{
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->AnimateDialogueWidget(EInputAnimatedWidgetAnimation::Click);
}
}

View File

@ -0,0 +1,111 @@
// Oleg Petruny proprietary.
#pragma once
#include "UObject/Object.h"
#include "DialogueManager.generated.h"
UENUM(BlueprintType)
enum class EDialogueWaveType : uint8
{
Main,
Secondary,
Sound
};
USTRUCT(BlueprintType)
struct FDialogueRow : public FTableRowBase
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TSoftObjectPtr<class USoundWave> wave = nullptr;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
EDialogueWaveType type = EDialogueWaveType::Main;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float duration = 2.0;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString id = "";
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FText text = FText::GetEmpty();
};
UENUM(BlueprintType)
enum class EDialoguePlayMode : uint8
{
Sequential,
ExactRow,
Random
};
USTRUCT(BlueprintType)
struct FDialogueEnqueProperties
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TSoftObjectPtr<class UDataTable> dialogue = nullptr;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
EDialoguePlayMode playMode = EDialoguePlayMode::Sequential;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FName rowName = TEXT("1");
};
DECLARE_DYNAMIC_DELEGATE(FDialogueEndCallback);
UCLASS(BlueprintType)
class UDialogueManager : public UObject
{
GENERATED_BODY()
public:
UDialogueManager();
// Ignores play mode and force pushing dialogue
UFUNCTION(BlueprintCallable)
void PlayDialogue(FDialogueEnqueProperties properties, FDialogueEndCallback endCallback);
UFUNCTION(BlueprintCallable)
void EnqueDialogue(FDialogueEnqueProperties properties, FDialogueEndCallback endCallback);
UFUNCTION(BlueprintCallable)
void SkipDialogue();
UFUNCTION(BlueprintCallable)
void ClearQueue();
UFUNCTION(BlueprintCallable)
void LockCallback(bool lock);
private:
void PlayNextDialogue();
UFUNCTION()
void OnDialogueEnd();
void OnInputPress();
TQueue<FDialogueEnqueProperties> _nextDialogues;
FCriticalSection _dialoguesLock;
TQueue<FDialogueEndCallback> _endCallbacks;
FCriticalSection _callbacksLock;
TArray<FTimerHandle> _timers;
FCriticalSection _timersLock;
int32 leadDialogueTimerId = -1;
FDialogueEnqueProperties* leadDialogueProperties;
class UAudioComponent* leadDialogueAudio;
class APlayerBase* _lastPlayer = nullptr;
TSoftObjectPtr<class UInputMappingContext> _inputContext;
int32 _inputHandler;
bool _lockCallback = false;
};

View File

@ -27,7 +27,7 @@ enum class EActivatorType : uint8
};
ENUM_CLASS_FLAGS(EActivatorType);
UCLASS(Abstract, MinimalAPI, Blueprintable, BlueprintType)
UCLASS(Blueprintable, BlueprintType, MinimalAPI)
class AInteractable : public AActor
{
GENERATED_BODY()

View File

@ -0,0 +1,22 @@
// Oleg Petruny proprietary.
#include "Level2.h"
#include "Atmosphere/AtmosphericFog.h"
#include "Components/LightComponent.h"
#include "Engine/DirectionalLight.h"
#include "Engine/SkyLight.h"
#include "LevelSequencePlayer.h"
#include "CutsceneManager.h"
#include "MainGameModeBase.h"
void ALevel2::BeginPlay()
{
AMainGameModeBase::leadLevel = this;
ALevelBase::BeginPlay();
CallNextState();
}

View File

@ -0,0 +1,17 @@
// Oleg Petruny proprietary.
#pragma once
#include "LevelBase.h"
#include "Level2.generated.h"
UCLASS(BlueprintType)
class ALevel2 : public ALevelBase
{
GENERATED_BODY()
protected:
virtual void BeginPlay() override;
};

View File

@ -0,0 +1,22 @@
// Oleg Petruny proprietary.
#include "Level3.h"
#include "Atmosphere/AtmosphericFog.h"
#include "Components/LightComponent.h"
#include "Engine/DirectionalLight.h"
#include "Engine/SkyLight.h"
#include "LevelSequencePlayer.h"
#include "CutsceneManager.h"
#include "MainGameModeBase.h"
void ALevel3::BeginPlay()
{
AMainGameModeBase::leadLevel = this;
ALevelBase::BeginPlay();
CallNextState();
}

View File

@ -0,0 +1,17 @@
// Oleg Petruny proprietary.
#pragma once
#include "LevelBase.h"
#include "Level3.generated.h"
UCLASS(BlueprintType)
class ALevel3 : public ALevelBase
{
GENERATED_BODY()
protected:
virtual void BeginPlay() override;
};

View File

@ -0,0 +1,22 @@
// Oleg Petruny proprietary.
#include "Level4.h"
#include "Atmosphere/AtmosphericFog.h"
#include "Components/LightComponent.h"
#include "Engine/DirectionalLight.h"
#include "Engine/SkyLight.h"
#include "LevelSequencePlayer.h"
#include "CutsceneManager.h"
#include "MainGameModeBase.h"
void ALevel4::BeginPlay()
{
AMainGameModeBase::leadLevel = this;
ALevelBase::BeginPlay();
CallNextState();
}

View File

@ -0,0 +1,17 @@
// Oleg Petruny proprietary.
#pragma once
#include "LevelBase.h"
#include "Level4.generated.h"
UCLASS(BlueprintType)
class ALevel4 : public ALevelBase
{
GENERATED_BODY()
protected:
virtual void BeginPlay() override;
};

View File

@ -0,0 +1,22 @@
// Oleg Petruny proprietary.
#include "Level5.h"
#include "Atmosphere/AtmosphericFog.h"
#include "Components/LightComponent.h"
#include "Engine/DirectionalLight.h"
#include "Engine/SkyLight.h"
#include "LevelSequencePlayer.h"
#include "CutsceneManager.h"
#include "MainGameModeBase.h"
void ALevel5::BeginPlay()
{
AMainGameModeBase::leadLevel = this;
ALevelBase::BeginPlay();
CallNextState();
}

View File

@ -0,0 +1,17 @@
// Oleg Petruny proprietary.
#pragma once
#include "LevelBase.h"
#include "Level5.generated.h"
UCLASS(BlueprintType)
class ALevel5 : public ALevelBase
{
GENERATED_BODY()
protected:
virtual void BeginPlay() override;
};

View File

@ -10,17 +10,23 @@
#include "CustomGameInstanceBase.h"
#include "CutsceneManager.h"
#include "DialogueManager.h"
#include "Levels/LevelBase.h"
#include "QuestManager.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;
void AMainGameModeBase::StartPlay()
{
_widgetsManager = NewObject<UWidgetsManager>(this, widgetManagerClass);
_cutsceneManager = NewObject<UCutsceneManager>(this);
_dialogueManager = NewObject<UDialogueManager>(this);
_questManager = NewObject<UQuestManager>(this);
AGameModeBase::StartPlay();
@ -59,6 +65,11 @@ UCutsceneManager* AMainGameModeBase::GetCutsceneManager()
return _cutsceneManager;
}
UDialogueManager* AMainGameModeBase::GetDialogueManager()
{
return _dialogueManager;
}
void AMainGameModeBase::CallNextLevelState()
{
if(leadLevel)

View File

@ -2,11 +2,12 @@
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "MainGameModeBase.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FQuestsUpdateDelegate, TArray<FText>, quests);
UCLASS()
class AMainGameModeBase : public AGameModeBase
{
@ -17,18 +18,22 @@ public:
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual bool SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate = FCanUnpause()) override;
void SwitchCameraMode();
UFUNCTION(BlueprintPure)
static class UWidgetsManager* GetWidgetsManager();
UFUNCTION(BlueprintPure)
static class UCutsceneManager* GetCutsceneManager();
UFUNCTION(BlueprintPure)
static class UDialogueManager* GetDialogueManager();
UFUNCTION(BlueprintCallable)
static void CallNextLevelState();
void SwitchCameraMode();
static class ALevelBase* leadLevel;
FQuestsUpdateDelegate questsUpdateDelegate;
protected:
UPROPERTY(EditDefaultsOnly)
TSubclassOf<class UWidgetsManager> widgetManagerClass;
@ -36,4 +41,6 @@ protected:
private:
static class UWidgetsManager* _widgetsManager;
static class UCutsceneManager* _cutsceneManager;
static class UDialogueManager* _dialogueManager;
static class UQuestManager* _questManager;
};

View File

@ -330,3 +330,9 @@ void APlayerBase::ShowInventory()
if(auto WM = AMainGameModeBase::GetWidgetsManager())
WM->ShowInventory();
}
void APlayerBase::ShowJournal()
{
if(auto WM = AMainGameModeBase::GetWidgetsManager())
WM->ShowJournal();
}

View File

@ -84,6 +84,9 @@ protected:
UFUNCTION(BlueprintCallable, Category = Character)
void ShowInventory();
UFUNCTION(BlueprintCallable, Category = Character)
void ShowJournal();
class APlayerController* playerController;
UPROPERTY(EditAnywhere)
float moveSpeed = 200;

View File

@ -0,0 +1,27 @@
// Oleg Petruny proprietary.
#include "QuestManager.h"
#include "Kismet/GameplayStatics.h"
#include "Levels/LevelBase.h"
#include "MainGameModeBase.h"
#include "Widgets/WidgetsManager.h"
UQuestManager::UQuestManager()
{
if(auto gamemode_base = UGameplayStatics::GetGameMode(GetWorld()))
{
if(auto gamemode = Cast<AMainGameModeBase>(gamemode_base))
{
//gamemode->questsUpdateDelegate.AddDynamic(this, &UQuestManager::Update);
}
}
}
void UQuestManager::Update(TArray<FText> quests)
{
if(auto WM = AMainGameModeBase::GetWidgetsManager())
WM->UpdateJournal(quests);
}

View File

@ -0,0 +1,20 @@
// Oleg Petruny proprietary.
#pragma once
#include "UObject/Object.h"
#include "QuestManager.generated.h"
UCLASS(BlueprintType)
class UQuestManager : public UObject
{
GENERATED_BODY()
public:
UQuestManager();
protected:
void Update(TArray<FText> quests);
};

View File

@ -0,0 +1,6 @@
// Oleg Petruny proprietary.
#include "SaveManager.h"

View File

@ -0,0 +1,19 @@
// Oleg Petruny proprietary.
#pragma once
#include "UObject/Object.h"
#include "SaveManager.generated.h"
UCLASS(BlueprintType)
class USaveManager : public UObject
{
GENERATED_BODY()
public:
private:
};

View File

@ -1,22 +1,22 @@
// Oleg Petruny proprietary.
#include "InventoryWidget.h"
#include "AutohideWidget.h"
#include "Animation/WidgetAnimation.h"
#include "Engine/World.h"
#include "TimerManager.h"
void UInventoryWidget::Show()
void UAutohideWidget::Show()
{
SetVisibility(ESlateVisibility::Visible);
if(!showTimer.IsValid())
PlayAnimation(showAnimation, GetAnimationCurrentTime(showAnimation), 1, EUMGSequencePlayMode::Forward, 1, false);
GetWorld()->GetTimerManager().SetTimer(showTimer, this, &UInventoryWidget::Hide, showDuration, false);
GetWorld()->GetTimerManager().SetTimer(showTimer, this, &UAutohideWidget::Hide, showDuration, false);
}
void UInventoryWidget::Hide()
void UAutohideWidget::Hide()
{
GetWorld()->GetTimerManager().ClearTimer(showTimer);
PlayAnimation(showAnimation, GetAnimationCurrentTime(showAnimation), 1, EUMGSequencePlayMode::Reverse, 1, false);
showTimer.Invalidate();
}

View File

@ -0,0 +1,27 @@
// Oleg Petruny proprietary.
#pragma once
#include "ResolutionResponsiveUserWidget.h"
#include "AutohideWidget.generated.h"
UCLASS()
class UAutohideWidget : public UResolutionResponsiveUserWidget
{
GENERATED_BODY()
public:
virtual void Show();
UPROPERTY(Transient, meta = (BindWidgetAnim))
class UWidgetAnimation* showAnimation;
protected:
virtual void Hide();
UPROPERTY(EditDefaultsOnly, meta = (ClampMin = "1.0"))
float showDuration = 2.0;
FTimerHandle showTimer;
};

View File

@ -0,0 +1,22 @@
// Oleg Petruny proprietary.
#pragma once
#include "ResolutionResponsiveUserWidget.h"
#include "DialogueRowWidget.generated.h"
enum class EDialogueWaveType : uint8;
UCLASS(Blueprintable, Abstract)
class UDialogueRowWidget : public UResolutionResponsiveUserWidget
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintImplementableEvent)
void SetStyle(EDialogueWaveType style);
UPROPERTY(meta = (BindWidget))
class UTextBlock* text;
};

View File

@ -0,0 +1,83 @@
// Oleg Petruny proprietary.
#include "DialogueRowWidgetManager.h"
#include "Blueprint/WidgetTree.h"
#include "Components/TextBlock.h"
#include "Components/VerticalBox.h"
#include "CommonFunctions.h"
#include "DialogueManager.h"
#include "Widgets/DialogueRowWidget.h"
#include "Widgets/DialogueSkipWidget.h"
void UDialogueRowWidgetManager::SetInput(const FKey key, const FText desc, FDialogueSkipDelegate& delegate)
{
dialogueSkipWidget->keyText->SetText(UCommonFunctions::GetKeyDisplayName(key));
dialogueSkipWidget->descriptionText->SetText(desc);
dialogueSkipWidget->skipDialogueDelegate = delegate;
}
void UDialogueRowWidgetManager::Append(const FDialogueRow& dialogue)
{
FScopeLock Lock(&rowsLock);
for(int32 i = rows->GetChildrenCount() - rowsIds.Num(); i < 1; ++i)
{
auto row = WidgetTree->ConstructWidget<UDialogueRowWidget>(rowWidgetClass);
row->SetVisibility(ESlateVisibility::Hidden);
rows->AddChild(row);
}
auto row = Cast<UDialogueRowWidget>(rows->GetChildAt(rowsIds.Num()));
row->text->SetText(dialogue.text);
row->SetStyle(dialogue.type);
row->SetVisibility(ESlateVisibility::Visible);
rowsIds.Add(dialogue.id);
if(dialogue.type == EDialogueWaveType::Main)
{
if(count == 0)
dialogueSkipWidget->SetVisibility(ESlateVisibility::Visible);
++count;
}
}
void UDialogueRowWidgetManager::Remove(const struct FDialogueRow& dialogue)
{
FScopeLock Lock(&rowsLock);
if(dialogue.id == "")
{
for(int32 i = 0; i < rowsIds.Num(); ++i)
rows->GetChildAt(i)->SetVisibility(ESlateVisibility::Hidden);
rowsIds.Empty();
return;
}
if(!rowsIds.Contains(dialogue.id))
return;
int32 index = rowsIds.Find(dialogue.id);
auto row = rows->GetChildAt(index);
row->SetVisibility(ESlateVisibility::Hidden);
rows->RemoveChildAt(index);
rows->AddChild(row);
rowsIds.Remove(dialogue.id);
if(dialogue.type == EDialogueWaveType::Main)
{
if(count == 1)
dialogueSkipWidget->SetVisibility(ESlateVisibility::Hidden);
--count;
}
}
void UDialogueRowWidgetManager::AnimateSkipWidget(const EInputAnimatedWidgetAnimation animation)
{
dialogueSkipWidget->RunAnimation(animation);
}

View File

@ -0,0 +1,35 @@
// Oleg Petruny proprietary.
#pragma once
#include "Blueprint/UserWidget.h"
#include "DialogueRowWidgetManager.generated.h"
enum class EInputAnimatedWidgetAnimation : uint8;
UCLASS(Blueprintable, Abstract)
class UDialogueRowWidgetManager : public UUserWidget
{
GENERATED_BODY()
public:
void SetInput(const FKey key, const FText desc, class FDialogueSkipDelegate& delegate);
void Append(const struct FDialogueRow& dialogue);
void Remove(const struct FDialogueRow& dialogue);
void AnimateSkipWidget(const EInputAnimatedWidgetAnimation animation);
protected:
UPROPERTY(EditDefaultsOnly)
TSubclassOf<class UDialogueRowWidget> rowWidgetClass;
UPROPERTY(meta = (BindWidget))
class UVerticalBox* rows;
UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
class UDialogueSkipWidget* dialogueSkipWidget;
TArray<FString> rowsIds;
FCriticalSection rowsLock;
int32 count = 0;
};

View File

@ -0,0 +1,29 @@
// Oleg Petruny proprietary.
#pragma once
#include "InputAnimatedWidgetInterface.h"
#include "ResolutionResponsiveUserWidget.h"
#include "DialogueSkipWidget.generated.h"
DECLARE_DYNAMIC_DELEGATE(FDialogueSkipDelegate);
UCLASS(Blueprintable, Abstract)
class UDialogueSkipWidget : public UResolutionResponsiveUserWidget, public IInputAnimatedWidgetInterface
{
GENERATED_BODY()
public:
FDialogueSkipDelegate skipDialogueDelegate;
UPROPERTY(meta = (BindWidget))
class UTextBlock* keyText;
UPROPERTY(meta = (BindWidget))
class UTextBlock* descriptionText;
protected:
UFUNCTION(BlueprintCallable)
void SkipDialogue() { skipDialogueDelegate.Execute(); }
};

View File

@ -2,19 +2,17 @@
#pragma once
#include "AutohideWidget.h"
#include "InputAnimatedWidgetInterface.h"
#include "ResolutionResponsiveUserWidget.h"
#include "InventoryWidget.generated.h"
UCLASS(Blueprintable, Abstract)
class UInventoryWidget : public UResolutionResponsiveUserWidget, public IInputAnimatedWidgetInterface
class UInventoryWidget : public UAutohideWidget, public IInputAnimatedWidgetInterface
{
GENERATED_BODY()
public:
void Show();
UPROPERTY(meta = (BindWidget))
class UTextBlock* firstItemKeyText;
UPROPERTY(meta = (BindWidget))
@ -23,14 +21,4 @@ public:
class UTextBlock* secondItemKeyText;
UPROPERTY(meta = (BindWidget))
class UTextBlock* secondItemDescriptionText;
UPROPERTY(Transient, meta = (BindWidgetAnim))
class UWidgetAnimation* showAnimation;
protected:
void Hide();
UPROPERTY(EditDefaultsOnly, meta = (ClampMin = "1.0"))
float showDuration = 2.0;
FTimerHandle showTimer;
};

View File

@ -0,0 +1,20 @@
// Oleg Petruny proprietary.
#include "JournalWidget.h"
#include "Blueprint/WidgetTree.h"
#include "Components/TextBlock.h"
#include "Components/VerticalBox.h"
void UJournalWidget::Update(TArray<FText> items)
{
text->ClearChildren();
for(auto& item : items)
{
auto obj = WidgetTree->ConstructWidget<UTextBlock>(textStyleClass);
obj->SetVisibility(ESlateVisibility::Visible);
obj->SetText(item);
text->AddChild(obj);
}
}

View File

@ -0,0 +1,25 @@
// Oleg Petruny proprietary.
#pragma once
#include "AutohideWidget.h"
#include "ResolutionResponsiveUserWidget.h"
#include "JournalWidget.generated.h"
UCLASS(Blueprintable, Abstract)
class UJournalWidget : public UAutohideWidget
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
void Update(TArray<FText> items);
UPROPERTY(meta = (BindWidget))
class UVerticalBox* text;
protected:
UPROPERTY(EditDefaultsOnly)
TSubclassOf<class UTextBlock> textStyleClass;
};

View File

@ -14,10 +14,13 @@
#include "Interactable/Interactable.h"
#include "Interactable/Modificators/InteractableModificator.h"
#include "Interactable/Modificators/InventoryInteractableModificator.h"
#include "InteractableHintWidgetManager.h"
#include "PlayerBase.h"
#include "Widgets/CutsceneSkipWidget.h"
#include "Widgets/DialogueRowWidgetManager.h"
#include "Widgets/DialogueSkipWidget.h"
#include "Widgets/InteractableHintWidgetManager.h"
#include "Widgets/InventoryWidget.h"
#include "Widgets/JournalWidget.h"
void UWidgetsManager::Init()
{
@ -50,6 +53,12 @@ void UWidgetsManager::Init()
cutsceneSkipWidget->SetVisibility(ESlateVisibility::Hidden);
cutsceneSkipWidget->AddToViewport();
}
if(auto instance = CreateWidget<UDialogueRowWidgetManager>(PC, dialogueRowWidgetManagerClass))
{
dialogueRowWidgetManager = instance;
dialogueRowWidgetManager->SetVisibility(ESlateVisibility::Visible);
dialogueRowWidgetManager->AddToViewport();
}
if(auto instance = CreateWidget<UInventoryWidget>(PC, inventoryWidgetClass))
{
inventoryWidget = instance;
@ -69,8 +78,22 @@ void UWidgetsManager::Init()
inventoryWidget->AddToViewport();
}
if(auto instance = CreateWidget<UJournalWidget>(PC, journalWidgetClass))
{
journalWidget = instance;
journalWidget->SetVisibility(ESlateVisibility::Hidden);
journalWidget->AddToViewport();
}
}
}
void UWidgetsManager::UpdateInputKeys()
{
// PLAYER CANT CHANGE UI KEYS FROM SETTINGS (maybe somewhere in future project)
//cutsceneSkipWidget->keyText->SetText(keyText);
}
void UWidgetsManager::HideWidgets()
{
@ -81,6 +104,8 @@ void UWidgetsManager::HideWidgets()
interactableHintWidgetManager->Remove(nullptr);
if(inventoryWidget)
inventoryWidget->SetVisibility(ESlateVisibility::Hidden);
if(journalWidget)
journalWidget->SetVisibility(ESlateVisibility::Hidden);
}
void UWidgetsManager::ShowWidgets()
@ -103,6 +128,8 @@ void UWidgetsManager::UpdateWidgetsOwner()
}
}
void UWidgetsManager::ShowInteractionHints(const UInteractableModificator* modificator)
{
if(interactableHintWidgetManager)
@ -119,9 +146,10 @@ void UWidgetsManager::AnimateInteractionHint(const UInteractableModificator* mod
interactableHintWidgetManager->AnimateInteractionHint(modificator, index, animation);
}
void UWidgetsManager::EnableCutsceneWidget(FText keyText, FSkipCutsceneDelegate& skipCutsceneDelegate)
void UWidgetsManager::EnableCutsceneWidget(FSkipCutsceneDelegate& skipCutsceneDelegate)
{
cutsceneSkipWidget->keyText->SetText(keyText);
cutsceneSkipWidget->skipCutsceneDelegate = skipCutsceneDelegate;
cutsceneSkipWidget->SetVisibility(ESlateVisibility::Visible);
}
@ -134,24 +162,53 @@ void UWidgetsManager::AnimateCutsceneWidget(const EInputAnimatedWidgetAnimation
cutsceneSkipWidget->RunAnimation(animation);
}
void UWidgetsManager::SetInputDialogueWidget(const FKey key, const FText desc, FDialogueSkipDelegate& delegate)
{
dialogueRowWidgetManager->SetInput(key, desc, delegate);
}
void UWidgetsManager::ShowDialogueWidget(const FDialogueRow& dialogue)
{
dialogueRowWidgetManager->Append(dialogue);
}
void UWidgetsManager::HideDialogueWidget(const FDialogueRow& dialogue)
{
dialogueRowWidgetManager->Remove(dialogue);
}
void UWidgetsManager::AnimateDialogueWidget(const EInputAnimatedWidgetAnimation animation)
{
dialogueRowWidgetManager->AnimateSkipWidget(animation);
}
void UWidgetsManager::ShowInventory()
{
inventoryWidget->Show();
}
void UWidgetsManager::ShowInventory(FText key1, FText key2)
{
inventoryWidget->firstItemKeyText->SetText(key2);
inventoryWidget->secondItemKeyText->SetText(key1);
ShowInventory();
}
void UWidgetsManager::SetInventoryFirstItem(FText item)
{
inventoryWidget->firstItemDescriptionText->SetText(item);
}
void UWidgetsManager::SetInventorySecondItem(FText item)
{
inventoryWidget->secondItemDescriptionText->SetText(item);
}
void UWidgetsManager::ShowJournal()
{
journalWidget->Show();
}
void UWidgetsManager::UpdateJournal(TArray<FText> text)
{
journalWidget->Update(text);
}

View File

@ -15,6 +15,7 @@ class UWidgetsManager : public UObject
public:
void Init();
void UpdateInputKeys();
void ShowWidgets();
void HideWidgets();
@ -24,33 +25,49 @@ public:
void HideInteractionHints(const class UInteractableModificator* modificator);
void AnimateInteractionHint(const class UInteractableModificator* modificator, const int32 index, const EInputAnimatedWidgetAnimation animation);
void EnableCutsceneWidget(FText keyText, class FSkipCutsceneDelegate& skipCutsceneDelegate);
void EnableCutsceneWidget(class FSkipCutsceneDelegate& skipCutsceneDelegate);
void DisableCutsceneWidget();
void AnimateCutsceneWidget(const EInputAnimatedWidgetAnimation animation);
void SetInputDialogueWidget(const FKey key, const FText desc, class FDialogueSkipDelegate& delegate);
void ShowDialogueWidget(const struct FDialogueRow& dialogue);
void HideDialogueWidget(const struct FDialogueRow& dialogue);
void AnimateDialogueWidget(const EInputAnimatedWidgetAnimation animation);
void ShowInventory();
void ShowInventory(FText key1, FText key2);
void SetInventoryFirstItem(FText item);
void SetInventorySecondItem(FText item);
void ShowJournal();
void UpdateJournal(TArray<FText> text);
protected:
UPROPERTY(EditDefaultsOnly)
TSet<TSubclassOf<class UUserWidget>> permaOverlayWidgets; // never hidden
TArray<class UUserWidget*> permaOverlayWidgetsInstances;
UPROPERTY(EditDefaultsOnly)
TSet<TSubclassOf<class UUserWidget>> overlayWidgets; // hidden in pause
TSet<TSubclassOf<class UUserWidget>> overlayWidgets; // hidden in pause, cutscene
TArray<class UUserWidget*> overlayWidgetsInstances;
UPROPERTY(EditDefaultsOnly)
TSubclassOf<class UInteractableHintWidgetManager> interactableHintWidgetManagerClass;
TSubclassOf<class UInteractableHintWidgetManager> interactableHintWidgetManagerClass; // hidden in cutscene
class UInteractableHintWidgetManager* interactableHintWidgetManager = nullptr;
UPROPERTY(EditDefaultsOnly)
TSubclassOf<class UCutsceneSkipWidget> cutsceneSkipWidgetClass;
TSubclassOf<class UCutsceneSkipWidget> cutsceneSkipWidgetClass; // never hidden
class UCutsceneSkipWidget* cutsceneSkipWidget = nullptr;
UPROPERTY(EditDefaultsOnly)
TSubclassOf<class UInventoryWidget> inventoryWidgetClass;
TSubclassOf<class UDialogueRowWidgetManager> dialogueRowWidgetManagerClass; // hidden in cutscene
class UDialogueRowWidgetManager* dialogueRowWidgetManager = nullptr;
UPROPERTY(EditDefaultsOnly)
TSubclassOf<class UInventoryWidget> inventoryWidgetClass; // hidden in pause, cutscene
class UInventoryWidget* inventoryWidget = nullptr;
UPROPERTY(EditDefaultsOnly)
TSubclassOf<class UJournalWidget> journalWidgetClass; // hidden in pause, cutscene
class UJournalWidget* journalWidget = nullptr;
};