feat : add Level01IntroSubtitles script for intro subtitle sequence
This commit is contained in:
8
Assets/Code/Scripts/Level.meta
Normal file
8
Assets/Code/Scripts/Level.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e7b9c54377674993a7922f84e9cfcce
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
244
Assets/Code/Scripts/Level/Level01IntroSubtitles.cs
Normal file
244
Assets/Code/Scripts/Level/Level01IntroSubtitles.cs
Normal file
@@ -0,0 +1,244 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
/// <summary>
|
||||
/// Auto-spawns in Level01 and displays an intro subtitle sequence.
|
||||
/// </summary>
|
||||
public class Level01IntroSubtitles : MonoBehaviour
|
||||
{
|
||||
[System.Serializable]
|
||||
private struct SubtitleLine
|
||||
{
|
||||
public string speaker;
|
||||
public string text;
|
||||
public float duration;
|
||||
}
|
||||
|
||||
[Header("Trigger")]
|
||||
[SerializeField] private string targetSceneName = "Level01";
|
||||
[SerializeField] private float initialDelay = 2.5f;
|
||||
|
||||
[Header("Subtitle Sequence")]
|
||||
[SerializeField] private SubtitleLine[] lines =
|
||||
{
|
||||
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 },
|
||||
};
|
||||
|
||||
[SerializeField] private float typewriterCharsPerSecond = 40f;
|
||||
[SerializeField] private float fadeDuration = 0.2f;
|
||||
[SerializeField] private float gapBetweenLines = 0.15f;
|
||||
|
||||
[Header("Visual")]
|
||||
[SerializeField] private int fontSize = 28;
|
||||
[SerializeField] private int speakerFontSize = 18;
|
||||
[SerializeField] private float horizontalPadding = 28f;
|
||||
[SerializeField] private float bottomOffset = 56f;
|
||||
[SerializeField] private Color textColor = new Color(1f, 1f, 1f, 1f);
|
||||
[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 float m_alpha;
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void ResetBootstrapFlag()
|
||||
{
|
||||
s_bootstrapped = false;
|
||||
}
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
|
||||
private static void Bootstrap()
|
||||
{
|
||||
if (s_bootstrapped)
|
||||
return;
|
||||
|
||||
s_bootstrapped = true;
|
||||
|
||||
GameObject go = new GameObject(nameof(Level01IntroSubtitles));
|
||||
go.hideFlags = HideFlags.DontSave;
|
||||
go.AddComponent<Level01IntroSubtitles>();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Scene activeScene = SceneManager.GetActiveScene();
|
||||
if (activeScene.name != targetSceneName)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
StartCoroutine(PlaySequence());
|
||||
}
|
||||
|
||||
private IEnumerator PlaySequence()
|
||||
{
|
||||
if (initialDelay > 0f)
|
||||
yield return new WaitForSeconds(initialDelay);
|
||||
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(lines[i].text) || lines[i].duration <= 0f)
|
||||
continue;
|
||||
|
||||
yield return StartCoroutine(ShowLine(lines[i]));
|
||||
|
||||
if (gapBetweenLines > 0f)
|
||||
yield return new WaitForSeconds(gapBetweenLines);
|
||||
}
|
||||
|
||||
m_currentSpeaker = string.Empty;
|
||||
m_currentText = string.Empty;
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
private IEnumerator ShowLine(SubtitleLine line)
|
||||
{
|
||||
m_currentSpeaker = line.speaker;
|
||||
m_currentText = string.Empty;
|
||||
m_isShowing = true;
|
||||
|
||||
if (fadeDuration > 0f)
|
||||
{
|
||||
float fadeIn = 0f;
|
||||
while (fadeIn < fadeDuration)
|
||||
{
|
||||
fadeIn += Time.deltaTime;
|
||||
m_alpha = Mathf.Clamp01(fadeIn / fadeDuration);
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_alpha = 1f;
|
||||
}
|
||||
|
||||
float typeTime = 0f;
|
||||
int totalChars = line.text.Length;
|
||||
if (typewriterCharsPerSecond > 0f)
|
||||
{
|
||||
while (m_currentText.Length < totalChars)
|
||||
{
|
||||
typeTime += Time.deltaTime;
|
||||
int visibleChars = Mathf.Clamp(Mathf.FloorToInt(typeTime * typewriterCharsPerSecond), 0, totalChars);
|
||||
m_currentText = line.text.Substring(0, visibleChars);
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_currentText = line.text;
|
||||
}
|
||||
|
||||
float holdDuration = Mathf.Max(0f, line.duration - (typewriterCharsPerSecond > 0f ? typeTime : 0f));
|
||||
if (holdDuration > 0f)
|
||||
yield return new WaitForSeconds(holdDuration);
|
||||
|
||||
if (fadeDuration > 0f)
|
||||
{
|
||||
float fadeOut = fadeDuration;
|
||||
while (fadeOut > 0f)
|
||||
{
|
||||
fadeOut -= Time.deltaTime;
|
||||
m_alpha = Mathf.Clamp01(fadeOut / fadeDuration);
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
m_alpha = 0f;
|
||||
m_isShowing = false;
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (!m_isShowing || string.IsNullOrEmpty(m_currentText))
|
||||
return;
|
||||
|
||||
EnsureStyles();
|
||||
|
||||
float maxWidth = Mathf.Min(Screen.width - 24f, 940f);
|
||||
float textWidth = maxWidth - horizontalPadding * 2f;
|
||||
float speakerHeight = string.IsNullOrEmpty(m_currentSpeaker)
|
||||
? 0f
|
||||
: m_speakerStyle.CalcHeight(new GUIContent(m_currentSpeaker), textWidth);
|
||||
float textHeight = m_textStyle.CalcHeight(new GUIContent(string.IsNullOrEmpty(m_currentText) ? " " : m_currentText), textWidth);
|
||||
|
||||
float boxWidth = maxWidth;
|
||||
float boxHeight = speakerHeight + textHeight + 28f;
|
||||
float boxX = (Screen.width - boxWidth) * 0.5f;
|
||||
float boxY = Screen.height - bottomOffset - boxHeight;
|
||||
|
||||
Rect boxRect = new Rect(boxX, boxY, boxWidth, boxHeight);
|
||||
Color previousColor = GUI.color;
|
||||
GUI.color = new Color(1f, 1f, 1f, m_alpha);
|
||||
GUI.DrawTexture(boxRect, m_background);
|
||||
|
||||
float yOffset = boxRect.y + 10f;
|
||||
if (!string.IsNullOrEmpty(m_currentSpeaker))
|
||||
{
|
||||
Rect speakerRect = new Rect(
|
||||
boxRect.x + horizontalPadding,
|
||||
yOffset,
|
||||
textWidth,
|
||||
speakerHeight);
|
||||
GUI.Label(speakerRect, m_currentSpeaker, m_speakerStyle);
|
||||
yOffset += speakerHeight + 2f;
|
||||
}
|
||||
|
||||
Rect textRect = new Rect(
|
||||
boxRect.x + horizontalPadding,
|
||||
yOffset,
|
||||
textWidth,
|
||||
textHeight);
|
||||
|
||||
GUI.Label(textRect, m_currentText, m_textStyle);
|
||||
GUI.color = previousColor;
|
||||
}
|
||||
|
||||
private void EnsureStyles()
|
||||
{
|
||||
if (m_textStyle != null)
|
||||
return;
|
||||
|
||||
m_background = new Texture2D(1, 1);
|
||||
m_background.SetPixel(0, 0, backgroundColor);
|
||||
m_background.Apply();
|
||||
|
||||
m_textStyle = new GUIStyle(GUI.skin.label)
|
||||
{
|
||||
alignment = TextAnchor.MiddleCenter,
|
||||
fontSize = fontSize,
|
||||
wordWrap = true,
|
||||
richText = false,
|
||||
clipping = TextClipping.Clip,
|
||||
};
|
||||
m_textStyle.normal.textColor = textColor;
|
||||
|
||||
m_speakerStyle = new GUIStyle(GUI.skin.label)
|
||||
{
|
||||
alignment = TextAnchor.MiddleCenter,
|
||||
fontSize = speakerFontSize,
|
||||
fontStyle = FontStyle.Bold,
|
||||
wordWrap = false,
|
||||
clipping = TextClipping.Clip,
|
||||
};
|
||||
m_speakerStyle.normal.textColor = speakerColor;
|
||||
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (m_background != null)
|
||||
Destroy(m_background);
|
||||
}
|
||||
}
|
||||
2
Assets/Code/Scripts/Level/Level01IntroSubtitles.cs.meta
Normal file
2
Assets/Code/Scripts/Level/Level01IntroSubtitles.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a315c9c77ad8a49238033181ece48806
|
||||
Reference in New Issue
Block a user