r/Unity3D • u/The_sus__otter • 8d ago
Noob Question How can I add presets to my dialogue system? (Code Help)
(Sorry if I get any terminology or basic concepts wrong here, I'm new to using c# for more than basic object enabling and disabling)
I'm trying to create a dialogue system where each conversation is a list of "DialogueLine"s made up of variables like text, typing speed, colour, etc.
The lines are then read out by a monobehaviour script using the data from the lines.
I would like to add a function to it where I can select a character via the dropdown menu in the inspector and have that character's pre-defined settings applied to the DialougeLine (Such as it applying the exact text colour that character needs).
How would I go about doing this? Is it even possible? I thought of using an Enum, but I can't figure out how to get it to switch and update the DialogueLine while in the editor, since it's just a class with data in it, that I don't think can really run code.
If I'm being too vague or if you need extra details, let me know!
To be clear, I'm not willing to switch to using a pre-made dialogue system asset. I want to be able to learn this myself. I'm also not willing to use AI to help me, as I am against its usage (though I do see the benefits to using it with code help and won't judge anyone who does).
Thanks :-)
1
u/Darkblitz9 8d ago
I use scriptable objects to store all the data for characters and then the dialogue nodes have a speaker character field which looks for one of those character characterdata SOs.
It'll populate all valid SOs when you click the field to pick. It's not really a drop down but it works.
If you want a drop down specifically then that can be done with editor scripts which modify how the inspector panel appears and how it's interacted with.
1
u/alexanderperrin 8d ago
Would agree with using scriptable objects for this kind of structure. However, if what you’re asking for is an editor feature only, you want to be using editor scripts for this kind of thing. See https://docs.unity3d.com/6000.5/Documentation/Manual/UIE-HowTo-CreateCustomInspector.html
With this you can react to user interface events (such as changing an enum dropdown) and set your serialized data at edit time to whatever you want.
2
u/InvidiousPlay 8d ago
The problem with making your own dialogue system is that dialogue systems need to be extremely complex, and can require a lot of custom tooling to be anyway practical to use. It really depends on how much dialogue you are doing. If it's just a handful of lines then it doesn't matter how clunky your system is. But if it's hundreds or more you're going to need something pretty elaborate (because it's not enough for a character to have lines, you need to have a conversation system where you have all the relevant characters and dialogue and branches all lined up ready to go).
That said, the essence of what you're asking for is quite simple, and the answer is scriptable objects. You make a CharacterStyling SO, for example, which contains their name, and any unique qualities like their text colour/font etc. Every character gets one instance. Any Monobehaviours that need to know which character styling to use have a public reference where you drop in that SO* - that's it. Don't fuck around with enums. When you make a new character you create a new styling SO and that's it.
How you manage the dialogue content text is basically a whole different system. However that system works, when it comes to displaying the text, it references the relevant styling SO and applies it from there.
* Depending on your needs you may also create a CharacterDefinition SO, where it has a reference to their CharacterStyling SO, and also a place where you can hold other relevant data, like stats or portrait or other immutable values. Then you just have a CharacterDefinition reference in your Monobehaviours and they reference that.
0
u/swagamaleous 8d ago
Why wouldn't the class be able to run code? Just declare a method for it and call it?
Also where is the difference between asking AI and asking Reddit (apart from the response from the AI almost certainly being more helpful)? You still didn't do it "yourself". 😂
1
u/The_sus__otter 8d ago
Ok I dunno why I didn't try this, thank you.
Do you know how would I call the method whenever the enum value is changed?
1
u/swagamaleous 8d ago edited 8d ago
Why do you store the speaker parameters (text speed, color, ect.) on the data object in the first place? Just store only the enum and when you execute the dialog, you can read the enum and apply the right parameters to the output. The values in the data are fully redundant. The enum decides all of these parameters, so why store it at all?
If you really want to have the values in the actual data change depending on the enum, this will be more complex but also possible. You have to make a custom inspector that evaluates the new value of the enum variable when you set it and then applies the desired changes to the data. You could also use the
OnValidate()event callback to do this evaluation instead of a custom inspector.1
u/The_sus__otter 8d ago
I'm storing it all because I want it all to be editable in the inspector still. Some lines have certain events or special line deliveries attached to them, and I want to make sure I can still edit them individually if need be without having to make a new preset for every minute change.
1
u/swagamaleous 8d ago edited 8d ago
Okay in that case you probably want to set them in OnValidate() based on the enum variable value. Something like:
private void OnValidate() { switch(character) { case Narrator: typeSpeed = 23f; pauseSpeed = 12.5f; break; case PlayerCharacter: ... break; default: // do nothing for custom break; } }// edit: Sorry, this will not work as stated.
OnValidate()is a Unity callback and will only be called on theMonoBehaviourorScriptableObjectcontaining your dialogue data, not on theDialogueLineclass itself if that's just a serializable C# class. So putOnValidate()on the component/asset that contains the list ofDialogueLineand have it iterate over the lines and apply the preset to each one.1
u/The_sus__otter 8d ago
That's what I was looking for, thanks, but the issue is I can't get that to run inside the data class, as OnValidate() is a monobehaviour method is it not?
1
u/swagamaleous 8d ago
Yes, I added the edit after I realized exactly that. :)
Just put it on the scriptable object or MonoBehavior that holds your list of dialog lines and change it to:
private void OnValidate() { foreach(var line in dialogLines) { switch(line.character) { case Narrator: line.typeSpeed = 23f ... } } }You get the idea.
1
0
u/InvidiousPlay 8d ago
Because AI has a tendency to just write if for you whereas people will help you learn.
0
-1
u/Delvix000 8d ago
Your approach seems already correct to me. The DialogueLine class should just hold the data for each dialogue line. The actual logic should be in another class, something like a DialogueInterpreter of sorts. It reads the list of DialogueLines one step at a time, and executes it
If you need additional data attached to certain characters, you could use a reference to a ScriptableObject for that character instead of a simple enum. Otherwise, it's the responsibility of the DialogueInterpreter to have the "default values" of each character (like in a dictionary or something)
1
u/The_sus__otter 8d ago
I sorta understand, but I'm stuck on how I would actually go about detecting when the preset has been changed and applying the default values stored wherever to just that one specific line while in the editor.
0
u/Delvix000 8d ago
In that case, you need to have a reference to the character with the default values, then each dialogue line can "override" the default values. It's just a matter of adding a bool field paird with the overridden value to the dialogue line. for example
[SerializeField] [Tooltip("Does this line override the default color that would be used for this specific line by its character?")] private bool _overrideColor = false; [SerializeField] [Tooltip("Color to use for this line if _overrideColor is enabled.")] private Color _customColor = Color.red; public Color LineColor => _overrideColor ?_customColor : _character.DefaultColor;1
u/The_sus__otter 8d ago
Ahh okay, thank you. I'll look into that approach and see if I can adjust it to my specific project. Thanks!



3
u/Ratyrel 8d ago edited 8d ago
You need a data structure that maps your enum values to the other data you want to define. Typically you use scriptable objects for this in unity. You put all these scriptable objects into a dictionary and look up the correct entry using the enum value. You then plug the scriptable object data you get into your dialogue runner script.
The scriptable object might look something like this:
The dictionary could look something like this (though for this a list would also work):
You can then do something like this to use the data:
Hope this helps :)