Tuesday, March 4, 2014

Unity Tutorial: Scrolling Ticker Text

As I work more and more with Unity, I've begun to learn tricks and tools that I'm guessing would probably be useful to others as well. In my most recent game, Bubble Market, I created a scrolling ticker text box at the bottom of the screen to display active events which were effecting the game at any given point in time. This kind of scrolling text is useful as a general UI element, so I made sure to keep the script generic enough to be re-used. It also occurred to me that these sort of tools may be useful to others as well, so I thought I'd write a quick post explaining what I did, how I did it, and providing the script as an example.

Step 1: Scissoring

The first thing you need to create a scrolling ticker text object is a graphical effect known as scissoring.
Scissoring: In computer graphics, the deleting of any parts of an image which fall outside of a window that has been sized and laid over the original image. Also called "clipping."
There are some more advanced ways to create this effect in Unity, but I went with the easiest route: using a separate camera to render the scissored object. If your scene has a lot of scissoring with different areas going on, I'd suggest looking into other methods, but for simple and limited applications, the camera method works just fine.

To apply this technique, first set up your object without scissoring enabled. Make sure it's large enough that it is easily evident whether your scissoring is working or not. For my example, I used a long test string in my ticker text mesh:

Before we set up the camera, you'll need to change the layer this object is set to. In the upper right of the object's inspector window, click the Layers drop-down and choose to create a new layer. Call it something like "ClippedObjects". Set your ticker object to the new layer.

Now, in your scene hierarchy, duplicate your main camera. Call the new camera something like "Clipping Camera". Make sure these two cameras are in exactly the same place in the game world. You'll need to make several important modifications to the cameras:

  • Clear Flags: On the Clipping Camera, change clear flags to "Don't Clear".
  • Culling Mask: On the Clipping Camera, change the Culling Mask to only have ClippedObjects (our new layer) selected. You'll also need to modify the Main Camera's Culling Mask, so that ClippedObjects is NOT selected. This will make our new camera only render this layer, and our old camera ignore it.
  • Viewport Rect: This is the actual rectangle where the clipping will take place. On the Clipping Camera, define it to whatever you like. You should be able to see the camera's bounds in the scene, and the effect in the camera preview and Game panel.
  • Depth: Make sure the depth of the Clipping Camera is higher (more positive) than the depth of the Main Camera. This will ensure the Clipping Camera is drawn AFTER the Main Camera, which is what we want.
If you run the game, your object should now be clipped based on the Viewport Rect you set on your new camera.

Step 2: Scrolling

This was the first part of the effect I was after, a ticker text where the text disappears as it scrolls to the side. Now for the scrolling itself.

The actual scrolling is just a simple change to the object's transform each frame, I won't bore you with that. The interesting bit was figuring out when the object was no longer visible, and figuring out exactly how far to the right to place it so it can start scrolling again.

While I could have simply used the renderer's isVisible property to tell if it was off screen, this wouldn't have been enough for the second part of the scrolling: moving it back to the other side of the screen. Instead, I decided to use the renderer's bound property, which measures the bounds of the object in world coordinates. I set up minimum and maximum x limits for the visible range of the object, which correspond to the viewport I set up in Step 1. I saved these limits as data members in the script.

With this set up, I can easily tell when the object has moved off screen to the left by comparing the renderer bounds of the object to my saved x limit:

ResetScroller() is a method which moves the scrolling text to the right, just off screen and ready to start scrolling again. We determine where to place this text in the same way that we determined when it was off screen: using our scissor limits and the object's renderer bounds:

This first calculates the width of the object in world space, then edits the object's x coordinate to be the maximum plus half it's width. This is because my text object is centre aligned - however, if your text is aligned left, you won't need this step.

If you create a simple script and apply the method described above, you should see something like this:

Further Modifications

What I described above will get a basic scrolling text functionality in place. However, what if you want to change the text? What if something tries to change the text mid-scroll? Currently, the text will change right there, somewhat ruining the effect. For my scroller, I designed a queue system which accepts new messages and switches to the next message while the text is off screen, or repeats the last message a specified number of times (or infinitely). I'm sure there's a lot more functionality you could add to the system even beyond that.

If you'd like to see the finished product, I've made the script available as a gist. Feel free to use it directly or as a model for your own creations.

What interest text systems have you added to your Unity programs? Please share if you implement the ticker text system in your game - I'd love to see this tutorial being put to good use.

Thanks for reading! 

No comments:

Post a Comment