Skip to content

Commit

Permalink
Add support for printing sprite tags (fixes Issue #35)
Browse files Browse the repository at this point in the history
  • Loading branch information
edwardrowe committed Jul 13, 2020
1 parent 8f04c26 commit f47178a
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 30 deletions.
1 change: 1 addition & 0 deletions Assets/RedBlueGames/TextTyper/Examples/TextTyperTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public void Start()
dialogueLines.Enqueue("Hello! My name is... <delay=0.5>NPC</delay>. Got it, <i>bub</i>?");
dialogueLines.Enqueue("You can <b>use</b> <i>uGUI</i> <size=40>text</size> <size=20>tag</size> and <color=#ff0000ff>color</color> tag <color=#00ff00ff>like this</color>.");
dialogueLines.Enqueue("bold <b>text</b> test <b>bold</b> text <b>test</b>");
dialogueLines.Enqueue("Sprites!<sprite index=0><sprite index=1><sprite index=2><sprite index=3>Isn't that neat?");
dialogueLines.Enqueue("You can <size=40>size 40</size> and <size=20>size 20</size>");
dialogueLines.Enqueue("You can <color=#ff0000ff>color</color> tag <color=#00ff00ff>like this</color>.");
dialogueLines.Enqueue("Sample Shake Animations: <anim=lightrot>Light Rotation</anim>, <anim=lightpos>Light Position</anim>, <anim=fullshake>Full Shake</anim>\nSample Curve Animations: <animation=slowsine>Slow Sine</animation>, <animation=bounce>Bounce Bounce</animation>, <animation=crazyflip>Crazy Flip</animation>");
Expand Down
12 changes: 5 additions & 7 deletions Assets/RedBlueGames/TextTyper/RichTextTag.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class RichTextTag
private const char OpeningNodeDelimeter = '<';
private const char CloseNodeDelimeter = '>';
private const char EndTagDelimeter = '/';
private const string ParameterDelimeter = "=";
private const char ParameterDelimeter = '=';

/// <summary>
/// Initializes a new instance of the <see cref="RichTextTag"/> class.
Expand Down Expand Up @@ -54,12 +54,10 @@ public string TagType
var tagType = this.TagText.Substring(1, this.TagText.Length - 2);
tagType = tagType.TrimStart(EndTagDelimeter);

// Strip Parameter
var parameterDelimeterIndex = tagType.IndexOf(ParameterDelimeter);
if (parameterDelimeterIndex > 0)
{
tagType = tagType.Substring(0, parameterDelimeterIndex);
}
var tagEndDelimeters = new char[] { ' ', ParameterDelimeter };
var delimeterIndex = tagType.IndexOfAny(tagEndDelimeters);
var tagEndIndex = delimeterIndex > 0 ? delimeterIndex : tagType.Length;
tagType = tagType.Substring(0, tagEndIndex);

return tagType;
}
Expand Down
12 changes: 12 additions & 0 deletions Assets/RedBlueGames/TextTyper/Tests/Editor/TextTagParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,17 @@ public void RemoveUnityTags_AllUnityTags_ReturnsNoTags()

Assert.AreEqual(expectedText, generatedText);
}

[Test]
public void RemoveUnityTags_SpriteTagWithValue_ReturnsTaglessText()
{
var builder = new System.Text.StringBuilder();
var textToType = "This string has a <sprite index=0> sprite.";
var generatedText = TextTagParser.RemoveUnityTags(textToType);

var expectedText = "This string has a sprite.";

Assert.AreEqual(expectedText, generatedText);
}
}
}
14 changes: 14 additions & 0 deletions Assets/RedBlueGames/TextTyper/TextTagParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,20 @@ public bool IsTag
}
}

/// <summary>
/// Gets a value indicating this Symbol represents a Sprite, which is treated
/// as a visible character by TextMeshPro.
/// See Issue #35 for details.
/// </summary>
/// <value></value>
public bool IsReplacedWithSprite
{
get
{
return this.IsTag && this.Tag.TagType == "sprite";
}
}

public float GetFloatParameter(float defaultValue = 0f)
{
if (!this.IsTag)
Expand Down
69 changes: 46 additions & 23 deletions Assets/RedBlueGames/TextTyper/TextTyper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public sealed class TextTyper : MonoBehaviour

private TextMeshProUGUI textComponent;
private float defaultPrintDelay;
private List<float> characterPrintDelays;
private List<TypableCharacter> charactersToType;
private List<TextAnimation> animations;
private Coroutine typeTextCoroutine;

Expand Down Expand Up @@ -127,7 +127,7 @@ public void TypeText(string text, float printDelay = -1)
}

this.defaultPrintDelay = printDelay > 0 ? printDelay : PrintDelaySetting;
this.ProcessCustomTags(text);
this.ProcessTags(text);

this.typeTextCoroutine = this.StartCoroutine(this.TypeTextCharByChar(text));
}
Expand Down Expand Up @@ -166,31 +166,24 @@ private void CleanupCoroutine()

private IEnumerator TypeTextCharByChar(string text)
{
string taglessText = TextTagParser.RemoveAllTags(text);
int totalPrintedChars = taglessText.Length;

int currPrintedChars = 1;
this.TextComponent.text = TextTagParser.RemoveCustomTags(text);
do
for (int numPrintedCharacters = 0; numPrintedCharacters < this.charactersToType.Count; ++numPrintedCharacters)
{
this.TextComponent.maxVisibleCharacters = currPrintedChars;
this.TextComponent.maxVisibleCharacters = numPrintedCharacters + 1;
this.UpdateMeshAndAnims();

this.OnCharacterPrinted(taglessText[currPrintedChars - 1].ToString());
var printedChar = this.charactersToType[numPrintedCharacters];
this.OnCharacterPrinted(printedChar.ToString());

var delay = this.characterPrintDelays[currPrintedChars - 1];
if (this.useUnscaledTime)
{
yield return new WaitForSecondsRealtime(delay);
yield return new WaitForSecondsRealtime(printedChar.Delay);
}
else
{
yield return new WaitForSeconds(delay);
yield return new WaitForSeconds(printedChar.Delay);
}

++currPrintedChars;
}
while (currPrintedChars <= totalPrintedChars);

this.typeTextCoroutine = null;
this.OnTypewritingComplete();
Expand Down Expand Up @@ -219,11 +212,10 @@ private void UpdateMeshAndAnims()
/// the appropriate TextAnimation components
/// </summary>
/// <param name="text">Full text string with tags</param>
private void ProcessCustomTags(string text)
private void ProcessTags(string text)
{
this.characterPrintDelays = new List<float>(text.Length);
this.charactersToType = new List<TypableCharacter>();
this.animations = new List<TextAnimation>();

var textAsSymbolList = TextTagParser.CreateSymbolListFromText(text);

int printedCharCount = 0;
Expand All @@ -232,7 +224,8 @@ private void ProcessCustomTags(string text)
float nextDelay = this.defaultPrintDelay;
foreach (var symbol in textAsSymbolList)
{
if (symbol.IsTag)
// Sprite prints a character so we need to throw it out and treat it like a character
if (symbol.IsTag && !symbol.IsReplacedWithSprite)
{
// TODO - Verification that custom tags are not nested, b/c that will not be handled gracefully
if (symbol.Tag.TagType == TextTagParser.CustomTags.Delay)
Expand Down Expand Up @@ -281,22 +274,31 @@ private void ProcessCustomTags(string text)
}
else
{
// Unrecognized CustomTag Type. Should we error here?
// Tag type is likely a Unity tag, but it might be something we don't know... could error if unrecognized.
}

}
else
{
printedCharCount++;

if (punctutationCharacters.Contains(symbol.Character))
TypableCharacter characterToType = new TypableCharacter ();
if (symbol.IsTag && symbol.IsReplacedWithSprite)
{
this.characterPrintDelays.Add(nextDelay * PunctuationDelayMultiplier);
characterToType.IsSprite = true;
}
else
{
this.characterPrintDelays.Add(nextDelay);
characterToType.Char = symbol.Character;
}

characterToType.Delay = nextDelay;
if (punctutationCharacters.Contains(symbol.Character))
{
characterToType.Delay *= PunctuationDelayMultiplier;
}

this.charactersToType.Add(characterToType);
}
}
}
Expand Down Expand Up @@ -334,5 +336,26 @@ private void OnTypewritingComplete()
public class CharacterPrintedEvent : UnityEvent<string>
{
}

/// <summary>
/// This class represents a printed character moment, which should correspond with a
/// delay in the text typer. It became necessary to make this a class when I had
/// to account for Sprite tags which are replaced by a sprite that counts as a "visble"
/// character. These sprites would not be in the Text string stripped of tags,
/// so this allows us to track and print them with a delay.
/// </summary>
private class TypableCharacter
{
public char Char { get; set; }

public float Delay { get; set; }

public bool IsSprite { get; set; }

public override string ToString()
{
return this.IsSprite ? "Sprite" : Char.ToString();
}
}
}
}

0 comments on commit f47178a

Please sign in to comment.