Refactor dialogue system, move stuff to cpp and clean up BPs
This commit is contained in:
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.
@@ -4,22 +4,15 @@
|
||||
#include "DialogueComponent.h"
|
||||
|
||||
#include "DialogueSubsystem.h"
|
||||
#include "Components/WidgetComponent.h"
|
||||
#include "DialogueWidget.h"
|
||||
#include "EleriPlayerController.h"
|
||||
#include "Speech.h"
|
||||
#include "SpeechDataAsset.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "ProjectEleri/GameEventSystem/GameEventSubsystem.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "DialogueSystem"
|
||||
|
||||
// Sets default values for this component's properties
|
||||
UDialogueComponent::UDialogueComponent()
|
||||
{
|
||||
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
|
||||
// off to improve performance if you don't need them.
|
||||
PrimaryComponentTick.bCanEverTick = true;
|
||||
|
||||
}
|
||||
|
||||
// Called when the game starts
|
||||
void UDialogueComponent::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
@@ -37,6 +30,7 @@ void UDialogueComponent::BeginPlay()
|
||||
}
|
||||
}
|
||||
|
||||
EleriPlayerController = Cast<AEleriPlayerController>(UGameplayStatics::GetPlayerController(this, 0));
|
||||
}
|
||||
|
||||
void UDialogueComponent::OnDialogueLoaded()
|
||||
@@ -48,14 +42,6 @@ void UDialogueComponent::OnDialogueLoaded()
|
||||
}
|
||||
}
|
||||
|
||||
// Called every frame
|
||||
void UDialogueComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
||||
{
|
||||
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
void UDialogueComponent::FilterSpeechData()
|
||||
{
|
||||
ActiveSpeechData.Empty();
|
||||
@@ -66,6 +52,59 @@ void UDialogueComponent::FilterSpeechData()
|
||||
}
|
||||
}
|
||||
|
||||
void UDialogueComponent::StartDialogueWithNpc()
|
||||
{
|
||||
UDialogueSubsystem* DialogueSubsystem = UDialogueSubsystem::Get(this);
|
||||
ensure(DialogueSubsystem);
|
||||
|
||||
if (!DialogueSubsystem->StartDialogue()) return;
|
||||
|
||||
MappedDialogueOptions.Empty();
|
||||
FilterSpeechData();
|
||||
TArray<USpeechDataAsset*> StartingDialogues = GetStartingDialogues();
|
||||
if (StartingDialogues.IsEmpty()) return;
|
||||
|
||||
TriggerDialogue(StartingDialogues[FMath::RandRange(0, StartingDialogues.Num() - 1)], CurrentDialogueReplacementMap);
|
||||
|
||||
TArray<USpeechDataAsset*> ActiveDialogues = GetActiveDialogues();
|
||||
TArray<FText> PlayerAsks = GetPlayerAsksFromDialogueList(ActiveDialogues);
|
||||
for (int32 i = 0; i < ActiveDialogues.Num() - 1; i++)
|
||||
{
|
||||
FPlayerSpeakToDialogue SpeakToDialogue;
|
||||
SpeakToDialogue.NextSpeechDataAsset = ActiveDialogues[i];
|
||||
MappedDialogueOptions.Add(i, SpeakToDialogue);
|
||||
}
|
||||
TriggerDialogueSelect(PlayerAsks, true);
|
||||
}
|
||||
|
||||
void UDialogueComponent::TriggerDialogue_Async(TSoftObjectPtr<USpeechDataAsset> DialogueAssetPath, const TMap<FString, FText>& ReplacementMap)
|
||||
{
|
||||
DialogueAssetPath.LoadAsync(FLoadSoftObjectPathAsyncDelegate::CreateWeakLambda(this, [this, ReplacementMap](const FSoftObjectPath& Path, UObject* Object)
|
||||
{
|
||||
if (USpeechDataAsset* DataAsset = Cast<USpeechDataAsset>(Object))
|
||||
{
|
||||
TriggerDialogue(DataAsset, ReplacementMap);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void UDialogueComponent::TriggerDialogue(USpeechDataAsset* DialogueAssetPath, const TMap<FString, FText>& ReplacementMap)
|
||||
{
|
||||
UDialogueSubsystem* DialogueSubsystem = UDialogueSubsystem::Get(this);
|
||||
if (!DialogueSubsystem) return;
|
||||
|
||||
if (!DialogueSubsystem->StartDialogue()) return;
|
||||
|
||||
BindToControllerInput();
|
||||
bDialogueSelectOpen = false;
|
||||
DialogueWidget = Cast<UDialogueWidget>(EleriPlayerController->ToggleDialogueWindow(true));
|
||||
DialogueWidget->AssignDialogueComponent(this);
|
||||
CurrentLineIndex = 0;
|
||||
CurrentActiveDialogue = DialogueAssetPath;
|
||||
CurrentDialogueReplacementMap = ReplacementMap;
|
||||
DialogueWidget->DisplayDialogue(CurrentActiveDialogue, GetOwner(), CurrentDialogueReplacementMap);
|
||||
}
|
||||
|
||||
TArray<USpeechDataAsset*> UDialogueComponent::GetActiveSpeechData() { return ActiveSpeechData; }
|
||||
|
||||
TArray<USpeechDataAsset*> UDialogueComponent::GetStartingDialogues()
|
||||
@@ -92,4 +131,130 @@ TArray<USpeechDataAsset*> UDialogueComponent::GetActiveDialogues()
|
||||
return TempSpeechData;
|
||||
}
|
||||
|
||||
void UDialogueComponent::SetTextReplacementMap(const TMap<FString, FText>& ReplacementMap)
|
||||
{
|
||||
CurrentDialogueReplacementMap = ReplacementMap;
|
||||
}
|
||||
|
||||
void UDialogueComponent::CloseDialogue()
|
||||
{
|
||||
UDialogueSubsystem* DialogueSubsystem = UDialogueSubsystem::Get(this);
|
||||
if (!DialogueSubsystem) return;
|
||||
DialogueSubsystem->EndDialogue();
|
||||
|
||||
SelectedDialogueOptionIndex = 0;
|
||||
CurrentLineIndex = 0;
|
||||
CurrentActiveDialogue = nullptr;
|
||||
UnbindControllerInput();
|
||||
EleriPlayerController->ToggleDialogueWindow(false);
|
||||
}
|
||||
|
||||
void UDialogueComponent::AdvanceDialogue()
|
||||
{
|
||||
const UDialogueSubsystem* DialogueSubsystem = UDialogueSubsystem::Get(this);
|
||||
if (!DialogueSubsystem) return;
|
||||
|
||||
if (!DialogueWidget) return;
|
||||
|
||||
if (CurrentActiveDialogue)
|
||||
{
|
||||
if (bDialogueSelectOpen) return;
|
||||
|
||||
if (DialogueWidget->IsTypingDialogue())
|
||||
{
|
||||
DialogueWidget->SkipDialogueTyping();
|
||||
return;
|
||||
}
|
||||
|
||||
const FSoftObjectPath EventToTrigger = CurrentActiveDialogue->DialogueLines[CurrentLineIndex].TriggerEventStart;
|
||||
if (!EventToTrigger.IsNull())
|
||||
{
|
||||
UGameEventSubsystem::GetGameEventSubsystem()->StartEvent(EventToTrigger);
|
||||
}
|
||||
|
||||
if (CurrentLineIndex < CurrentActiveDialogue->DialogueLines.Num() - 1)
|
||||
{
|
||||
CurrentLineIndex++;
|
||||
DialogueWidget->AdvanceDialogue(CurrentActiveDialogue->DialogueLines[CurrentLineIndex].DialogueLine, CurrentActiveDialogue->DialogueLines[CurrentLineIndex].SpeakerName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CurrentActiveDialogue->PlayerSpeechMap.IsEmpty())
|
||||
{
|
||||
MappedDialogueOptions.Empty();
|
||||
TArray<FText> PlayerSpeakOptions;
|
||||
for (int32 i = 0; i < CurrentActiveDialogue->PlayerSpeechMap.Num() - 1; i++)
|
||||
{
|
||||
MappedDialogueOptions.Add(i, CurrentActiveDialogue->PlayerSpeechMap[i]);
|
||||
PlayerSpeakOptions.Add(CurrentActiveDialogue->PlayerSpeechMap[i].PlayerSpeak);
|
||||
}
|
||||
TriggerDialogueSelect(PlayerSpeakOptions, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CloseDialogue();
|
||||
DialogueSubsystem->OnDialogueEnded.Broadcast();
|
||||
}
|
||||
|
||||
void UDialogueComponent::TriggerDialogueSelect(TArray<FText>& DialogueOptions, bool bIsDialogueStart)
|
||||
{
|
||||
if (DialogueOptions.IsEmpty()) return;
|
||||
|
||||
if (bIsDialogueStart)
|
||||
{
|
||||
DialogueOptions.Add(LOCTEXT("Bye_DialogueEnd", "Bye"));
|
||||
}
|
||||
|
||||
DialogueWidget->OnDialogueOptionSelected.AddUniqueDynamic(this, &UDialogueComponent::OnDialogueOptionSelected);
|
||||
bDialogueSelectOpen = true;
|
||||
SelectedDialogueOptionIndex = 0;
|
||||
DialogueWidget->ShowDialogueOptions(true, DialogueOptions);
|
||||
}
|
||||
|
||||
void UDialogueComponent::OnDialogueOptionSelected(int32 Index)
|
||||
{
|
||||
DialogueWidget->OnDialogueOptionSelected.RemoveDynamic(this, &UDialogueComponent::OnDialogueOptionSelected);
|
||||
SelectedDialogueOptionIndex = Index;
|
||||
|
||||
if (const FPlayerSpeakToDialogue* PlayerSpeak = MappedDialogueOptions.Find(SelectedDialogueOptionIndex))
|
||||
{
|
||||
if (PlayerSpeak->GameplayTag.IsValid())
|
||||
{
|
||||
UDialogueSubsystem::Get(this)->OnDialogueGameplayEvent.Broadcast(PlayerSpeak->GameplayTag);
|
||||
}
|
||||
|
||||
if(!PlayerSpeak->NextSpeechDataAsset.IsNull())
|
||||
{
|
||||
TriggerDialogue_Async(PlayerSpeak->NextSpeechDataAsset, CurrentDialogueReplacementMap);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CloseDialogue();
|
||||
}
|
||||
|
||||
TArray<FText> UDialogueComponent::GetPlayerAsksFromDialogueList(const TArray<USpeechDataAsset*>& DialogueList)
|
||||
{
|
||||
TArray<FText> PlayerAsks;
|
||||
for (const USpeechDataAsset* DataAsset : DialogueList)
|
||||
{
|
||||
PlayerAsks.Add(DataAsset->PlayerAsk);
|
||||
}
|
||||
|
||||
return PlayerAsks;
|
||||
}
|
||||
|
||||
TArray<FText> UDialogueComponent::GetDialogueOptionsFromPlayerSpeakList(const TArray<FPlayerSpeakToDialogue>& SpeakList)
|
||||
{
|
||||
TArray<FText> Options;
|
||||
for (const FPlayerSpeakToDialogue& Speak : SpeakList)
|
||||
{
|
||||
Options.Add(Speak.PlayerSpeak);
|
||||
}
|
||||
|
||||
return Options;
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "ProjectEleri/DialogueSystem/SpeechDataAsset.h"
|
||||
#include "DialogueComponent.generated.h"
|
||||
|
||||
|
||||
class USpeechDataAsset;
|
||||
struct FPlayerSpeakToDialogue;
|
||||
class AEleriPlayerController;
|
||||
class UDialogueWidget;
|
||||
class UWidgetComponent;
|
||||
|
||||
@@ -17,32 +19,54 @@ class PROJECTELERI_API UDialogueComponent : public UActorComponent
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
// Sets default values for this component's properties
|
||||
UDialogueComponent();
|
||||
|
||||
public:
|
||||
// Called every frame
|
||||
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
UFUNCTION(BlueprintCallable, Category = "Eleri|Dialogue")
|
||||
void FilterSpeechData();
|
||||
|
||||
// use when you want to chit chat with an npc instead of play a specific dialogue option
|
||||
UFUNCTION(BlueprintCallable, Category = "Eleri|Dialogue")
|
||||
void StartDialogueWithNpc();
|
||||
UFUNCTION(BlueprintCallable, Category = "Eleri|Dialogue", meta = (AutoCreateRefTerm = "ReplacementMap"))
|
||||
void TriggerDialogue_Async(TSoftObjectPtr<USpeechDataAsset> DialogueAssetPath, const TMap<FString, FText>& ReplacementMap);
|
||||
UFUNCTION(BlueprintCallable, Category = "Eleri|Dialogue", meta = (AutoCreateRefTerm = "ReplacementMap"))
|
||||
void TriggerDialogue(USpeechDataAsset* DialogueAssetPath, const TMap<FString, FText>& ReplacementMap);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
UFUNCTION(BlueprintCallable, Category = "Eleri|Dialogue")
|
||||
TArray<USpeechDataAsset*> GetActiveSpeechData();
|
||||
|
||||
//Goes through active speech data and returns the all speech data asset without a condition and player ask
|
||||
UFUNCTION(BlueprintCallable)
|
||||
UFUNCTION(BlueprintCallable, Category = "Eleri|Dialogue")
|
||||
TArray<USpeechDataAsset*> GetStartingDialogues();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
UFUNCTION(BlueprintCallable, Category = "Eleri|Dialogue")
|
||||
TArray<USpeechDataAsset*> GetActiveDialogues();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Eleri|Dialogue")
|
||||
void SetTextReplacementMap(const TMap<FString, FText>& ReplacementMap);
|
||||
|
||||
protected:
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category = "Eleri|Dialogue")
|
||||
void BindToControllerInput();
|
||||
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category = "Eleri|Dialogue")
|
||||
void UnbindControllerInput();
|
||||
UFUNCTION(BlueprintCallable, Category = "Eleri|Dialogue")
|
||||
void CloseDialogue();
|
||||
UFUNCTION(BlueprintCallable, Category = "Eleri|Dialogue")
|
||||
void AdvanceDialogue();
|
||||
UFUNCTION(BlueprintCallable, Category = "Eleri|Dialogue")
|
||||
void TriggerDialogueSelect(TArray<FText>& DialogueOptions, bool bIsDialogueStart);
|
||||
UFUNCTION()
|
||||
void OnDialogueOptionSelected(int32 Index);
|
||||
static TArray<FText> GetPlayerAsksFromDialogueList(const TArray<USpeechDataAsset*>& DialogueList);
|
||||
static TArray<FText> GetDialogueOptionsFromPlayerSpeakList(const TArray<FPlayerSpeakToDialogue>& SpeakList);
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "DialogueWidget")
|
||||
TSubclassOf<UDialogueWidget> DialogueWidgetClass;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
|
||||
AActor* OwnerActor;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
AEleriPlayerController* EleriPlayerController;
|
||||
|
||||
TObjectPtr<UWidgetComponent> DialogueWidgetComponent;
|
||||
UPROPERTY()
|
||||
@@ -54,6 +78,19 @@ protected:
|
||||
UPROPERTY()
|
||||
TArray<TObjectPtr<USpeechDataAsset>> ActiveSpeechData;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
bool bDialogueSelectOpen = false;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
int32 CurrentLineIndex = 0;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
int32 SelectedDialogueOptionIndex = 0;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
USpeechDataAsset* CurrentActiveDialogue;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
TMap<int32, FPlayerSpeakToDialogue> MappedDialogueOptions;
|
||||
UPROPERTY()
|
||||
TMap<FString, FText> CurrentDialogueReplacementMap;
|
||||
|
||||
protected:
|
||||
// Called when the game starts
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
@@ -5,6 +5,17 @@
|
||||
|
||||
#include "SpeechDataAsset.h"
|
||||
#include "Engine/AssetManager.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
UDialogueSubsystem* UDialogueSubsystem::Get(const UObject* WorldContext)
|
||||
{
|
||||
if(const UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(WorldContext))
|
||||
{
|
||||
return GameInstance->GetSubsystem<UDialogueSubsystem>();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void UDialogueSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
||||
{
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "DialogueSubsystem.generated.h"
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnDialogueAssetsLoaded);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnDialogueEnded);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnDialogueGameplayEvent, FGameplayTag, GameplayTag);
|
||||
|
||||
class USpeechDataAsset;
|
||||
/**
|
||||
@@ -19,10 +21,15 @@ class PROJECTELERI_API UDialogueSubsystem : public UGameInstanceSubsystem
|
||||
|
||||
public:
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
UPROPERTY(BlueprintAssignable, Category = "Eleri|Dialogue")
|
||||
FOnDialogueAssetsLoaded OnDialogueAssetsLoaded;
|
||||
UPROPERTY(BlueprintAssignable, BlueprintCallable, Category = "Eleri|Dialogue")
|
||||
FOnDialogueEnded OnDialogueEnded;
|
||||
UPROPERTY(BlueprintAssignable, BlueprintCallable, Category = "Eleri|Dialogue")
|
||||
FOnDialogueGameplayEvent OnDialogueGameplayEvent;
|
||||
|
||||
static UDialogueSubsystem* Get(const UObject* WorldContext);
|
||||
|
||||
public:
|
||||
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
||||
bool IsDialogueLoaded() const { return bDialogueLoaded; }
|
||||
TArray<TObjectPtr<USpeechDataAsset>> GetDialogueForActor(const AActor* Actor);
|
||||
|
||||
@@ -27,6 +27,8 @@ public:
|
||||
|
||||
virtual void NativeOnInitialized() override;
|
||||
|
||||
bool IsTypingDialogue() const { return bIsTypingDialogue; }
|
||||
|
||||
protected:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
bool bIsAnimating = false;
|
||||
@@ -51,11 +53,11 @@ protected:
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
int32 CurrentTypingDialogueIndex = 0;
|
||||
|
||||
UPROPERTY(BlueprintAssignable, BlueprintReadWrite, BlueprintCallable)
|
||||
FOnDialogueOptionSelected OnDialogueOptionSelected;
|
||||
|
||||
|
||||
public:
|
||||
void AssignDialogueComponent(UDialogueComponent* InDialogueComponent) { DialogueComponent = InDialogueComponent; }
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable)
|
||||
void SetDialogueOptionsPadding();
|
||||
|
||||
@@ -82,5 +84,7 @@ public:
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable)
|
||||
void SetSpeakerName(const FText& NewSpeakerName);
|
||||
|
||||
|
||||
UPROPERTY(BlueprintAssignable, BlueprintReadWrite, BlueprintCallable)
|
||||
FOnDialogueOptionSelected OnDialogueOptionSelected;
|
||||
};
|
||||
|
||||
@@ -1103,10 +1103,10 @@ UEleriBaseWidget *AEleriPlayerController::ToggleAlchemyMenu(bool bOpen)
|
||||
|
||||
UEleriBaseWidget *AEleriPlayerController::ToggleDialogueWindow(bool bOpen)
|
||||
{
|
||||
if (!IsValid(MainGameUI->GetDialogueWidget()) || MainGameUI->GetDialogueWidget()->IsAnimating())
|
||||
if (!IsValid(MainGameUI->GetDialogueWidget()))
|
||||
return nullptr;
|
||||
|
||||
MainGameUI->OpenWidget(MainGameUI->GetDialogueWidget());
|
||||
bOpen? MainGameUI->OpenWidget(MainGameUI->GetDialogueWidget()) : MainGameUI->CloseWidget(MainGameUI->GetDialogueWidget());
|
||||
return MainGameUI->GetDialogueWidget();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user