Refactor dialogue system, move stuff to cpp and clean up BPs
This commit is contained in:
@@ -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