revival/game/Assets/Scripts/Dialogue/DialogueSystem.cs

119 lines
3.1 KiB
C#

using System;
using System.Collections.Generic;
using FMOD.Studio;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
[CreateAssetMenu(menuName = "KernelPanic/Dialogue/Dialogue System")]
public partial class DialogueSystem : ScriptableObject
{
[SerializeField] private DialogueSettings _settings;
// https://stackoverflow.com/questions/2282476/actiont-vs-delegate-event
public event EventHandler<DialogueLine> onDialogueLine;
private readonly Dictionary<string, string> _fmodKeyCache = new Dictionary<string, string>();
// a list of dialogue keys that have already been spoken
private readonly List<string> _usedKeys = new List<string>();
private void OnEnable()
{
_fmodKeyCache.Clear();
_usedKeys.Clear();
// cache all dialogue keys for FMOD at start to avoid allocations later
foreach (var key in DialogueDatabase.Keys)
{
_fmodKeyCache[key] = $"{_settings.FMODPrefix}{key}";
}
}
// noRepeat locks this key off from further use. further attempts to use the key will be discarded
public void PlayLine(string key, bool noRepeat = true)
{
if (noRepeat)
{
if (_usedKeys.Contains(key)) return;
_usedKeys.Add(key);
}
// retrieve cached key
var fmodKey = _fmodKeyCache[key];
EventDescription? eventDescription = null;
try
{
eventDescription = FMODUnity.RuntimeManager.GetEventDescription(fmodKey);
}
catch (FMODUnity.EventNotFoundException e)
{
Debug.LogWarning($"no FMOD event {fmodKey}");
}
DialogueLine dl;
dl.text = DialogueDatabase.ReadDialogue(key);
// default duration to show ui elements for
dl.duration = _settings.HideAfter;
// read audio data out of FMOD, check if event exists
if (eventDescription.HasValue)
{
// assign values and play audio
// get dialogue line duration from FMOD
eventDescription.Value.getLength(out int ms);
// get length gives us a value in milliseconds so it needs to be converted to seconds
// before assignment
dl.duration = ms / 1000f;
// event is valid
FMODUnity.RuntimeManager.PlayOneShot(fmodKey);
}
onDialogueLine?.Invoke(this, dl);
}
}
public struct DialogueLine
{
public string text;
public float duration;
}
#region Editor
#if UNITY_EDITOR
[CustomEditor(typeof(DialogueSystem))]
public class DialogueSystemEditor : Editor
{
private DialogueSystem _dialogue;
private string _key;
private void OnEnable()
{
_dialogue = target as DialogueSystem;
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
_key = EditorGUILayout.TextField("key", _key);
if (GUILayout.Button("Play Line"))
{
_dialogue.PlayLine(_key);
}
}
}
#endif
#endregion