Refactor dialogue system, move stuff to cpp and clean up BPs

This commit is contained in:
2026-08-15 18:55:56 +02:00
parent b73e9065d1
commit 2fe7f83a38
15 changed files with 281 additions and 57 deletions

View File

@@ -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