For context, I’m creating a visual novel following this tutorial. (I was stuck at 6:22) Prior to this part of the tutorial, everything was working fine. The things I changed here is I replaced it with my own characters.
Please be patient with me since I think there will be a lot of scripts that I have to include here. Let me know if I’m miss something out. Thank you! ![]()
Here’s a testing script I did:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using CHARACTERS;
using DIALOGUE;
namespace TESTING
{
public class TestCharacters : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
// Character Narrator = CharacterManager.instance.CreateCharacter("Narrator");
// Character Effects = CharacterManager.instance.CreateCharacter("Effects");
StartCoroutine(Test());
}
IEnumerator Test()
{
Character Williams = CharacterManager.instance.CreateCharacter("Mr. Williams");
List<string> lines = new List<string>()
{
"Hi, there!",
"My name is Williams.",
"What's your name?",
"Oh, {wa 1} that's very nice."
};
yield return Williams.Say(lines);
Debug.Log("Finished");
}
// Update is called once per frame
void Update()
{
}
}
}
Here’s my Dialogue System:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
namespace DIALOGUE
{
public class DialogueSystem : MonoBehaviour
{
[SerializeField] private DialogueSystemConfigurationSO _config;
public DialogueSystemConfigurationSO config => _config;
public DialogueContainer dialogueContainer = new DialogueContainer();
private ConversationManager conversationManager;
private TextArchitect architect;
public static DialogueSystem instance { get; private set; }
public delegate void DialogueSystemEvent();
public event DialogueSystemEvent onUserPrompt_Next;
public bool isRunningConversation => conversationManager.isRunning;
private void Awake()
{
if (instance == null)
{
instance = this;
Initialize();
}
else
DestroyImmediate(gameObject);
}
bool _initialized = false;
private void Initialize()
{
if (_initialized)
return;
architect = new TextArchitect(dialogueContainer.dialogueText);
conversationManager = new ConversationManager(architect);
}
public void OnUserPrompt_Next()
{
onUserPrompt_Next?.Invoke();
}
public void ShowSpeakerName(string speakerName = "")
{
if (speakerName.ToLower() != "narrator")
dialogueContainer.nameContainer.Show(speakerName);
else
HideSpeakerName();
}
public void HideSpeakerName() => dialogueContainer.nameContainer.Hide();
public Coroutine Say(string speaker, string dialogue)
{
List<string> conversation = new List<string>() { $"{speaker} \"{dialogue}\"" };
return Say(conversation);
}
public Coroutine Say(List<string> conversation)
{
return conversationManager.StartConversation(conversation);
}
}
}
Here’s my Character script:
using DIALOGUE;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace CHARACTERS // BASE CLASS FROM WHICH ALL CHARACTER TYPES DERIVE FROM
{
public abstract class Character
{
public string name = "";
public RectTransform root = null;
public Character(string name)
{
this.name = name;
}
public Coroutine Say(string dialogue) => Say(new List<string> { dialogue} );
public Coroutine Say(List<string> dialogue)
{
return DialogueSystem.instance.Say(dialogue);
}
public enum CharacterType
{
Text,
Sprite,
SpriteSheet
}
}
}
And here’s my conversation manager script:
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using COMMANDS;
namespace DIALOGUE
{
public class ConversationManager
{
private DialogueSystem dialogueSystem => DialogueSystem.instance;
private Coroutine process = null;
public bool isRunning => process != null;
private TextArchitect architect = null;
private bool userPrompt = false;
public ConversationManager(TextArchitect architect)
{
this.architect = architect;
dialogueSystem.onUserPrompt_Next += OnUserPrompt_Next;
}
private void OnUserPrompt_Next()
{
userPrompt = true;
}
public Coroutine StartConversation(List<string> conversation)
{
StopConversation();
process = dialogueSystem.StartCoroutine(RunningConversation(conversation));
return process;
}
public void StopConversation()
{
if (!isRunning)
return;
dialogueSystem.StopCoroutine(process);
process = null;
}
IEnumerator RunningConversation(List<string> conversation)
{
for (int i = 0; i < conversation.Count; i++)
{
//Dont show any blank lines or try to run any logic on them
if (string.IsNullOrWhiteSpace(conversation[i]))
continue;
DIALOGUE_LINE line = DialogueParser.Parse(conversation[i]);
//show dialogue
if (line.hasDialogue)
yield return Line_RunDialogue(line);
//Run any commands
if (line.hasCommands)
yield return Line_RunCommands(line);
if (line.hasDialogue)
//Wait for User Input
yield return WaitForUserInput();
}
}
IEnumerator Line_RunDialogue(DIALOGUE_LINE line)
{
//Show or hide the speaker name if there is one present.
if (line.hasSpeaker)
dialogueSystem.ShowSpeakerName(line.speakerData.displayname);
//Build dialogue
yield return BuildLineSegments(line.dialogueData);
}
IEnumerator Line_RunCommands(DIALOGUE_LINE line)
{
List<DL_COMMAND_DATA.Command> commands = line.commandData.commands;
foreach(DL_COMMAND_DATA.Command command in commands)
{
if (command.waitForCompletion)
yield return CommandManager.instance.Execute(command.name, command.arguments);
else
CommandManager.instance.Execute(command.name, command.arguments);
}
yield return null;
}
IEnumerator BuildLineSegments(DL_DIALOGUE_DATA line)
{
for(int i = 0; i < line.segments.Count; i++)
{
DL_DIALOGUE_DATA.DIALOGUE_SEGMENT segment = line.segments[i];
yield return WaitForDialogueSegmentSignalToBeTriggered(segment);
yield return BuildDialogue(segment.dialogue, segment.appendText);
}
}
IEnumerator WaitForDialogueSegmentSignalToBeTriggered(DL_DIALOGUE_DATA.DIALOGUE_SEGMENT segment)
{
switch(segment.startSignal)
{
case DL_DIALOGUE_DATA.DIALOGUE_SEGMENT.StartSignal.C:
case DL_DIALOGUE_DATA.DIALOGUE_SEGMENT.StartSignal.A:
yield return WaitForUserInput();
break;
case DL_DIALOGUE_DATA.DIALOGUE_SEGMENT.StartSignal.WC:
case DL_DIALOGUE_DATA.DIALOGUE_SEGMENT.StartSignal.WA:
yield return new WaitForSeconds(segment.signalDelay);
break;
default:
break;
}
}
IEnumerator BuildDialogue(string dialogue, bool append = false)
{
if (!append)
architect.Build(dialogue);
else
architect.Append(dialogue);
while (architect.isBuilding) gawing hindi Hurryup pag sakin. Check kung pwede force complete lang p
{
if (userPrompt)
{
if (!architect.hurryUp)
architect.hurryUp = true;
else
architect.ForceComplete(); /
userPrompt = false;
}
yield return null;
}
}
IEnumerator WaitForUserInput()
{
while(!userPrompt)
yield return null;
userPrompt = false;
}
}
}