I am currently writing a dialogue system for our game. I am still learning Unity, our game up until this point has been written in the old GameMaker Studio 1 and the project has definitely outgrown that engine. I would like this system to be as generic as possible so it could possibly be reused in a different project.
The problem: I am currently struggling to think of an elegant way to send messages from my Usable components to the DialogueSystemController which lives on a Dialogue Manager game object in the scene.
The easy solution would be a Singleton class with a public method called StartConversation or something similar, but having read the criticisms of that pattern, I would like to avoid those. Currently, the DialogueSystemController uses FindObjectsOfType() on Start to get a list of all usables in the scene and stores them in a list. Then, it iterates through that list and subscribes to each Usable’s UsableUsed event.
public class DialogueSystemController : MonoBehaviour
{
private List<Usable> usables;
private void Start()
{
usables = new List<Usable>();
Usable[] usablesInScene = FindObjectsOfType<Usable>();
foreach (Usable usable in usablesInScene)
{
usables.Add(usable);
usable.UsableUsed += OnUsableUsed;
}
}
// [irrelevant code omitted]
}
public class Usable : MonoBehaviour
{
[SerializeField]
private Conversation initialConversation = null;
public event EventHandler<UsableUsedArgs> UsableUsed;
[ContextMenu("Use Usable")]
public void OnUse()
{
Debug.Log($"Usable {name} was used.");
UsableUsedArgs args = new UsableUsedArgs();
args.Conversation = initialConversation;
UsableUsed?.Invoke(this, args);
}
}
This works, but it kind of feels like a hack. And I can imagine the number of references I have to keep track of and/or pass around will only grow as I add more components/features to the system. And also, eventually I would like to write a component that will expose some UnityEvents relating to the dialogue system so outside systems can hook into it.
I have considered [this] solution by Game Dev Guide. I would make an events class purely for “internal” use by the dialogue system, but this would also use a Singleton.
Any thoughts on whether my current solution would continue to work? Are singletons okay to use as long as they are only for internal use of a separate system?