Aericks
(Aericks)
February 5, 2018, 4:18am
1
I want to create a dialogue system that doesn’t have to be built at every new instance. Therefore, in my mind the best way to do this is to create a LinkedList with multiple possible branches, and end-nodes will have a type of interaction linked to an enum. (ie. accept quest, decline, open shop, etc.)
A simple way to do this is the following code:
USTRUCT(BlueprintType)
struct FDialogueTree
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dialogue Properties")
TArray<FDialogueTree> DialogueNodes;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dialogue Properties")
FText DialogueText;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dialogue Properties")
int32 InteractType;
};
However, this resulted in catastrophic failure:
Error: 'Struct recursion via arrays is unsupported for properties.
Is there no workaround to this? A linked list like this is pretty standard practice; the leaf nodes are generally null pointers. If there is no way to correctly do this, what is generally used for dialogue options in Unreal? I’ve seen a few tutorials in this for Blueprints, but even then they seemed overly complex - Hard coding each option in. Are there any better options out there that I need to be aware of?
Ali_Akbar
(Ali_Akbar)
February 5, 2018, 6:32am
2
Reference your structures with an ID rather than a direct reference. There’s an ID field on your structure and the children list refer to their ID
USTRUCT(BlueprintType)
struct FDialogue
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dialogue Properties")
FName ID;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dialogue Properties")
TArray<FName> Children;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dialogue Properties")
FText DialogueText;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dialogue Properties")
int32 InteractType;
};
Save all these dialogs in a flat array somewhere
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dialogues")
TArray<FDialog> DialogList;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dialogues")
FName RootDialogID;
You can create a class on top of this for easier traversal and retrieval during runtime
Helper class for traversing the tree
class FDialogTree {
public:
FDialogTree(const TArray<FDialog>& InDialogs) {
for (const FDialog& Dialog : InDialogs) {
DialogMap.Add(Dialog.ID, Dialog);
}
}
FDialog Get(const FName& ID) {
return DialogMap[ID];
}
TArray<FDialog> GetChildren(const FDialog& Dialog) {
TArray<FDialog> Children;
for (const FName& ChildID : Dialog.Children) {
Children.Add(DialogMap[ChildID]);
}
return Children;
}
private:
TMap<FName, FDialog> DialogMap;
};
Helper class for editing the tree
class FDialogTreeEdit {
FDialogTree(const TArray<FDialog>& InDialogs) {
// ..
}
FDialog* CreateNew(const FName& ParentID) {
// ...
}
TArray<FDialog> Save() {
// ..
}
};
Ali_Akbar
(Ali_Akbar)
February 5, 2018, 6:35am
3
Alternatively, use UObjects to store your data. They support recursive references, since they are pointers
Aericks
(Aericks)
February 5, 2018, 5:57pm
4
This is great! Thank you! This is going to take a little bit to set up, but I am going to pre-emptively say that my question has been answered.
Thanks! Huge fan of your work, by the way!