diff --git a/Assets/Code/Scripts/Level/Level01IntroSubtitles.cs.meta b/Assets/Code/Scripts/Level/Level01IntroSubtitles.cs.meta
deleted file mode 100644
index 727a995..0000000
--- a/Assets/Code/Scripts/Level/Level01IntroSubtitles.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: a315c9c77ad8a49238033181ece48806
\ No newline at end of file
diff --git a/Assets/Code/Scripts/Level/Level01IntroSubtitles.cs b/Assets/Code/Scripts/Level/SubtitleSequencePlayer.cs
similarity index 73%
rename from Assets/Code/Scripts/Level/Level01IntroSubtitles.cs
rename to Assets/Code/Scripts/Level/SubtitleSequencePlayer.cs
index c2878f5..7446f11 100644
--- a/Assets/Code/Scripts/Level/Level01IntroSubtitles.cs
+++ b/Assets/Code/Scripts/Level/SubtitleSequencePlayer.cs
@@ -1,13 +1,13 @@
+using System;
using System.Collections;
using UnityEngine;
-using UnityEngine.SceneManagement;
///
-/// Auto-spawns in Level01 and displays an intro subtitle sequence.
+/// Reusable subtitle player that renders and plays subtitle lines loaded from JSON.
///
-public class Level01IntroSubtitles : MonoBehaviour
+public class SubtitleSequencePlayer : MonoBehaviour
{
- [System.Serializable]
+ [Serializable]
private struct SubtitleLine
{
public string speaker;
@@ -15,17 +15,15 @@ public class Level01IntroSubtitles : MonoBehaviour
public float duration;
}
- [Header("Trigger")]
- [SerializeField] private string targetSceneName = "Level01";
- [SerializeField] private float initialDelay = 2.5f;
-
- [Header("Subtitle Sequence")]
- [SerializeField] private SubtitleLine[] lines =
+ [Serializable]
+ private struct SubtitleFile
{
- new SubtitleLine { speaker = "SYSTEME", text = "...Ici, quelque chose cloche.", duration = 2.5f },
- new SubtitleLine { speaker = "SYSTEME", text = "Reste calme. Observe la piece.", duration = 2.5f },
- new SubtitleLine { speaker = "SYSTEME", text = "Trouve une sortie.", duration = 2.2f },
- };
+ public SubtitleLine[] lines;
+ }
+
+ [Header("Optional Default Data")]
+ [Tooltip("Used only if trigger zone calls PlayDefault().")]
+ [SerializeField] private TextAsset defaultSubtitleJson;
[SerializeField] private float typewriterCharsPerSecond = 40f;
[SerializeField] private float fadeDuration = 0.2f;
@@ -40,58 +38,55 @@ public class Level01IntroSubtitles : MonoBehaviour
[SerializeField] private Color speakerColor = new Color(1f, 0.85f, 0.35f, 1f);
[SerializeField] private Color backgroundColor = new Color(0f, 0f, 0f, 0.62f);
- private static bool s_bootstrapped;
-
private string m_currentSpeaker;
private string m_currentText;
private GUIStyle m_textStyle;
private GUIStyle m_speakerStyle;
private Texture2D m_background;
private bool m_isShowing;
+ private bool m_isPlaying;
private float m_alpha;
+ private SubtitleLine[] m_runtimeLines = Array.Empty();
- [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
- private static void ResetBootstrapFlag()
+ public bool IsPlaying => m_isPlaying;
+
+ public bool TryPlay(TextAsset subtitleJson, float initialDelay = 0f)
{
- s_bootstrapped = false;
+ if (m_isPlaying)
+ return false;
+
+ if (!TryReadLinesFromJson(subtitleJson, out SubtitleLine[] parsedLines))
+ return false;
+
+ m_runtimeLines = parsedLines;
+ StartCoroutine(PlaySequence(initialDelay));
+ return true;
}
- [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
- private static void Bootstrap()
+ public bool PlayDefault(float initialDelay = 0f)
{
- if (s_bootstrapped)
- return;
-
- s_bootstrapped = true;
-
- GameObject go = new GameObject(nameof(Level01IntroSubtitles));
- go.hideFlags = HideFlags.DontSave;
- go.AddComponent();
+ return TryPlay(defaultSubtitleJson, initialDelay);
}
- private void Start()
+ private IEnumerator PlaySequence(float initialDelay)
{
- Scene activeScene = SceneManager.GetActiveScene();
- if (activeScene.name != targetSceneName)
+ m_isPlaying = true;
+
+ if (m_runtimeLines == null || m_runtimeLines.Length == 0)
{
- Destroy(gameObject);
- return;
+ m_isPlaying = false;
+ yield break;
}
- StartCoroutine(PlaySequence());
- }
-
- private IEnumerator PlaySequence()
- {
if (initialDelay > 0f)
yield return new WaitForSeconds(initialDelay);
- for (int i = 0; i < lines.Length; i++)
+ for (int i = 0; i < m_runtimeLines.Length; i++)
{
- if (string.IsNullOrWhiteSpace(lines[i].text) || lines[i].duration <= 0f)
+ if (string.IsNullOrWhiteSpace(m_runtimeLines[i].text) || m_runtimeLines[i].duration <= 0f)
continue;
- yield return StartCoroutine(ShowLine(lines[i]));
+ yield return StartCoroutine(ShowLine(m_runtimeLines[i]));
if (gapBetweenLines > 0f)
yield return new WaitForSeconds(gapBetweenLines);
@@ -99,7 +94,31 @@ public class Level01IntroSubtitles : MonoBehaviour
m_currentSpeaker = string.Empty;
m_currentText = string.Empty;
- Destroy(gameObject);
+ m_isPlaying = false;
+ }
+
+ private bool TryReadLinesFromJson(TextAsset subtitleJson, out SubtitleLine[] parsedLines)
+ {
+ parsedLines = Array.Empty();
+
+ if (subtitleJson == null || string.IsNullOrWhiteSpace(subtitleJson.text))
+ return false;
+
+ SubtitleFile file;
+ try
+ {
+ file = JsonUtility.FromJson(subtitleJson.text);
+ }
+ catch
+ {
+ return false;
+ }
+
+ if (file.lines == null || file.lines.Length == 0)
+ return false;
+
+ parsedLines = file.lines;
+ return true;
}
private IEnumerator ShowLine(SubtitleLine line)
@@ -233,7 +252,6 @@ public class Level01IntroSubtitles : MonoBehaviour
clipping = TextClipping.Clip,
};
m_speakerStyle.normal.textColor = speakerColor;
-
}
private void OnDestroy()
diff --git a/Assets/Code/Scripts/Level/SubtitleSequencePlayer.cs.meta b/Assets/Code/Scripts/Level/SubtitleSequencePlayer.cs.meta
new file mode 100644
index 0000000..5ebda90
--- /dev/null
+++ b/Assets/Code/Scripts/Level/SubtitleSequencePlayer.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 4947743d7bc9b4589b9932d429517d3a
\ No newline at end of file
diff --git a/Assets/Code/Scripts/Level/SubtitleTriggerZone.cs b/Assets/Code/Scripts/Level/SubtitleTriggerZone.cs
new file mode 100644
index 0000000..8410dd1
--- /dev/null
+++ b/Assets/Code/Scripts/Level/SubtitleTriggerZone.cs
@@ -0,0 +1,51 @@
+using UnityEngine;
+
+///
+/// Trigger zone that starts a subtitle JSON sequence on a linked SubtitleSequencePlayer.
+/// Put this on the zone collider object, and link the player on your empty object.
+///
+[RequireComponent(typeof(Collider))]
+public class SubtitleTriggerZone : MonoBehaviour
+{
+ [Header("References")]
+ [SerializeField] private SubtitleSequencePlayer subtitlePlayer;
+ [SerializeField] private TextAsset subtitleJson;
+
+ [Header("Playback")]
+ [SerializeField] private float initialDelay = 0f;
+ [SerializeField] private bool oneShot = true;
+
+ private bool m_hasPlayed;
+
+ private void Reset()
+ {
+ Collider col = GetComponent();
+ col.isTrigger = true;
+ }
+
+ private void OnTriggerEnter(Collider other)
+ {
+ if (!IsPlayer(other))
+ return;
+
+ if (oneShot && m_hasPlayed)
+ return;
+
+ if (subtitlePlayer == null)
+ return;
+
+ if (subtitlePlayer.TryPlay(subtitleJson, initialDelay))
+ m_hasPlayed = true;
+ }
+
+ private bool IsPlayer(Collider other)
+ {
+ if (other.CompareTag("Player"))
+ return true;
+
+ if (other.GetComponentInParent() != null)
+ return true;
+
+ return false;
+ }
+}
diff --git a/Assets/Code/Scripts/Level/SubtitleTriggerZone.cs.meta b/Assets/Code/Scripts/Level/SubtitleTriggerZone.cs.meta
new file mode 100644
index 0000000..739926a
--- /dev/null
+++ b/Assets/Code/Scripts/Level/SubtitleTriggerZone.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 33a33c65f75e2443383c2e29bd6bf5f1
\ No newline at end of file
diff --git a/Assets/Code/Subtitles.meta b/Assets/Code/Subtitles.meta
new file mode 100644
index 0000000..9c9ba8f
--- /dev/null
+++ b/Assets/Code/Subtitles.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3952fe191e7e945b3ba35d76408a51a6
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Code/Subtitles/Level01IntroSubtitles.json b/Assets/Code/Subtitles/Level01IntroSubtitles.json
new file mode 100644
index 0000000..afcce3e
--- /dev/null
+++ b/Assets/Code/Subtitles/Level01IntroSubtitles.json
@@ -0,0 +1,19 @@
+{
+ "lines": [
+ {
+ "speaker": "SYSTEME",
+ "text": "...Ici, quelque chose cloche.",
+ "duration": 2.5
+ },
+ {
+ "speaker": "SYSTEME",
+ "text": "Reste calme. Observe la piece.",
+ "duration": 2.5
+ },
+ {
+ "speaker": "SYSTEME",
+ "text": "Trouve une sortie.",
+ "duration": 2.2
+ }
+ ]
+}
diff --git a/Assets/Code/Subtitles/Level01IntroSubtitles.json.meta b/Assets/Code/Subtitles/Level01IntroSubtitles.json.meta
new file mode 100644
index 0000000..3d5ec86
--- /dev/null
+++ b/Assets/Code/Subtitles/Level01IntroSubtitles.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: c4b9d13b29337441dbdb06a8a45e32c3
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant: