Need help designing a dialogue system (or, how could I deal with referencing scene objects in ScriptableObjects?)
Hi everybody, I need some suggestions for a topic I'm tackling.
I want to code the whole thing myself for the sake of exercise and understanding how it works (and possibly have a custom asset I can reuse for my actual future projects), so I'd like to avoid premade assets from the store.
One of the main goals is to be able to compose the dialogues in the editor/inspector without touching Visual Studio once the system is done. Possibly avoiding custom editors additions, as I never done anything like that and it feels maybe a bit too much dealing with two problems at once, both the dialogue system and the custom editor (but if that's the only way, I'm willing to look into that too; please point me in the right direction if that's the case).
Based on that, I already made a skeleton that is nothing fancy but does at least a part of it's job. It's made of two ScriptableObject classes, a DialogueNode and a DialogueOption.
DialogueNode contains a serializable private string[] npcLines, a serializable private DialogueOption[] options, plus public methods that return both.
DialogueOptions is basically the same, except that there is a single string that is of course the player's line, and it has an array of nodes.
The DialogueManager handles the flow of the whole thing by keeping track of the current node, assigning the text to the correct GUI elements and generating the correct amount of buttons for the player from the options array.
As I said it works decently, except that it works only in isolation. In my plans, both DialogueNode and DialogueOption were meant to optionally have attachable conditions that chacked all sorts of other gameplay elements (say, having a certain item in the player's inventory, checking the value of a certain variable held by either the player instance or another object in the scene, etc) and something else that would affect the same things (again, acquiring an inventory item via dialogue, or setting some variables, or whatever) and this is where i got stuck. I thought I could make a series of DialogueCondition derived classes with something like for example
public class ConditionNPCStat : DialogueCondition
{
[SerializableField] private NPC npc;
[SerializableField] private int requiredValue;
public bool IsConditionMet()
{
return (npc.whateverVariableINeedToCheck >= requiredValue);
}
}
but then I found that I can only drag prefabs in a ScriptableObject instance's inspector, so that was all for nothing. Same for non monobeaviour, base classes. I didn't even try Structs because as far as I know you can't derive them from a base struct, and I need DialogueConditions to be all of the same base type so I can create an array of the base type in the nodes/options (the idea was to have the method that return the private array to check each of the array's entries for any unmet condition, create a second array with only the acceptable entries and then return that one).
Any suggestion? Including throwing this whole thing into the bin and trying another approach, if you can point me in the right direction.
For the TLDR, I'd like to build, if possible, a system where I can drag and drop stuff in the editor, and set fields in the inspector. Dialogue nodes and dialogue options may or may not be available depending on conditions which require to check on stuff that happens in other game systems. I would like to keep each system more or less indipendent so that I can both reuse the dialogue assets in other projects, and avoid breaking everything in case I decide to heavily modify one of those systems.
Also this whole thing derailed my train of thoughts and I didn't even start to tackle the problem of interacting with other gameplay elements via dialogue, so suggestions on that topic would be appriciated too.
Thank you in advance, any suggestion is appreciated!