Thank you for your answer, I'm unsure of what version I have but we sure had it around for a while before actually start implementing it, I ended up getting what I wanted, I created 2 modifications of your typewriter, one works just like yours but instead of just show the character, all characters start fading in (producing a smooth typewriter/fade in effect)
The other uses the 'Pause characters' variable to know when to fade in a block of text, so basically everything between .\ will come in together and then it looks for the next, and so on:
this text comes in \. now this one fades in \. now this comes
(that last one produces the effect I was looking for, and more because I can put \. anywhere)
both have some variables to control the fade in times and speed (again, I'm using 95% of your code only modifying the 'Play()' method in both cases,
here is the code in case you want to include it somehow, I think that the final result looks pretty cool, they still need some work (just finished now and I can't get bother to cleaned it up today) but as they stand now they cover all my needs:
Code: Select all
// Copyright (c) Pixel Crushers. All rights reserved.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
namespace PixelCrushers.DialogueSystem
{
#if TMP_PRESENT
/// <summary>
/// This is a typewriter effect for TextMesh Pro.
///
/// Note: Handles RPGMaker codes, but not two codes next to each other.
/// </summary>
[AddComponentMenu("")] // Use wrapper.
[DisallowMultipleComponent]
public class FadeInParagraphEffect : AbstractTypewriterEffect
{
[System.Serializable]
public class AutoScrollSettings
{
[Tooltip("Automatically scroll to bottom of scroll rect. Useful for long text. Works best with left justification.")]
public bool autoScrollEnabled = false;
public UnityEngine.UI.ScrollRect scrollRect = null;
[Tooltip("Optional. Add a UIScrollBarEnabler to main dialogue panel, assign UI elements, then assign it here to automatically enable scrollbar if content is taller than viewport.")]
public UIScrollbarEnabler scrollbarEnabler = null;
}
/// <summary>
/// Optional auto-scroll settings.
/// </summary>
public AutoScrollSettings autoScrollSettings = new AutoScrollSettings();
public bool fadeInToPauseCharacter;
public UnityEvent onBegin = new UnityEvent();
public UnityEvent onCharacter = new UnityEvent();
public UnityEvent onEnd = new UnityEvent();
/// <summary>
/// Indicates whether the effect is playing.
/// </summary>
/// <value><c>true</c> if this instance is playing; otherwise, <c>false</c>.</value>
public override bool isPlaying { get { return typewriterCoroutine != null; } }
/// @cond FOR_V1_COMPATIBILITY
public bool IsPlaying { get { return isPlaying; } }
/// @endcond
protected const string RPGMakerCodeQuarterPause = @"\,";
protected const string RPGMakerCodeFullPause = @"\.";
protected const string RPGMakerCodeSkipToEnd = @"\^";
protected const string RPGMakerCodeInstantOpen = @"\>";
protected const string RPGMakerCodeInstantClose = @"\<";
public int RolloverCharacterSpread = 1;
private int numberOfCharacters = 1;
private int currentTokenIndex;
protected enum RPGMakerTokenType
{
None,
QuarterPause,
FullPause,
SkipToEnd,
InstantOpen,
InstantClose
}
protected Dictionary<int, List<RPGMakerTokenType>> rpgMakerTokens = new Dictionary<int, List<RPGMakerTokenType>>();
protected TMPro.TMP_Text m_textComponent = null;
protected TMPro.TMP_Text textComponent
{
get
{
if (m_textComponent == null) m_textComponent = GetComponent<TMPro.TMP_Text>();
return m_textComponent;
}
}
protected LayoutElement m_layoutElement = null;
protected LayoutElement layoutElement
{
get
{
if (m_layoutElement == null)
{
m_layoutElement = GetComponent<LayoutElement>();
if (m_layoutElement == null) m_layoutElement = gameObject.AddComponent<LayoutElement>();
}
return m_layoutElement;
}
}
protected AudioSource runtimeAudioSource
{
get
{
if (audioSource == null) audioSource = GetComponent<AudioSource>();
if (audioSource == null && (audioClip != null))
{
audioSource = gameObject.AddComponent<AudioSource>();
audioSource.playOnAwake = false;
audioSource.panStereo = 0;
}
return audioSource;
}
}
protected bool started = false;
protected int charactersTyped = 0;
protected Coroutine typewriterCoroutine = null;
protected MonoBehaviour coroutineController = null;
public override void Awake()
{
if (removeDuplicateTypewriterEffects) RemoveIfDuplicate();
}
protected void RemoveIfDuplicate()
{
var effects = GetComponents<TextMeshProTypewriterEffect>();
if (effects.Length > 1)
{
var keep = effects[0];
for (int i = 1; i < effects.Length; i++)
{
if (effects[i].GetInstanceID() < keep.GetInstanceID())
{
keep = effects[i];
}
}
for (int i = 0; i < effects.Length; i++)
{
if (effects[i] != keep)
{
Destroy(effects[i]);
}
}
}
}
public override void Start()
{
if (!IsPlaying && playOnEnable)
{
StopTypewriterCoroutine();
StartTypewriterCoroutine(0);
}
started = true;
}
public override void OnEnable()
{
base.OnEnable();
if (!IsPlaying && playOnEnable && started)
{
StopTypewriterCoroutine();
StartTypewriterCoroutine(0);
}
}
public override void OnDisable()
{
base.OnEnable();
Stop();
}
/// <summary>
/// Pauses the effect.
/// </summary>
public void Pause()
{
paused = true;
}
/// <summary>
/// Unpauses the effect. The text will resume at the point where it
/// was paused; it won't try to catch up to make up for the pause.
/// </summary>
public void Unpause()
{
paused = false;
}
public void Rewind()
{
charactersTyped = 0;
}
/// <summary>
/// Starts typing, optionally from a starting index. Characters before the
/// starting index will appear immediately.
/// </summary>
/// <param name="text">Text to type.</param>
/// <param name="fromIndex">Character index to start typing from.</param>
public override void StartTyping(string text, int fromIndex = 0)
{
StopTypewriterCoroutine();
textComponent.text = text;
StartTypewriterCoroutine(fromIndex);
}
public override void StopTyping()
{
Stop();
}
/// <summary>
/// Play typewriter on text immediately.
/// </summary>
/// <param name="text"></param>
public virtual void PlayText(string text, int fromIndex = 0)
{
StopTypewriterCoroutine();
textComponent.text = text;
StartTypewriterCoroutine(fromIndex);
}
protected void StartTypewriterCoroutine(int fromIndex)
{
if (coroutineController == null || !coroutineController.gameObject.activeInHierarchy)
{
// This MonoBehaviour might not be enabled yet, so use one that's guaranteed to be enabled:
MonoBehaviour controller = GetComponentInParent<AbstractDialogueUI>();
if (controller == null) controller = DialogueManager.instance;
coroutineController = controller;
if (coroutineController == null) coroutineController = this;
}
typewriterCoroutine = coroutineController.StartCoroutine(Play());
}
/// <summary>
/// Plays the typewriter effect.
/// </summary>
public virtual IEnumerator Play()
{
if ((textComponent != null) && (charactersPerSecond > 0))
{
ProcessRPGMakerCodes();
if (fadeInToPauseCharacter)
{
numberOfCharacters = rpgMakerTokens.First().Key;
rpgMakerTokens.Remove(rpgMakerTokens.First().Key);
}
// Set the whole text transparent
textComponent.color = new Color
(
textComponent.color.r,
textComponent.color.g,
textComponent.color.b,
0
);
// Need to force the text object to be generated so we have valid data to work with right from the start.
textComponent.ForceMeshUpdate();
TMP_TextInfo textInfo = textComponent.textInfo;
Color32[] newVertexColors;
int currentCharacter = numberOfCharacters;
int startingCharacterRange = 0;
bool isRangeMax = false;
bool fullAlpha = false;
while (!isRangeMax)
{
int characterCount = textInfo.characterCount;
// Spread should not exceed the number of characters.
byte fadeSteps = (byte)Mathf.Max(1, 255 / RolloverCharacterSpread);
for (int i = startingCharacterRange; i < currentCharacter + 1; i++)
{
charactersTyped = i;
// Skip characters that are not visible (like white spaces)
if (!textInfo.characterInfo[i].isVisible) continue;
// Get the index of the material used by the current character.
int materialIndex = textInfo.characterInfo[i].materialReferenceIndex;
// Get the vertex colors of the mesh used by this text element (character or sprite).
newVertexColors = textInfo.meshInfo[materialIndex].colors32;
// Get the index of the first vertex used by this text element.
int vertexIndex = textInfo.characterInfo[i].vertexIndex;
// Get the current character's alpha value.
byte alpha = (byte)Mathf.Clamp(newVertexColors[vertexIndex + 0].a + fadeSteps, 0, 255);
// Set new alpha values.
newVertexColors[vertexIndex + 0].a = alpha;
newVertexColors[vertexIndex + 1].a = alpha;
newVertexColors[vertexIndex + 2].a = alpha;
newVertexColors[vertexIndex + 3].a = alpha;
fullAlpha = alpha == 255;
}
// Upload the changed vertex colors to the Mesh.
textComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32);
//the previous text is totally visible
if (fullAlpha)
{
fullAlpha = false;
if (currentCharacter + numberOfCharacters < characterCount) currentCharacter += numberOfCharacters;
if (fadeInToPauseCharacter && rpgMakerTokens.Any())
{
//we use the next stop point to know what to show next
var nextToken = rpgMakerTokens.First().Key;
if (nextToken < characterCount)
{
numberOfCharacters = rpgMakerTokens.First().Key;
rpgMakerTokens.Remove(rpgMakerTokens.First().Key);
yield return DialogueTime.WaitForSeconds(fullPauseDuration);
}
}
else
{
//we are seeing full text, time to stop
if (characterCount - 1 == currentCharacter) isRangeMax = true;
//no stop points, we show all what is left
currentCharacter = characterCount - 1;
}
}
yield return new WaitForSeconds(0.25f - charactersPerSecond * 0.01f);
}
}
Stop();
}
protected void ProcessRPGMakerCodes()
{
rpgMakerTokens.Clear();
var source = textComponent.text;
var result = string.Empty;
if (!source.Contains("\\")) return;
source = Tools.StripTextMeshProTags(source);
int safeguard = 0;
while (!string.IsNullOrEmpty(source) && safeguard < 9999)
{
safeguard++;
RPGMakerTokenType token;
if (PeelRPGMakerTokenFromFront(ref source, out token))
{
int i = result.Length;
if (!rpgMakerTokens.ContainsKey(i))
{
rpgMakerTokens.Add(i, new List<RPGMakerTokenType>());
}
rpgMakerTokens[i].Add(token);
}
else
{
result += source[0];
source = source.Remove(0, 1);
}
}
textComponent.text = Regex.Replace(textComponent.text, @"\\[\.\,\^\<\>]", string.Empty);
}
protected bool PeelRPGMakerTokenFromFront(ref string source, out RPGMakerTokenType token)
{
token = RPGMakerTokenType.None;
if (string.IsNullOrEmpty(source) || source.Length < 2 || source[0] != '\\') return false;
var s = source.Substring(0, 2);
if (string.Equals(s, RPGMakerCodeQuarterPause))
{
token = RPGMakerTokenType.QuarterPause;
}
else if (string.Equals(s, RPGMakerCodeFullPause))
{
token = RPGMakerTokenType.FullPause;
}
else if (string.Equals(s, RPGMakerCodeSkipToEnd))
{
token = RPGMakerTokenType.SkipToEnd;
}
else if (string.Equals(s, RPGMakerCodeInstantOpen))
{
token = RPGMakerTokenType.InstantOpen;
}
else if (string.Equals(s, RPGMakerCodeInstantClose))
{
token = RPGMakerTokenType.InstantClose;
}
else
{
return false;
}
source = source.Remove(0, 2);
return true;
}
protected void StopTypewriterCoroutine()
{
if (typewriterCoroutine == null) return;
if (coroutineController == null)
{
StopCoroutine(typewriterCoroutine);
}
else
{
coroutineController.StopCoroutine(typewriterCoroutine);
}
typewriterCoroutine = null;
coroutineController = null;
}
/// <summary>
/// Stops the effect.
/// </summary>
public override void Stop()
{
if (isPlaying)
{
onEnd.Invoke();
Sequencer.Message(SequencerMessages.Typed);
}
StopTypewriterCoroutine();
if (textComponent != null) textComponent.maxVisibleCharacters = textComponent.textInfo.characterCount;
HandleAutoScroll();
}
protected void HandleAutoScroll()
{
if (!autoScrollSettings.autoScrollEnabled) return;
var layoutElement = textComponent.GetComponent<LayoutElement>();
if (layoutElement == null) layoutElement = textComponent.gameObject.AddComponent<LayoutElement>();
layoutElement.preferredHeight = textComponent.textBounds.size.y;
if (autoScrollSettings.scrollRect != null)
{
autoScrollSettings.scrollRect.normalizedPosition = new Vector2(0, 0);
}
if (autoScrollSettings.scrollbarEnabler != null)
{
autoScrollSettings.scrollbarEnabler.CheckScrollbar();
}
}
}
#else
[AddComponentMenu("")] // Use wrapper.
public class TextMeshProTypewriterEffect : AbstractTypewriterEffect
{
public override bool isPlaying { get { return false; } }
public override void Awake() { }
public override void Start() { }
public override void StartTyping(string text, int fromIndex = 0) { }
public override void Stop() { }
public override void StopTyping() { }
}
#endif
}
Code: Select all
// Copyright (c) Pixel Crushers. All rights reserved.
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
namespace PixelCrushers.DialogueSystem
{
#if TMP_PRESENT
/// <summary>
/// This is a typewriter effect for TextMesh Pro.
///
/// Note: Handles RPGMaker codes, but not two codes next to each other.
/// </summary>
[AddComponentMenu("")] // Use wrapper.
[DisallowMultipleComponent]
public class FadeInTypewritterEffect : AbstractTypewriterEffect
{
[System.Serializable]
public class AutoScrollSettings
{
[Tooltip("Automatically scroll to bottom of scroll rect. Useful for long text. Works best with left justification.")]
public bool autoScrollEnabled = false;
public UnityEngine.UI.ScrollRect scrollRect = null;
[Tooltip("Optional. Add a UIScrollBarEnabler to main dialogue panel, assign UI elements, then assign it here to automatically enable scrollbar if content is taller than viewport.")]
public UIScrollbarEnabler scrollbarEnabler = null;
}
/// <summary>
/// Optional auto-scroll settings.
/// </summary>
public AutoScrollSettings autoScrollSettings = new AutoScrollSettings();
public UnityEvent onBegin = new UnityEvent();
public UnityEvent onCharacter = new UnityEvent();
public UnityEvent onEnd = new UnityEvent();
/// <summary>
/// Indicates whether the effect is playing.
/// </summary>
/// <value><c>true</c> if this instance is playing; otherwise, <c>false</c>.</value>
public override bool isPlaying { get { return typewriterCoroutine != null; } }
/// @cond FOR_V1_COMPATIBILITY
public bool IsPlaying { get { return isPlaying; } }
/// @endcond
protected const string RPGMakerCodeQuarterPause = @"\,";
protected const string RPGMakerCodeFullPause = @"\.";
protected const string RPGMakerCodeSkipToEnd = @"\^";
protected const string RPGMakerCodeInstantOpen = @"\>";
protected const string RPGMakerCodeInstantClose = @"\<";
public int RolloverCharacterSpread = 10;
protected enum RPGMakerTokenType
{
None,
QuarterPause,
FullPause,
SkipToEnd,
InstantOpen,
InstantClose
}
protected Dictionary<int, List<RPGMakerTokenType>> rpgMakerTokens = new Dictionary<int, List<RPGMakerTokenType>>();
protected TMPro.TMP_Text m_textComponent = null;
protected TMPro.TMP_Text textComponent
{
get
{
if (m_textComponent == null) m_textComponent = GetComponent<TMPro.TMP_Text>();
return m_textComponent;
}
}
protected LayoutElement m_layoutElement = null;
protected LayoutElement layoutElement
{
get
{
if (m_layoutElement == null)
{
m_layoutElement = GetComponent<LayoutElement>();
if (m_layoutElement == null) m_layoutElement = gameObject.AddComponent<LayoutElement>();
}
return m_layoutElement;
}
}
protected AudioSource runtimeAudioSource
{
get
{
if (audioSource == null) audioSource = GetComponent<AudioSource>();
if (audioSource == null && (audioClip != null))
{
audioSource = gameObject.AddComponent<AudioSource>();
audioSource.playOnAwake = false;
audioSource.panStereo = 0;
}
return audioSource;
}
}
protected bool started = false;
protected int charactersTyped = 0;
protected Coroutine typewriterCoroutine = null;
protected MonoBehaviour coroutineController = null;
public override void Awake()
{
if (removeDuplicateTypewriterEffects) RemoveIfDuplicate();
}
protected void RemoveIfDuplicate()
{
var effects = GetComponents<TextMeshProTypewriterEffect>();
if (effects.Length > 1)
{
var keep = effects[0];
for (int i = 1; i < effects.Length; i++)
{
if (effects[i].GetInstanceID() < keep.GetInstanceID())
{
keep = effects[i];
}
}
for (int i = 0; i < effects.Length; i++)
{
if (effects[i] != keep)
{
Destroy(effects[i]);
}
}
}
}
public override void Start()
{
if (!IsPlaying && playOnEnable)
{
StopTypewriterCoroutine();
StartTypewriterCoroutine(0);
}
started = true;
}
public override void OnEnable()
{
base.OnEnable();
if (!IsPlaying && playOnEnable && started)
{
StopTypewriterCoroutine();
StartTypewriterCoroutine(0);
}
}
public override void OnDisable()
{
base.OnEnable();
Stop();
}
/// <summary>
/// Pauses the effect.
/// </summary>
public void Pause()
{
paused = true;
}
/// <summary>
/// Unpauses the effect. The text will resume at the point where it
/// was paused; it won't try to catch up to make up for the pause.
/// </summary>
public void Unpause()
{
paused = false;
}
public void Rewind()
{
charactersTyped = 0;
}
/// <summary>
/// Starts typing, optionally from a starting index. Characters before the
/// starting index will appear immediately.
/// </summary>
/// <param name="text">Text to type.</param>
/// <param name="fromIndex">Character index to start typing from.</param>
public override void StartTyping(string text, int fromIndex = 0)
{
StopTypewriterCoroutine();
textComponent.text = text;
StartTypewriterCoroutine(fromIndex);
}
public override void StopTyping()
{
Stop();
}
/// <summary>
/// Play typewriter on text immediately.
/// </summary>
/// <param name="text"></param>
public virtual void PlayText(string text, int fromIndex = 0)
{
StopTypewriterCoroutine();
textComponent.text = text;
StartTypewriterCoroutine(fromIndex);
}
protected void StartTypewriterCoroutine(int fromIndex)
{
if (coroutineController == null || !coroutineController.gameObject.activeInHierarchy)
{
// This MonoBehaviour might not be enabled yet, so use one that's guaranteed to be enabled:
MonoBehaviour controller = GetComponentInParent<AbstractDialogueUI>();
if (controller == null) controller = DialogueManager.instance;
coroutineController = controller;
if (coroutineController == null) coroutineController = this;
}
typewriterCoroutine = coroutineController.StartCoroutine(Play());
}
/// <summary>
/// Plays the typewriter effect.
/// </summary>
public virtual IEnumerator Play()
{
if ((textComponent != null) && (charactersPerSecond > 0))
{
// Set the whole text transparent
textComponent.color = new Color
(
textComponent.color.r,
textComponent.color.g,
textComponent.color.b,
0
);
// Need to force the text object to be generated so we have valid data to work with right from the start.
textComponent.ForceMeshUpdate();
TMP_TextInfo textInfo = textComponent.textInfo;
Color32[] newVertexColors;
int currentCharacter = 0;
int startingCharacterRange = currentCharacter;
bool isRangeMax = false;
ProcessRPGMakerCodes();
while (!isRangeMax)
{
int characterCount = textInfo.characterCount;
// Spread should not exceed the number of characters.
byte fadeSteps = (byte)Mathf.Max(1, 255 / RolloverCharacterSpread);
for (int i = startingCharacterRange; i < currentCharacter + 1; i++)
{
charactersTyped = i;
// Skip characters that are not visible (like white spaces)
if (!textInfo.characterInfo[i].isVisible) continue;
// Get the index of the material used by the current character.
int materialIndex = textInfo.characterInfo[i].materialReferenceIndex;
// Get the vertex colors of the mesh used by this text element (character or sprite).
newVertexColors = textInfo.meshInfo[materialIndex].colors32;
// Get the index of the first vertex used by this text element.
int vertexIndex = textInfo.characterInfo[i].vertexIndex;
// Get the current character's alpha value.
byte alpha = (byte)Mathf.Clamp(newVertexColors[vertexIndex + 0].a + fadeSteps, 0, 255);
// Set new alpha values.
newVertexColors[vertexIndex + 0].a = alpha;
newVertexColors[vertexIndex + 1].a = alpha;
newVertexColors[vertexIndex + 2].a = alpha;
newVertexColors[vertexIndex + 3].a = alpha;
if (alpha == 255)
{
startingCharacterRange += 1;
if (startingCharacterRange == characterCount)
{
// Update mesh vertex data one last time.
textComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32);
yield return new WaitForSeconds(1.0f);
// Reset the text object back to original state.
textComponent.ForceMeshUpdate();
yield return new WaitForSeconds(1.0f);
// Reset our counters.
currentCharacter = 0;
startingCharacterRange = 0;
isRangeMax = true; // end the coroutine.
}
}
}
// Upload the changed vertex colors to the Mesh.
textComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32);
if (currentCharacter + 1 < characterCount) currentCharacter += 1;
if (rpgMakerTokens.ContainsKey(charactersTyped))
{
var tokens = rpgMakerTokens[charactersTyped];
for (int i = 0; i < tokens.Count; i++)
{
var token = tokens[i];
switch (token)
{
case RPGMakerTokenType.QuarterPause:
yield return DialogueTime.WaitForSeconds(quarterPauseDuration);
break;
case RPGMakerTokenType.FullPause:
yield return DialogueTime.WaitForSeconds(fullPauseDuration);
break;
case RPGMakerTokenType.SkipToEnd:
charactersTyped = characterCount - 1;
break;
case RPGMakerTokenType.InstantOpen:
var close = false;
while (!close && charactersTyped < characterCount)
{
charactersTyped++;
if (rpgMakerTokens.ContainsKey(charactersTyped) && rpgMakerTokens[charactersTyped].Contains(RPGMakerTokenType.InstantClose))
{
close = true;
}
}
break;
}
}
}
yield return new WaitForSeconds(0.25f - charactersPerSecond * 0.01f);
}
}
Stop();
}
protected void ProcessRPGMakerCodes()
{
rpgMakerTokens.Clear();
var source = textComponent.text;
var result = string.Empty;
if (!source.Contains("\\")) return;
source = Tools.StripTextMeshProTags(source);
int safeguard = 0;
while (!string.IsNullOrEmpty(source) && safeguard < 9999)
{
safeguard++;
RPGMakerTokenType token;
if (PeelRPGMakerTokenFromFront(ref source, out token))
{
int i = result.Length;
if (!rpgMakerTokens.ContainsKey(i))
{
rpgMakerTokens.Add(i, new List<RPGMakerTokenType>());
}
rpgMakerTokens[i].Add(token);
}
else
{
result += source[0];
source = source.Remove(0, 1);
}
}
textComponent.text = Regex.Replace(textComponent.text, @"\\[\.\,\^\<\>]", string.Empty);
}
protected bool PeelRPGMakerTokenFromFront(ref string source, out RPGMakerTokenType token)
{
token = RPGMakerTokenType.None;
if (string.IsNullOrEmpty(source) || source.Length < 2 || source[0] != '\\') return false;
var s = source.Substring(0, 2);
if (string.Equals(s, RPGMakerCodeQuarterPause))
{
token = RPGMakerTokenType.QuarterPause;
}
else if (string.Equals(s, RPGMakerCodeFullPause))
{
token = RPGMakerTokenType.FullPause;
}
else if (string.Equals(s, RPGMakerCodeSkipToEnd))
{
token = RPGMakerTokenType.SkipToEnd;
}
else if (string.Equals(s, RPGMakerCodeInstantOpen))
{
token = RPGMakerTokenType.InstantOpen;
}
else if (string.Equals(s, RPGMakerCodeInstantClose))
{
token = RPGMakerTokenType.InstantClose;
}
else
{
return false;
}
source = source.Remove(0, 2);
return true;
}
protected void StopTypewriterCoroutine()
{
if (typewriterCoroutine == null) return;
if (coroutineController == null)
{
StopCoroutine(typewriterCoroutine);
}
else
{
coroutineController.StopCoroutine(typewriterCoroutine);
}
typewriterCoroutine = null;
coroutineController = null;
}
/// <summary>
/// Stops the effect.
/// </summary>
public override void Stop()
{
if (isPlaying)
{
onEnd.Invoke();
Sequencer.Message(SequencerMessages.Typed);
}
StopTypewriterCoroutine();
if (textComponent != null) textComponent.maxVisibleCharacters = textComponent.textInfo.characterCount;
HandleAutoScroll();
}
protected void HandleAutoScroll()
{
if (!autoScrollSettings.autoScrollEnabled) return;
var layoutElement = textComponent.GetComponent<LayoutElement>();
if (layoutElement == null) layoutElement = textComponent.gameObject.AddComponent<LayoutElement>();
layoutElement.preferredHeight = textComponent.textBounds.size.y;
if (autoScrollSettings.scrollRect != null)
{
autoScrollSettings.scrollRect.normalizedPosition = new Vector2(0, 0);
}
if (autoScrollSettings.scrollbarEnabler != null)
{
autoScrollSettings.scrollbarEnabler.CheckScrollbar();
}
}
}
#else
[AddComponentMenu("")] // Use wrapper.
public class TextMeshProTypewriterEffect : AbstractTypewriterEffect
{
public override bool isPlaying { get { return false; } }
public override void Awake() { }
public override void Start() { }
public override void StartTyping(string text, int fromIndex = 0) { }
public override void Stop() { }
public override void StopTyping() { }
}
#endif
}