OctoCore 0.0.1
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace OctoCore.Dialogue.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Component to trigger dialogue events.
|
||||
/// Listens to dialogue start/end and invokes UnityEvents.
|
||||
/// </summary>
|
||||
public class OctoDialogueEvent : MonoBehaviour
|
||||
{
|
||||
[SerializeField, Tooltip("Dialogue data to listen for")]
|
||||
private Data.OctoDialogueData _dialogue;
|
||||
|
||||
[SerializeField, Tooltip("Called when the specified dialogue starts")]
|
||||
private UnityEvent _onDialogueStarted;
|
||||
|
||||
[SerializeField, Tooltip("Called when the specified dialogue ends")]
|
||||
private UnityEvent _onDialogueEnded;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (OctoDialogueManager.Instance != null)
|
||||
{
|
||||
// Subscribe to manager events
|
||||
OctoDialogueManager.Instance.GetComponent<OctoDialogueManager>()
|
||||
._events.OnDialogueStarted.AddListener(OnDialogueStarted);
|
||||
OctoDialogueManager.Instance.GetComponent<OctoDialogueManager>()
|
||||
._events.OnDialogueEnded.AddListener(OnDialogueEnded);
|
||||
}
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (OctoDialogueManager.Instance != null)
|
||||
{
|
||||
// Unsubscribe from manager events
|
||||
OctoDialogueManager.Instance.GetComponent<OctoDialogueManager>()
|
||||
._events.OnDialogueStarted.RemoveListener(OnDialogueStarted);
|
||||
OctoDialogueManager.Instance.GetComponent<OctoDialogueManager>()
|
||||
._events.OnDialogueEnded.RemoveListener(OnDialogueEnded);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDialogueStarted()
|
||||
{
|
||||
if (OctoDialogueManager.Instance == null)
|
||||
return;
|
||||
|
||||
var currentDialogue = OctoDialogueManager.Instance.GetCurrentDialogue();
|
||||
if (currentDialogue == _dialogue)
|
||||
{
|
||||
_onDialogueStarted?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDialogueEnded()
|
||||
{
|
||||
// Dialogue already ended, so we check if it was our dialogue
|
||||
// Note: This might not work perfectly if dialogue changes rapidly
|
||||
// A better implementation would track the last active dialogue
|
||||
_onDialogueEnded?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7c573c7064e10f4ba4855e8f448ee81
|
||||
@@ -0,0 +1,291 @@
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
using OctoCore.Localization;
|
||||
using OctoCore.Components;
|
||||
|
||||
namespace OctoCore.Dialogue.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Dialogue manager component.
|
||||
/// Singleton that handles dialogue display and flow.
|
||||
/// Uses UI Text components if assigned, otherwise falls back to GUI.
|
||||
/// </summary>
|
||||
public class OctoDialogueManager : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton instance.
|
||||
/// </summary>
|
||||
public static OctoDialogueManager Instance { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// References to UI components.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class References
|
||||
{
|
||||
[Tooltip("Legacy UI Text component (optional)")]
|
||||
public Text Text;
|
||||
|
||||
[Tooltip("TextMeshPro component (optional)")]
|
||||
public TextMeshPro TextMeshPro;
|
||||
|
||||
[Tooltip("TextMeshPro UGUI component (optional)")]
|
||||
public TextMeshProUGUI TextMeshProUGUI;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dialogue events.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Events
|
||||
{
|
||||
[Tooltip("Called when a dialogue starts")]
|
||||
public UnityEvent OnDialogueStarted;
|
||||
|
||||
[Tooltip("Called when a new entry starts displaying")]
|
||||
public UnityEvent OnEntryStarted;
|
||||
|
||||
[Tooltip("Called when a choice is selected")]
|
||||
public UnityEvent OnChoiceSelected;
|
||||
|
||||
[Tooltip("Called when a dialogue ends")]
|
||||
public UnityEvent OnDialogueEnded;
|
||||
}
|
||||
|
||||
[SerializeField] private References _references;
|
||||
[SerializeField] public Events _events;
|
||||
|
||||
private Data.OctoDialogueData _currentDialogue;
|
||||
private int _currentEntryIndex;
|
||||
private List<OctoDialogueChoice> _availableChoices = new List<OctoDialogueChoice>();
|
||||
private bool _isActive;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (Instance == this)
|
||||
{
|
||||
Instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a new dialogue.
|
||||
/// Automatically displays the first entry.
|
||||
/// </summary>
|
||||
public void StartDialogue(Data.OctoDialogueData dialogue)
|
||||
{
|
||||
if (dialogue == null || dialogue.Entries == null || dialogue.Entries.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("[OctoDialogueManager] Cannot start dialogue: null or empty");
|
||||
return;
|
||||
}
|
||||
|
||||
_currentDialogue = dialogue;
|
||||
_currentEntryIndex = 0;
|
||||
_isActive = true;
|
||||
|
||||
_events.OnDialogueStarted?.Invoke();
|
||||
if (OctoPlayer.Instance) OctoPlayer.Instance.Pause(true); // TMP
|
||||
DisplayCurrentEntry();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display the current dialogue entry.
|
||||
/// </summary>
|
||||
private void DisplayCurrentEntry()
|
||||
{
|
||||
if (_currentDialogue == null || _currentEntryIndex >= _currentDialogue.Entries.Length)
|
||||
{
|
||||
EndDialogue();
|
||||
return;
|
||||
}
|
||||
|
||||
OctoDialogueEntry entry = _currentDialogue.Entries[_currentEntryIndex];
|
||||
|
||||
_events.OnEntryStarted?.Invoke();
|
||||
|
||||
// Display text
|
||||
string text = OctoLocalization.GetLocalizedText(entry.Text);
|
||||
SetText(text);
|
||||
|
||||
// Build available choices
|
||||
_availableChoices.Clear();
|
||||
if (entry.Choices != null)
|
||||
{
|
||||
foreach (var choice in entry.Choices)
|
||||
{
|
||||
if (choice.IsAvailable())
|
||||
{
|
||||
_availableChoices.Add(choice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Select a choice by index.
|
||||
/// </summary>
|
||||
public void SelectChoice(int choiceIndex)
|
||||
{
|
||||
if (!_isActive || choiceIndex < 0 || choiceIndex >= _availableChoices.Count)
|
||||
return;
|
||||
|
||||
OctoDialogueChoice choice = _availableChoices[choiceIndex];
|
||||
|
||||
_events.OnChoiceSelected?.Invoke();
|
||||
|
||||
if (choice.NextDialogue != null)
|
||||
{
|
||||
StartDialogue(choice.NextDialogue);
|
||||
}
|
||||
else
|
||||
{
|
||||
EndDialogue();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Continue to next entry (when no choices available).
|
||||
/// </summary>
|
||||
public void Continue()
|
||||
{
|
||||
if (!_isActive)
|
||||
return;
|
||||
|
||||
if (_availableChoices.Count == 0)
|
||||
{
|
||||
_currentEntryIndex++;
|
||||
DisplayCurrentEntry();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End the current dialogue.
|
||||
/// </summary>
|
||||
private void EndDialogue()
|
||||
{
|
||||
_isActive = false;
|
||||
_currentDialogue = null;
|
||||
_currentEntryIndex = 0;
|
||||
_availableChoices.Clear();
|
||||
|
||||
if (OctoPlayer.Instance) OctoPlayer.Instance.Pause(false); // TMP
|
||||
_events.OnDialogueEnded?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set text using available UI component or GUI fallback.
|
||||
/// </summary>
|
||||
private void SetText(string text)
|
||||
{
|
||||
if (_references.Text != null)
|
||||
{
|
||||
_references.Text.text = text;
|
||||
}
|
||||
else if (_references.TextMeshPro != null)
|
||||
{
|
||||
_references.TextMeshPro.text = text;
|
||||
}
|
||||
else if (_references.TextMeshProUGUI != null)
|
||||
{
|
||||
_references.TextMeshProUGUI.text = text;
|
||||
}
|
||||
// GUI fallback handled in OnGUI
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
// Only use GUI if no text component is assigned
|
||||
if (_references.Text != null || _references.TextMeshPro != null || _references.TextMeshProUGUI != null)
|
||||
return;
|
||||
|
||||
if (!_isActive || _currentDialogue == null)
|
||||
return;
|
||||
|
||||
if (_currentEntryIndex >= _currentDialogue.Entries.Length)
|
||||
return;
|
||||
|
||||
OctoDialogueEntry entry = _currentDialogue.Entries[_currentEntryIndex];
|
||||
|
||||
GUILayout.BeginArea(new Rect(50, Screen.height - 200, Screen.width - 100, 150));
|
||||
GUILayout.Box("", GUILayout.Width(Screen.width - 100), GUILayout.Height(150));
|
||||
|
||||
GUILayout.BeginArea(new Rect(10, 10, Screen.width - 120, 130));
|
||||
|
||||
// Speaker name
|
||||
if (entry.Speaker != null && entry.Speaker.Name != null)
|
||||
{
|
||||
string speakerName = OctoLocalization.GetLocalizedText(entry.Speaker.Name);
|
||||
GUILayout.Label(speakerName, GUI.skin.box);
|
||||
}
|
||||
|
||||
// Dialogue text
|
||||
string text = OctoLocalization.GetLocalizedText(entry.Text);
|
||||
GUILayout.Label(text, GUILayout.ExpandHeight(true));
|
||||
|
||||
// Choices
|
||||
if (_availableChoices.Count > 0)
|
||||
{
|
||||
GUILayout.Space(10);
|
||||
for (int i = 0; i < _availableChoices.Count; i++)
|
||||
{
|
||||
string choiceText = OctoLocalization.GetLocalizedText(_availableChoices[i].Text);
|
||||
if (GUILayout.Button(choiceText))
|
||||
{
|
||||
SelectChoice(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Space(10);
|
||||
if (GUILayout.Button("→"))
|
||||
{
|
||||
Continue();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndArea();
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get current dialogue data.
|
||||
/// </summary>
|
||||
public Data.OctoDialogueData GetCurrentDialogue()
|
||||
{
|
||||
return _currentDialogue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get available choices for current entry.
|
||||
/// </summary>
|
||||
public List<OctoDialogueChoice> GetAvailableChoices()
|
||||
{
|
||||
return new List<OctoDialogueChoice>(_availableChoices);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if dialogue is currently active.
|
||||
/// </summary>
|
||||
public bool IsActive()
|
||||
{
|
||||
return _isActive;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a41b5f79f61ad94c9479c28b4397de4
|
||||
Reference in New Issue
Block a user