Essential Systems
  • Welcome
  • Getting Started
    • Quickstart
    • ‼️Installation Guide
  • Systems
    • Object Pooling
    • Audio
    • Camera Shake
    • Console
    • Dialogue
    • Interface
    • Inputs
    • Proximity
    • Spawner
    • UI Components
    • Particles
    • Objects
    • Editor
    • Scenes
    • Utility
Powered by GitBook
On this page
  • Conditions
  • Initializing dialogues
  1. Systems

Dialogue

In most games, a system for displaying dialogue is essential, whether for NPC conversations, tutorials, or other in-game messages. Here we display a system that helps you create these dialogues easily

PreviousConsoleNextInterface

Last updated 3 months ago

You can create a new dialogue by going to Create/Essentials/Dialogue/Dialogue. Here we can configure a couple of settings.

The actual dialogue data is what's called the Header and the Description. To create a full conversation we can create new Branches. A Branch is a link to another dialogue instance. For example, if we want to transition from dialogue A to B, we create a new Branch and assign dialogue B as the Next dialogue.

For the dialogue to understand which and when it should transition to another branch, we use Conditions. A condition can be for example; Done (whenever dialogue has finished), Skip (if a user presses a button) etc. You can create and locate new conditions under the Create/Essentials/Dialogue/Conditions.

Conditions

To create a custom condition, we do the following:

// This creates a ScriptableObject that is located wherever all the other conditions are
[CreateAssetMenu(fileName = "Test [CONDITION]", menuName = "Essentials/Dialogue/Conditions/Test", order = 0)]
public class TestCondition : Condition // we must extend Condition
{
    // if Evaluate() is NOT overriden, it will return a protected variable called isSatisfied.
    //     we can change this variable wherever we want directly, or call SetTrue() or SetFalse().

    // we don't NEED to override this, only if we want some initilization code
    public override void Init(DialogueManager manager)
    {
        base.Init(manager); // make sure to call the base.Init()
        // do some initialize code
    }
    
    // we don't NEED to override this, only if we want some dispose code
    public override void Dispose()
    {
        base.Init(manager); // usually, we call base.Init() here.
        // do some dispose code
    }
    
    // we don't NEED to override this, only if we want to return something else, rather than isSatisfied
    public override bool Evaluate()
    {
        return // return some code to evaluate.
    }
}

For example, to create a skip condition we write:

// This creates a ScriptableObject that is located wherever all the other conditions are
[CreateAssetMenu(fileName = "Skip [CONDITION]", menuName = "Essentials/Dialogue/Conditions/Skip", order = 0)]
public class SkipCondition : Condition // we must extend Condition
{
    public override bool Evaluate()
    {
        return Input.GetKeyDown(KeyCode.Space);
    }
}

Or, if we just want to create a condition that auto-selects the branch when the dialogue is finished:

// This creates a ScriptableObject that is located wherever all the other conditions are
[CreateAssetMenu(fileName = "Done [CONDITION]", menuName = "Essentials/Dialogue/Conditions/Done", order = 0)]
public class DoneCondition : Condition // we must extend Condition
{
    public override void Init(DialogueManager manager)
    {
        base.Init(manager);
        manager.onDialogueFinished += SetTrue; // we subscribes to the dialogue's finish event to set this condition true.
    }
    
    public override void Dispose()
    {
        base.Dispose();
        manager.onDialogueFinished -= SetTrue; // we MUST also remember to unsubscribe to avoid leak over dialogues.
    }
}

Initializing dialogues

Dialogues can appear visually in many different scenarios. This is why we created an abstract DialogueManager that you can extend wherever you need a dialogue to appear.

For example; if we want to show the dialogue in a UI we could create a dialogue manager like this:

public class DialogueUI : DialogueManager // extend the dialogue manager
{
    public TextMeshProUGUI headerText, descriptionText;
    
    // this must exist in any class that extends DialogueManager
    //     it is called whenever the dialogue has finished.
    protected override void Hide()
    {
        headerText.text = ""; // clear the header
        descriptionText.text = ""; // clear the description
    }
    
    // this must exist in any class that extends DialogueManager
    //     it is called whenever a new dialogue is supposed to show
    protected override void Show(Dialogue dialogue)
    {
        headerText.text = dialogue.Header; // we set the header to the dialogue's header
        descriptionText.text = dialogue.Description; // we set the description to the dialogue's description
        
        StartCoroutine(DelayFinish()); // we delay the finish a bit to allow the player to see the dialogue before it finishes.
        // alt. we can use the Thread.Delay(this, Finish, 1) that comes with the package as a utility function.
    }
    
    private IEnumerator DelayFinish()
    {
        yield return new WaitForSeconds(5); // waits 5 seconds.
        Finish(); // this must always be called somewhere in a DialogueManager whenever the dialogue is supposed to be finished.
    }
}

For more examples, we can see the dialogue demo.

To later start a dialogue, we can simply call:

public DialogueManager manager; // some reference to any manager (could be a UI)
public Dialogue dialogue; // some reference to the dialogue to show

manager.Run(dialogue); // run the new dialogue (could be placed in a Start() or any other desired place.