Working regular dialogue and speech bubble. Item conditions need work
This commit is contained in:
@@ -16,6 +16,7 @@ namespace Dialogue
|
||||
private RuntimeDialogueNode currentNode;
|
||||
private int currentLineIndex;
|
||||
private bool initialized = false;
|
||||
private SpeechBubble speechBubble;
|
||||
|
||||
// Properties
|
||||
public bool IsActive { get; private set; }
|
||||
@@ -37,10 +38,33 @@ namespace Dialogue
|
||||
ItemManager.Instance.OnCorrectItemSlotted += OnAnyItemSlotted;
|
||||
}
|
||||
|
||||
speechBubble = GetComponentInChildren<SpeechBubble>();
|
||||
|
||||
if (speechBubble == null)
|
||||
{
|
||||
Debug.LogError("SpeechBubble component is missing on Dialogue Component");
|
||||
}
|
||||
|
||||
// Auto-start the dialogue
|
||||
StartDialogue();
|
||||
|
||||
var interactable = GetComponent<Interactable>();
|
||||
if (interactable != null)
|
||||
{
|
||||
interactable.characterArrived.AddListener(OnCharacterArrived);
|
||||
}
|
||||
|
||||
if (HasAnyLines())
|
||||
{
|
||||
speechBubble.SetText(". . .");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnCharacterArrived()
|
||||
{
|
||||
speechBubble.SetText(GetCurrentDialogueLine());
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
// Unregister from events
|
||||
@@ -314,6 +338,49 @@ namespace Dialogue
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the dialogue component has any lines available to serve
|
||||
/// </summary>
|
||||
/// <returns>True if there are lines available, false otherwise</returns>
|
||||
public bool HasAnyLines()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
// If not initialized yet but has a dialogue graph, it will have lines when initialized
|
||||
return dialogueGraph != null;
|
||||
}
|
||||
|
||||
// No lines if dialogue is not active or is completed
|
||||
if (!IsActive || IsCompleted || currentNode == null)
|
||||
return false;
|
||||
|
||||
// Check if the current node has any lines
|
||||
if (currentNode.dialogueLines.Count > 0)
|
||||
{
|
||||
// If we're not at the end of the lines or we loop through them
|
||||
if (currentLineIndex < currentNode.dialogueLines.Count - 1 || currentNode.loopThroughLines)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we're at the end of lines but not waiting for a condition and have a next node
|
||||
if (!IsWaitingForCondition() && !string.IsNullOrEmpty(currentNode.nextNodeID))
|
||||
{
|
||||
// We need to check if the next node would have lines
|
||||
RuntimeDialogueNode nextNode = dialogueGraph.GetNodeByID(currentNode.nextNodeID);
|
||||
return nextNode != null && (nextNode.dialogueLines.Count > 0 || nextNode.nodeType != RuntimeDialogueNodeType.End);
|
||||
}
|
||||
}
|
||||
|
||||
// Special case for conditional nodes waiting on conditions
|
||||
if (IsWaitingForCondition())
|
||||
{
|
||||
return currentNode.dialogueLines.Count > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Editor functionality
|
||||
public void SetDialogueGraph(RuntimeDialogueGraph graph)
|
||||
{
|
||||
|
||||
193
Assets/Scripts/Dialogue/SpeechBubble.cs
Normal file
193
Assets/Scripts/Dialogue/SpeechBubble.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Dialogue
|
||||
{
|
||||
/// <summary>
|
||||
/// Display mode for the speech bubble text
|
||||
/// </summary>
|
||||
public enum TextDisplayMode
|
||||
{
|
||||
Instant, // Display all text at once
|
||||
Typewriter // Display text one character at a time
|
||||
}
|
||||
|
||||
[AddComponentMenu("Apple Hills/Dialogue/Speech Bubble")]
|
||||
public class SpeechBubble : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TextMeshProUGUI textDisplay;
|
||||
[SerializeField] private TextDisplayMode displayMode = TextDisplayMode.Typewriter;
|
||||
[SerializeField] private float typewriterSpeed = 0.05f; // Time between characters in seconds
|
||||
[SerializeField] private AudioSource typingSoundSource;
|
||||
[SerializeField] private float typingSoundFrequency = 3; // Play sound every X characters
|
||||
[SerializeField] private bool useRichText = true; // Whether to respect rich text tags
|
||||
|
||||
private Coroutine typewriterCoroutine;
|
||||
private string currentFullText = string.Empty;
|
||||
private bool isVisible = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show the speech bubble
|
||||
/// </summary>
|
||||
public void Show()
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
isVisible = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hide the speech bubble
|
||||
/// </summary>
|
||||
public void Hide()
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
isVisible = false;
|
||||
|
||||
// Stop any ongoing typewriter effect
|
||||
if (typewriterCoroutine != null)
|
||||
{
|
||||
StopCoroutine(typewriterCoroutine);
|
||||
typewriterCoroutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle visibility of the speech bubble
|
||||
/// </summary>
|
||||
public void Toggle()
|
||||
{
|
||||
if (isVisible)
|
||||
Hide();
|
||||
else
|
||||
Show();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the text to display in the speech bubble
|
||||
/// </summary>
|
||||
/// <param name="text">Text to display</param>
|
||||
public void SetText(string text)
|
||||
{
|
||||
if (textDisplay == null)
|
||||
{
|
||||
Debug.LogError("SpeechBubble: TextMeshProUGUI component is not assigned!");
|
||||
return;
|
||||
}
|
||||
|
||||
currentFullText = text;
|
||||
|
||||
// Stop any existing typewriter effect
|
||||
if (typewriterCoroutine != null)
|
||||
{
|
||||
StopCoroutine(typewriterCoroutine);
|
||||
typewriterCoroutine = null;
|
||||
}
|
||||
|
||||
// Display text based on the selected mode
|
||||
if (displayMode == TextDisplayMode.Instant)
|
||||
{
|
||||
textDisplay.text = text;
|
||||
}
|
||||
else // Typewriter mode
|
||||
{
|
||||
textDisplay.text = string.Empty; // Clear the text initially
|
||||
typewriterCoroutine = StartCoroutine(TypewriterEffect(text));
|
||||
}
|
||||
|
||||
// Make sure the bubble is visible when setting text
|
||||
if (!isVisible)
|
||||
Show();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change the display mode
|
||||
/// </summary>
|
||||
/// <param name="mode">New display mode</param>
|
||||
public void SetDisplayMode(TextDisplayMode mode)
|
||||
{
|
||||
displayMode = mode;
|
||||
|
||||
// If we're changing modes while text is displayed, refresh it
|
||||
if (!string.IsNullOrEmpty(currentFullText))
|
||||
{
|
||||
SetText(currentFullText);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Skip the typewriter effect and show the full text immediately
|
||||
/// </summary>
|
||||
public void SkipTypewriter()
|
||||
{
|
||||
if (typewriterCoroutine != null)
|
||||
{
|
||||
StopCoroutine(typewriterCoroutine);
|
||||
typewriterCoroutine = null;
|
||||
textDisplay.text = currentFullText;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the speed of the typewriter effect
|
||||
/// </summary>
|
||||
/// <param name="charactersPerSecond">Characters per second</param>
|
||||
public void SetTypewriterSpeed(float charactersPerSecond)
|
||||
{
|
||||
if (charactersPerSecond <= 0)
|
||||
{
|
||||
Debug.LogError("SpeechBubble: Typewriter speed must be greater than 0!");
|
||||
return;
|
||||
}
|
||||
|
||||
typewriterSpeed = 1f / charactersPerSecond;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Coroutine that gradually reveals text one character at a time
|
||||
/// </summary>
|
||||
private IEnumerator TypewriterEffect(string text)
|
||||
{
|
||||
int visibleCount = 0;
|
||||
int characterCount = 0;
|
||||
|
||||
while (visibleCount < text.Length)
|
||||
{
|
||||
// Skip rich text tags if enabled
|
||||
if (useRichText && visibleCount < text.Length && text[visibleCount] == '<')
|
||||
{
|
||||
// Find the end of the tag
|
||||
int tagEnd = text.IndexOf('>', visibleCount);
|
||||
if (tagEnd != -1)
|
||||
{
|
||||
// Include the entire tag at once
|
||||
visibleCount = tagEnd + 1;
|
||||
textDisplay.text = text.Substring(0, visibleCount);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Reveal the next character
|
||||
visibleCount++;
|
||||
characterCount++;
|
||||
textDisplay.text = text.Substring(0, visibleCount);
|
||||
|
||||
// Play typing sound at specified frequency
|
||||
if (typingSoundSource != null && characterCount % typingSoundFrequency == 0)
|
||||
{
|
||||
typingSoundSource.Play();
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(typewriterSpeed);
|
||||
}
|
||||
|
||||
typewriterCoroutine = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Dialogue/SpeechBubble.cs.meta
Normal file
3
Assets/Scripts/Dialogue/SpeechBubble.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb3605ae81a54d2689504e0cd456ac27
|
||||
timeCreated: 1758973942
|
||||
Reference in New Issue
Block a user