Git Product home page Git Product logo

unity-text-typer's Introduction

Unity-TextTyper

TextTyper is a text typing effect component for Unity. TextTyper prints out characters one by one to a uGUI Text component. Adapted by RedBlueGames from synchrok's GitHub project (https://github.com/synchrok/TypeText).

It's easy to find other examples of Text printing components, but TextTyper provides two major differences:

  • Correct wrapping as characters are printed
  • Support for Rich Text Tags

Note this verison of TextTyper requires TextMeshPro, which can be installed for free from the Package Manager in Unity 2018, or the Asset Store in older versions. If you want the version that is compatible with Unity's uGUI Text component, this branch or download this release.

How To Use

To start TextTyping all you need to do is add the TextTyper component to a unity Text widget:

  1. Create a GameObject with a Unity UI Text Widget, as normal.
  2. Add a TextTyper component to the GameObject.
  3. Call the TextTyper component's public functions TypeText and Skip to print the desired text with the specified delay. We call these from a 3rd component we call Talker.

You can optionally subscribe to the PrintCompleted and CharacterPrinted UnityEvents to add additional feedback like sounds and paging widgets.

Features

  • Define Text Speed Per Character: Mayday! <delay=0.05>S.O.S.</delay>
  • Support for uGUI Rich Text Tags: <b>,<i>,<size>,<color>,...
  • Additional delay for punctuation
  • Skip to end
  • OnComplete Callback
  • OnCharacterPrinted Callback (for audio)

Screenshots

TypeText Screenshot GIF Image of TextTyper in Sparklite (© RedBlueGames 2016)

The Code

The core of our text typer is a coroutine that’s triggered via the TypeText method. The coroutine has the following steps: Check next character to see if it’s the start of a Rich Text tag

  • If It’s a tag, parse it and apply it. Right now “applying” a tag just means modifying the print delay, but other tags could be added. Add it to a list of tags that need to be closed (because we have not yet reached the corresponding closing tag in our string). Move to next character and repeat
  • If it’s not a tag, print it
  • Wait for the print delay
  • Check if we are complete

The tool also uses RichTextTag.cs, a class that’s used to help with parsing. There are a few details I left out, but this should give you enough to start reading through the code if you want to know more.

How to Help

The easiest way to help with the project is to just to use it! As you use it, you can submit bugs and feature requests through GitHub issues.

Contributors

Issue Resporters

  • JonathanGorr

License and Credits

  • TypeText is under MIT license. See the LICENSE file for more info.
  • Typing sound effect (UITextDisplay.wav) provided by @kevinrmabie. Free for others to use, no attribution necessary.

unity-text-typer's People

Contributors

casimps1 avatar devxoul avatar edwardrowe avatar synchrok avatar timminkov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

unity-text-typer's Issues

Custom Tags with Custom Functionality

Saw a tweet where someone put rumble on text printing... seems niche, but would be nice to support some way for people to do this.

Best I can think is to have custom self-closing tags (and maybe not self closing?) that just call a function.

Improve clarity of PrintCompleted Event

I find the two methods PrintCompleted and CharacterPrinted to be a little ambiguous. I get the latter, but the meaning of PrintCompleted only makes sense when you know it can't be the event for character printed since that would be redundant.

Suggestions - rename "PrintCompleted" to "TypewritingCompleted" or "TextCompleted"

Sprites reappear if followed by text with an Animation

Repro:
The following is observable in master right now by running the test scene and skipping + advancing.

  1. Print text to a TMProUGui component that includes sprites. Ex: "This is a sprite !"
  2. Change the text to something else.
  3. Call UpdateGeometry on each MeshInfo. Ex:
        var textInfo = this.TextComponent.textInfo;
        for (int i = 0; i < textInfo.meshInfo.Length; i++)
        {
            textInfo.meshInfo[i].mesh.vertices = textInfo.meshInfo[i].vertices;
            this.TextComponent.UpdateGeometry(textInfo.meshInfo[i].mesh, i);
        }

The issue is sort of with TMPro. As an optimization they leave the SubMesh objects around that are used to render the sprites. They use the same SubMesh objects for fallback fonts. Then, in TextAnimation, calling TextComponent.UpdateGeometry(this.textInfo.meshInfo[i].mesh, i); causes the garbage sprite mesh info to be resupplied to the SubMesh.

We should be able to use TextInfo.ClearMeshInfo() before every print to fix.

Sprite tag causes text to be truncated.

Using a sprite tag causes the text to be truncated (i.e. not fully typed out).

It looks like this is because the sprites are not included in the totalPrintedChars count, which is derived from the length of the text with all tags removed. So each time you use a sprite tag your text will end up truncated by 1 character.

TextTyper requires RichText on Text component but does not warn

The text component this prints to must currently use rich tags because we hide characters using a color tag.

At bare minimum we should error if they don't have RichText checked. As far as supporting it, the best thing I can think is to implement the naive solution of printing each character, if they don't have RichText enabled.

Cleanup TextTyper to use less state

The TextTyper has a couple bad smells that I'd like to get rid of:

  • It modifies the iterator (i) when applying tags in the loop
  • It modifies the displayedText member as it loops. This is critical for keeping track of what's been printed, but it can be cleaned up.

Instead I think we should add a function, SplitForTyping that would take a string and an index. It would return a struct that contains a string for the display text, a string for the hidden text, and a list of outstanding tags (which need to be applied but only if they haven't already been applied). Every loop the TextTyper would simply call this function, and act on the data accordingly.

It might not even be a function, but rather a complete class, and it should be unit tested.

Split Example scene out of the Tests Folder

Release UnityPackages typically don't include tests. Therefore, since we will want to include the example scene and sound effects I should create an Examples folder for these.

Uncap 1 character from frame limit

One character per frame is simply too slow for anything heavy on dialogue.
Sorry if this has been addressed already. I don't understand the majority of the other tickets.

problem with UTF-32 characters, like: 🍀 or 💕

those UTF-32 characters ( like U+1F340) are stored in 4-bytes sequences, starting with 0xD8xx ... thus in one moment Unity Text components receives only a first-half of the UTF-32 character, which leads to crash like this:

ArgumentException: invalid utf-16 sequence at -1819518832 (missing surrogate tail) Parameter name: string

UnityEngine.TextGenerator.Populate_Internal (System.String str, UnityEngine.Font font, Color color, Int32 fontSize, Single scaleFactor, Single lineSpacing, FontStyle style, Boolean richText, Boolean resizeTextForBestFit, Int32 resizeTextMinSize, Int32 resizeTextMaxSize, Int32 verticalOverFlow, Int32 horizontalOverflow, Boolean updateBounds, TextAnchor anchor, Single extentsX, Single extentsY, Single pivotX, Single pivotY, Boolean generateOutOfBounds, Boolean alignByGeometry, System.UInt32& error)
UnityEngine.TextGenerator.Populate_Internal (System.String str, UnityEngine.Font font, Color color, Int32 fontSize, Single scaleFactor, Single lineSpacing, FontStyle style, Boolean richText, Boolean resizeTextForBestFit, Int32 resizeTextMinSize, Int32 resizeTextMaxSize, VerticalWrapMode verticalOverFlow, HorizontalWrapMode horizontalOverflow, Boolean updateBounds, TextAnchor anchor, Vector2 extents, Vector2 pivot, Boolean generateOutOfBounds, Boolean alignByGeometry, UnityEngine.TextGenerationError& error)
UnityEngine.TextGenerator.PopulateAlways (System.String str, TextGenerationSettings settings)
UnityEngine.TextGenerator.PopulateWithError (System.String str, TextGenerationSettings settings)
UnityEngine.TextGenerator.Populate (System.String str, TextGenerationSettings settings)
UnityEngine.TextGenerator.GetPreferredWidth (System.String str, TextGenerationSettings settings)
UnityEngine.UI.Text.get_preferredWidth ()
UnityEngine.UI.LayoutUtility.m__2 (ILayoutElement e)
UnityEngine.UI.LayoutUtility.GetLayoutProperty (UnityEngine.RectTransform rect, System.Func2 property, Single defaultValue, ILayoutElement& source) UnityEngine.UI.LayoutUtility.GetLayoutProperty (UnityEngine.RectTransform rect, System.Func2 property, Single defaultValue)
UnityEngine.UI.LayoutUtility.GetPreferredWidth (UnityEngine.RectTransform rect)
UnityEngine.UI.LayoutUtility.GetPreferredSize (UnityEngine.RectTransform rect, Int32 axis)
UnityEngine.UI.HorizontalOrVerticalLayoutGroup.GetChildSizes (UnityEngine.RectTransform child, Int32 axis, Boolean controlSize, Boolean childForceExpand, System.Single& min, System.Single& preferred, System.Single& flexible)
UnityEngine.UI.HorizontalOrVerticalLayoutGroup.CalcAlongAxis (Int32 axis, Boolean isVertical)
UnityEngine.UI.VerticalLayoutGroup.CalculateLayoutInputHorizontal ()
UnityEngine.UI.LayoutRebuilder.m__2 (UnityEngine.Component e)
UnityEngine.UI.LayoutRebuilder.PerformLayoutCalculation (UnityEngine.RectTransform rect, UnityEngine.Events.UnityAction`1 action)
UnityEngine.UI.LayoutRebuilder.Rebuild (CanvasUpdate executing)
UnityEngine.UI.CanvasUpdateRegistry.PerformUpdate ()
UnityEngine.Canvas:SendWillRenderCanvases()

Strip Style Tags

Style tags are not considered the "Built-in" type, so they end up getting included in the calculations for visible text, even though they get stripped. This causes text to be truncated and index out of bounds errors.

To fix we should include "Style" as part of the Unity tags in TextTagParser.

Add Support for Text Mesh Pro

See Pull Request #14

It's a simple fix, really, but the challenge is how to structure it so that user's aren't getting errors if they don't have TMP in the project.

Add "How to Use" Section to Readme

The Readme could use some help for how you expect people to use TextTyper. I think more could be done to make it "scripting free" but right now even the scripting could use a little API overview.

Some suggestions for how to achieve it:

  • How do you install this thing? There's no package linked. If you want people to just download the code, at least mention that.
  • Snippet of all code needed to get something Typing
  • A list of "other methods" we've exposed that people can hook into - don't need to go into detail - this isn't an API Reference exactly

As I user of a tool like this, I want to get up and running as fast as possible. I might not want to use it once I see it in action so let me get to that point as fast as I can. I'll dive in for more features later. I definitely don't want to email the owner and ask "How do you intend for people to use this tool?"

Option to use in Unscaled Time / use WaitForSecondsRealtime instead

I'm using this component for tutorial dialogue. There is a case where I use it in a pause screen where Time.timeScale = 0. This component doesn't work there.
I tried changing this line:
yield return new WaitForSeconds(this.characterPrintDelays[currPrintedChars - 1]);
to
yield return new WaitForSecondsRealtime(this.characterPrintDelays[currPrintedChars - 1]);
but it leads to an exception related to the array characterPrintDelays.
Can you please add the option? Like a bool field to toggle using scaled time or not

Add parameter to animations for Strength to be relative to character size

Right now it's hard to share animations between fonts of different sizes. This is because a shake that is extreme on a small font is minimal on a bigger font.

I think using a relative strength might be most correct by default, but alternatively we could add a flag to each animation which determines if it will use absolute positions or positions relative to the size of the character.

Add an isTyping bool

It would be helpful to know if text is actively being typed. For example I use a queue system for successive messages but don't want to auto-dequeue if typing is in progress.

I personally just added public bool IsTyping { get; private set; } to the TextTyper and toggle it from appropriate locations.

Anyway, thanks for this lib. I was looking for something that handles colors and more critically, wrapping. So far this works well!

Skip() bug when replaying dialogue queue

When restarting a dialogue queue, the Skip() function seems to jump dialogue lines and fails after the first run through. Using the TextTyperTester example, I changed Start() to a function StartTyping() and have a button to call that function. After the dialogue finishes when using the "skip or advance" button, replaying the dialogue causes a bug on that button.

Modify TypedTextGenerator to use TextGenerator lines

The text generator currently moves an alpha tag to change what characters are visible, which is not optimal for garbage collection. A solution to this is to use the following code in place of the function that changes the location of the alpha tag, but some changes would likely need to be made since this is mostly unmodified from the system that I use.
// textField is the text object that the player sees, and is also where the unformatted text starts // I don't remember what tempString does, I just know that you need it // I also don't remember what start or end index do , but again, they are very important public void InitializeText() { textField.color = Color.clear; textField.text = text; Canvas.ForceUpdateCanvases(); for (int i = 0; i < textField.cachedTextGenerator.lines.Count; i++) { int startIndex = textField.cachedTextGenerator.lines[i].startCharIdx; int endIndex = (i == textField.cachedTextGenerator.lines.Count - 1) ? textField.text.Length : textField.cachedTextGenerator.lines[i + 1].startCharIdx; int length = endIndex - startIndex; tempString += textField.text.Substring(startIndex, length) + "\n"; } textField.text = string.Empty; textField.color = Color.white; // Replace with whatever color you need text = tempString; }
I'm sorry I don't know as much as I should about a script that I wrote, but I wrote this a very long time ago, and I never used to put comments in my code (I have since learned my lesson), so I hope you can make at least some sense of this. Despite all of these problems with it, I hope you get at least some use out of this script even though it was very poorly done, and i will probably need to redo it at some point

Sprite tag issue

When having a tag, the script assumes it requires a closing and adds it to the final text that's being printed. Also for some reason the sprite appears as soon as the typing appears instead of being "typed".

Cleanup TypedTextGenerator by doing more operations on SymbolLists

We could break the symbol list into two lists - one for visible and one for hidden text. Instead of doing operations on text, we should do operations on the symbol lists.

For example: RemoveFirstOccurance(string, text) uses a string operation to take out tags. We could instead just remove it from the symbol list.

So we build the two strings entirely from symbol lists, then just do a ToString() on each SymbolList.

SymbolList should probably be made into a class.

This is all just to make the code a bit cleaner.

Some TMPro tags are not stripped, resulting in exceptions

We need to strip all native tags when parsing the text, or else it will calculate the wrong number of characters to print and results in an ArgumentException.

Repro:

  1. Add a <style> tag to text
  2. Print it
  3. Observe ArgumentException

To fix, we either need to add all missing "Unity" tags to the parser, or calculate characters to print based on the visible text. For now the easiest fix is to include all missing tags. Ex:

style
link

Another issue that could come up is you can use color like "<#FFFFFF>" instead of <color=#FFFF>. If that results in this same issue, we may want to look at solution that examines the visible text.

Animation Framerate should be customizable

Users shouldn't have to modify core code to change the framerate of the animations.

We should either expose the framerate as a setting, or make it a setting per Animation. I'd vote the latter if it's possible.

Off centered bold text

When having centered and bolded text, while it's being typed it will slightly move left each time a character appears.

Delay tag should take optional multiplier

Delay as a fixed amount is a bit problematic if users change default print speed. This tag could support a multiplier like <delay=1.5x> which would multiply their default print speed.

Delay persists between lines of dialogue.

The text typer doesn't reset the text speed on a new line. The bug occurs when you skip dialogue between delay tags. I fixed this temporarily by prefacing each new line with its own delay:

scripts.Enqueue("<delay=0></delay>" + conversationText);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.