198 lines
5.5 KiB
C#
198 lines
5.5 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using TMPro;
|
|
using UnityEngine.UI;
|
|
|
|
namespace Unheimlich.UI
|
|
{
|
|
[RequireComponent(typeof(TextMeshProUGUI))]
|
|
public class PerLetterFontShifter : MonoBehaviour
|
|
{
|
|
#region Serialized Fields
|
|
|
|
[Header("Fonts")]
|
|
[SerializeField] private TMP_FontAsset[] _fonts;
|
|
|
|
[Header("Timing")]
|
|
[SerializeField] private float _shiftInterval = 3f;
|
|
[SerializeField] private float _minLetterDelay = 0.05f;
|
|
[SerializeField] private float _maxLetterDelay = 0.25f;
|
|
|
|
[Header("Style")]
|
|
[SerializeField] private float _fontSize = 36f;
|
|
[SerializeField] private Color _textColor = Color.white;
|
|
|
|
#endregion
|
|
|
|
#region Private Fields
|
|
|
|
private TextMeshProUGUI _originalTmp;
|
|
private string _originalText;
|
|
private readonly List<TextMeshProUGUI> _letterObjects = new List<TextMeshProUGUI>();
|
|
private Coroutine _shiftLoopRoutineHandle;
|
|
|
|
#endregion
|
|
|
|
#region Unity Lifecycle Methods
|
|
|
|
private void Awake()
|
|
{
|
|
_originalTmp = GetComponent<TextMeshProUGUI>();
|
|
_originalText = _originalTmp.text;
|
|
_originalTmp.enabled = false;
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
BuildLetterObjects();
|
|
_shiftLoopRoutineHandle = StartCoroutine(ShiftLoopRoutine());
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
if (_shiftLoopRoutineHandle != null)
|
|
StopCoroutine(_shiftLoopRoutineHandle);
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
DestroyLetterObjects();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public Methods
|
|
|
|
public void SetText(string newText)
|
|
{
|
|
_originalText = newText;
|
|
BuildLetterObjects();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private Methods
|
|
|
|
private void BuildLetterObjects()
|
|
{
|
|
DestroyLetterObjects();
|
|
|
|
foreach (char character in _originalText)
|
|
{
|
|
GameObject letterGo = new GameObject($"Letter_{character}");
|
|
letterGo.transform.SetParent(transform, false);
|
|
|
|
TextMeshProUGUI letterTmp = letterGo.AddComponent<TextMeshProUGUI>();
|
|
letterTmp.text = character.ToString();
|
|
letterTmp.fontSize = _fontSize;
|
|
letterTmp.color = _textColor;
|
|
letterTmp.alignment = TextAlignmentOptions.Center;
|
|
|
|
_letterObjects.Add(letterTmp);
|
|
}
|
|
|
|
ArrangeLetters();
|
|
ShuffleFonts();
|
|
}
|
|
|
|
private void DestroyLetterObjects()
|
|
{
|
|
foreach (TextMeshProUGUI letter in _letterObjects)
|
|
{
|
|
if (letter != null)
|
|
Destroy(letter.gameObject);
|
|
}
|
|
|
|
_letterObjects.Clear();
|
|
}
|
|
|
|
private void ArrangeLetters()
|
|
{
|
|
HorizontalLayoutGroup layout = gameObject.GetComponent<HorizontalLayoutGroup>();
|
|
if (layout == null)
|
|
layout = gameObject.AddComponent<HorizontalLayoutGroup>();
|
|
|
|
layout.childAlignment = TextAnchor.MiddleCenter;
|
|
layout.childForceExpandWidth = false;
|
|
layout.childForceExpandHeight = false;
|
|
layout.childControlWidth = true;
|
|
layout.childControlHeight = true;
|
|
layout.spacing = 0f;
|
|
|
|
foreach (TextMeshProUGUI letter in _letterObjects)
|
|
{
|
|
ContentSizeFitter fitter = letter.gameObject.GetComponent<ContentSizeFitter>();
|
|
if (fitter == null)
|
|
fitter = letter.gameObject.AddComponent<ContentSizeFitter>();
|
|
|
|
fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
|
|
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
|
}
|
|
}
|
|
|
|
private void ShuffleFonts()
|
|
{
|
|
if (_fonts == null || _fonts.Length == 0)
|
|
{
|
|
Debug.LogWarning($"[{nameof(PerLetterFontShifter)}] No fonts assigned.", this);
|
|
return;
|
|
}
|
|
|
|
StartCoroutine(ShuffleStaggeredRoutine());
|
|
}
|
|
|
|
private List<int> GetShuffledIndices()
|
|
{
|
|
List<int> indices = new List<int>();
|
|
|
|
for (int i = 0; i < _letterObjects.Count; i++)
|
|
indices.Add(i);
|
|
|
|
for (int i = indices.Count - 1; i > 0; i--)
|
|
{
|
|
int j = Random.Range(0, i + 1);
|
|
(indices[i], indices[j]) = (indices[j], indices[i]);
|
|
}
|
|
|
|
return indices;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Coroutines
|
|
|
|
private IEnumerator ShiftLoopRoutine()
|
|
{
|
|
while (true)
|
|
{
|
|
yield return new WaitForSeconds(_shiftInterval);
|
|
ShuffleFonts();
|
|
}
|
|
}
|
|
|
|
private IEnumerator ShuffleStaggeredRoutine()
|
|
{
|
|
List<int> shuffledIndices = GetShuffledIndices();
|
|
|
|
foreach (int index in shuffledIndices)
|
|
{
|
|
TextMeshProUGUI letter = _letterObjects[index];
|
|
|
|
if (letter.text == " " || letter.text == "\n")
|
|
continue;
|
|
|
|
letter.font = _fonts[Random.Range(0, _fonts.Length)];
|
|
|
|
yield return new WaitForSeconds(Random.Range(_minLetterDelay, _maxLetterDelay));
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#if UNITY_EDITOR
|
|
[ContextMenu("Test Shuffle Now")]
|
|
private void TestShuffle() => ShuffleFonts();
|
|
#endif
|
|
}
|
|
} |