Unity – Simple dialogue with correct word-wrapping

I ran into an issue with getting the correct word-wrap behavior in Unity using the Canvas Text UI element. I wanted to create a simple dialogue system that added characters of a string a bit at a time in order to simulate character speech, a common-enough request. However, with Horizontal Overflow set to Wrap, line-breaks are added when the word flows outside the box. And since Unity doesn’t know how long the rest of the word is, the word jumps to the next line in the middle of writing, which looks weird.

I adapted the following solution based off an answer found here. I set a total duration for the entire dialogue text to complete, and I find the index of the separator between visible text and invisible text. Then, with Rich Text enabled, I add the “color” tag, which sets the color of the rest of the text to 0 opacity.

private IEnumerator _PlayDialogueText(string text, float duration)
{
    float timer = 0;
    int separator = 0;
    m_text.text = "";

    while (timer < duration)
    {
        // Find midpoint in string.
        separator = (int)Mathf.Lerp(0, text.Length, timer / duration);

        // Divide string in 2 and add color at separator.
        string left = text.Substring(0, separator);
        string right = text.Substring(separator, text.Length - separator);
        m_text.text = left + "<color=#00000000>" + right + "</color>";

        timer += Time.deltaTime;
        yield return null;
    }

    m_text.text = text;
}

Now the Text element knows the length of each word in the string; it just doesn’t display the latter half.

Admittedly, this isn’t the most friendly solution in terms of garbage collection, but it’s simple enough to implement on a first pass. I’d love to hear a smarter implementation, perhaps using StringBuilder?

Unity – Scaling instantiated child elements in uGUI

It’s been a while since my last post, but I randomly discovered that someone RT’d my tip about safe renaming in Unity. I just ran across something else that isn’t really complex, but I’ve had run-ins with it a number of times. I’ll continue to post common issues that I encounter if it ends up being useful to someone out there.

Unity’s native GUI system is powerful and covers most use cases. But one thing I’ve consistently needed to do is create a number of child elements that are parented to a RectTransform that has a width that scales with screen width. While your RectTransform may look fine when hand-parented in the hierarchy, Unity performs a number of hidden transformations when an object is instantiated from a script and then parented.

Screen Shot 2015-11-05 at 12.20.32 PM

What you see in the editor.

Screen Shot 2015-11-05 at 12.20.07 PM

What you see during runtime.

I needed to parent a number of characters to a ScrollRect menu, but their offsets were incorrect when parented. This probably occurs because my content panel width scales with the screen width, causing a bit of chaos when parenting and scaling the offsets according to my content width.

Basically, I need to re-assign the x-values of my offset (the y-values are a fixed size of 64 and do not scale with screen height).

for (int i = 0; i < GetInventoryCharacterCount (); i++) {
	// Create new button for char in inventory.
	GameObject gobj = GameObject.Instantiate (this.loadoutCharacterButtonPrefab, Vector3.zero, Quaternion.identity) as GameObject;
	gobj.transform.SetParent (this.contentParent);

	// Reset position and offsets of button.
	RectTransform rt = gobj.GetComponent<RectTransform> ();
	rt.offsetMin = new Vector2 (0.0f, rt.offsetMin.y);
	rt.offsetMax = new Vector2 (0.0f, rt.offsetMax.y);
	rt.anchoredPosition = new Vector2 (0.0f, i * -64.0f);
	rt.localScale = Vector3.one;

	// Populate character button with info from inventory.
}

The key is to reset the x-offsets to 0, or whatever you want the offsets to be. I’m keep the same y-offset, but you may have a different usage depending on what elements you want or don’t want to keep fixed.

rt.offsetMin = new Vector2 (0.0f, rt.offsetMin.y);
rt.offsetMax = new Vector2 (0.0f, rt.offsetMax.y);

Also, the prefab that I’m instantiating is set to scale with the parent content.

Screen Shot 2015-11-05 at 12.16.12 PM

I have a scaling width, fixed height, and anchor and pivot set to top.

After that, you should have no problems with the child element being rescaled.

Hope this helps!

Unity – Class renaming solution

This is just a quick note-to-self, though hopefully it might help someone out with some headaches in the future.

I’ve had a number of issues with renaming scripts/classes between MonoDevelop/Xamarin and the Unity engine itself. Refactor -> Rename of the class itself in the IDE will very likely cause a number of scripts to become unlinked within the script component attached to a GameObject. This will happen whether the GameObject is in the scene hierarchy or in the project, forcing you to re-link the script to the GameObject.

Turns out the way to do this without breaking links is:
1. Rename the script file in the engine to the desired name.
2. Refactor -> Rename the class name in MonoDevelop/Xamarin.

Then everyone is happy!

Making an Endless Runner – Part 0 – Endless Runners Suck

The Endless Runner genre has brought a lot to mobile gaming in its prime. The popularity of runner games has provided a fantastic entry point for scores of players to experience the gaming world. They are easy to learn and intuitive to play.

That being said, I still considered them thoroughly boring to both play and develop. Alongside many other others out there in mobile development, I generally think that they’re a dead genre. Larger mobile studios love these games due to the low-risk existing market, minimal investment into design, and ease of monetization through extra skins and in-game currency. Basically, running-game innovation is over, and the market is over-saturated.

This is the wrong approach.

Games are unlike movies, TV, and other entertainment media, as we are still creating new experiences and new ways to interact. There will always be new approaches to things in games. With that in mind, I sought to add my own take on an endless runner game by integrating the gameplay elements that I usually love to have in games but aren’t typical to the existing genre.

Making an Endless Runner – Part 1 – Generating Endless Levels

Encapsulate timed events with coroutines in Unity

Creating a separate timer and incrementing it with each Update() step can be useful…sometimes. Certain events that occur in Update() may need to reference the timer’s value directly, in which case it’s just easier to create a timer specifically for that purpose.

But before you decide to create another float timer, consider that coroutines in Unity can make timed events easier to track and improve your code’s readability.

WaitForEndOfFrame()
If you have a timed event that would otherwise run inside an Update() call, try running a coroutine using,

yield return new WaitForEndOfFrame()

It’s a clean, encapsulated way to run a sequence event outside of Update() while retaining functionality (and using a locally defined timer instead).

Example: Move a GameObject for 5 seconds.

public class CoroutineTest : MonoBehaviour{
    public GameObject bob;
    void Start(){
        StartCoroutine( PrintDelayedSequence(bob, 5.0f) );
    }

    IEnumerator PrintDelayedSequence( GameObject gobj, float delay ){
        float timer = 0.0f;
        while (timer < delay){
            gobj.transform.position += Vector.right;
            yield return new WaitForEndOfFrame();
            timer += Time.deltaTime;
        }
    }
}