July 16, 2019

Scrolling UI Text

Create a flexible text scroller for Unity.

Scrolling UI Text

Unity 2018.1+ (I'm using the latest 19.1 betas)
Basic C# Scripting

What we are making in this tutorial.


1. Create a UI > Canvas Gameobject via the Heirarcy. Rename it to Scroll Menu.


2. Create an empty child gameobject and rename About. Create another empty child gameobject and rename it background. Enable Gizmos to see the outline of your canvas.


3. Create a child text gameobject. Rename it Page Title and enter About as the Text(script) input.

3. Always keep the Heirarcy clean and easy to read

4. Create another Empty gameobject. Name it mask and add a Rect Mask 2D component to it. Add a UI > Text gameobject as a child. Name it TextToScroll. If you move TextToScroll it will only appear inside the mask.


5. Lets tidy the menu a little. Scale the background gameobject so it's easier to see and provides better context. Scale the mask using height/width in the Inspector. Make it nearly the same size as the backgound image.

5. Notice in the game view how to text is masked.

6. Lets add the code that makes our text move. Select Scroll Text and add a new C# script component to it. Call it Scroll. Open the newly created Scroll.cs file.

We will add a bool to signal we want to repeat, an int to control the speed our text moves and the game object that holds out text.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Scroll : MonoBehaviour
{
    public bool repeat;
    public int scrollSpeed;
    public GameObject textToScroll;
    
}

7. Now we create a rectangle based on our canvas size. We will use this to check if another object overlaps

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Scroll : MonoBehaviour
{
    public bool repeat;
    public int scrollSpeed;
    public GameObject textToScroll;
    
    //We want to store the world position of the
    //canvas to the screen as a rect.
    private Rect screen;

    public void Start()
    {
        // Get the parent canvas of the current game object
        Canvas menuCanvas = gameObject.GetComponentInParent<Canvas>();

        // Grab the tranform position as a world point
        // First zero then the width and height
        Vector3 canvasWorldPointZero = menuCanvas.worldCamera.ScreenToWorldPoint(Vector3.zero);
        Vector3 canvasWorldPointWH = menuCanvas.worldCamera.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height));

        // Draw our rectangle. First the position from canvasWorldPointZero then to the width and height.
        screen = new Rect(canvasWorldPointZero,
            new Vector2(canvasWorldPointWH.x - canvasWorldPointZero.x, canvasWorldPointWH.y - canvasWorldPointZero.y));

    }
}

8. Now we update the screen if our text is displayed inside the canvas

public void Update()
    {
        //Create an array of four values to store our text corners
        Vector3[] wc = new Vector3[4];

        // Grab the corners of our text rect tranform. 
        textToScroll.GetComponent<RectTransform>().GetWorldCorners(wc);

        // Create a rectangle based on our text to scroll game object
        // the same as we did above
        Rect rect = new Rect(wc[0].x, wc[0].y, wc[2].x - wc[0].x, wc[2].y - wc[0].y);


        // Check if it overlaps the canvas rect using the overlap function
        if(rect.Overlaps(screen))
        {
            // Move the text up
            textToScroll.transform.Translate(Vector3.up * (scrollSpeed * Time.deltaTime));
        }
    }

9. This example uses Screenspace Overlay - Camera so we will have to set up our camera to deal with that. Select Scroll Menu and change the Render Mode to Screen Space - Camera. Drag the Main Camera into the Render Camera slot. The canvas will adjust so the canvas is over the cameras view plain. Find the Scroll(Script) compnent. Assign a int as the speed and TextToscroll as Text To Scroll.

Press play. Your text should now move towards the top of the screen and stop when outside the canvas.

10. To make the text repeat will need to store the original position of the text. Add `private Vector3 startPosition;' to the list of variables

public class Scroll : MonoBehaviour
{
    public bool repeat;
    public int scrollSpeed;
    public GameObject textToScroll;
    
    private Rect screen;
    private Vector3 startPosition;

Lets store it in our start fuction

public void Start()
    {
        //Get the start position of our text
        startPosition = textToScroll.transform.position;

        ...
    }

Finally we extend our if statement to check if our text is no longer being rendered on the screen.

// Check if it overlaps the canvas rect using the overlap function
if(rect.Overlaps(screen))
        {
       // Move the text up
       textToScroll.transform.Translate(Vector3.up * (scrollSpeed * Time.deltaTime));
        }

        else
        {
            //Enable our bool variable
            if(repeat)
            {
                textToScroll.transform.position = startPosition;
            }
        }
        
        ...

Head back into Unity and select the Scroll Menu and enable Repeat. Now play the scene. Your text will repeat from the bottom once it leaves the canvas.