Improving a Dialog Module

I’m working on a dialog system for a game. I wanted to try to make it as flexible as possible and mostly event-based.

Things I’m concerned about:

  • Dialog:CreateReplyObject is kind of weird. I am not using inheritance so this was the only way I could have Responses create Reply objects. Since Replies require the Response module I could not do vice versa without running into a cyclic issue.
  • Are any of the names confusing? Responses/Replies seem too similar to me and I often confuse the two.
  • Is it confusing that Replies can also have responses?
  • Are the destroy functions properly removing all instances so I can avoid memory leaks? I’m wondering if it’s better to have something like self._instances instead of having self._prompt and self._clickDetector
  • Is creating responses/reply intuitive enough? I’m worried that if conversations were longer it might be really messy to look at.
  • What kind of naming could improve the API?

Mainly looking for ways to improve the module or any feedback on the module design (not UI design.) Thanks.

Example of how the methods work can be found in StarterPlayerScripts > Dialog

dialog_test.rbxl (81.4 KB)

EDIT: Added a Dialog:GoToReply method. It’s a little scuffed but it works.

I have made an alternative tree-like syntax version that you might like:

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Dialog = require(ReplicatedStorage.Shared.Dialog)
local NewDialog = Dialog.new
local Response = NewDialog
local TraverseToDialog = Dialog.traverse
local ApplyToObject = Dialog.ApplyToObject

local test = NewDialog()
	:AddId("FirstReply")
	:Answer("Hello there!")
	:AddResponses({
		Response("How is it going?"):Answer("It's going well, thank you!"):AddResponses({
			Response("Good to hear."),
			Response("Back"):OnResponded(function()
				TraverseToDialog("FirstReply")
			end):Ends(false),
		}),
		Response("What are you?"):Answer("I'm a block!"),
		Response("Bye bye!"),
	})
	:OnEnd(function()
		print("Dialog ended!")
	end)

ApplyToObject(test, workspace.Part, {
	workspace.Part.ProximityPrompt,
})

Reply back if you’d like me to provide the code.

Hey. this seems like an improvement. I think if you do it like this you could also do away with the :Ends() method since you should be able to infer when the chain ends.

I’d love to see the code.

I’ll provide the file for the code, I’ll warn you though, the code is somewhat messy and definitely has a few bugs hiding.

DialogCode.rbxl (79.7 KB)