Unity: Creating GUI transitions
Posted by Dimitri | May 4th, 2012 | Filed under Programming
This Unity scripting tutorial shows how to manipulate the GUI system origin to create an animated transition, so you can make your GUI’s look more interesting. To keep things simple, this post shows how to create an horizontal transition between two Text Areas using a couple of buttons. All code featured below is available for download at the end of the post.
To achieve an animated transition, the origin of the GUI system must be manipulated. This is done by changing the elements of the matrix that sets the rendering reference point of the GUI elements. Conveniently, Unity allows us to do that by manipulating the GUI.matrix values. So, the script requires a Matrix4x4 object. Also, to make the code more readable, a Vector3 is going to be created, also making it easier to translate the GUI system origin. Here’s the script:
using UnityEngine; using System.Collections; public class HorizontalTransitionGUI : MonoBehaviour { //A 4x4 Matrix private Matrix4x4 trsMatrix; //A three dimension vector that will translate GUI coordinate system private Vector3 positionVec; //Two booleans to determine which of the GUI buttons have been pressed private bool next = false; private bool back = false; // Use this for initialization void Start() { //Initialize the matrix trsMatrix = Matrix4x4.identity; //Initialize the Vector positionVec = Vector3.zero; } // Update is called once per frame void Update() { //If the 'next' boolean is true if(next) { //Interpolate the current vector x component until it has the same as value the screen width positionVec.x = Mathf.SmoothStep(positionVec.x, Screen.width,Time.deltaTime*10); /*Make 'trsMatrix' a matrix that translates, rotates and scales the GUI. The position is set to positionVec, the Quaternion is set to identity and the scale is set to one.*/ trsMatrix.SetTRS(positionVec , Quaternion.identity, Vector3.one); } else if(back) //If 'back is true' { //Interpolate the current vector x component until it reaches zero positionVec.x = Mathf.SmoothStep(positionVec.x, 0,Time.deltaTime*10); //Make 'trsMatrix' a matrix that translates, rotates and scales the GUI. trsMatrix.SetTRS(positionVec , Quaternion.identity, Vector3.one); } } void OnGUI() { //The GUI matrix must changed to the trsMatrix GUI.matrix = trsMatrix; //If the button labeled 'Next' is pressed if(GUI.Button(new Rect(Screen.width - 400, 315, 100, 30),"Next")) { next = true; back = false; } //The TextArea that appears on the first screen. GUI.TextArea(new Rect(300,200,Screen.width-600,100), "Click on the 'Next' button to change the Text Area."); //If the button labeled 'Back' is pressed if(GUI.Button(new Rect(-Screen.width + 300, 315, 100, 30),"Back")) { next = false; back = true; } //The TextArea that appears on the second screen GUI.TextArea(new Rect(-Screen.width + 300,200,Screen.width-600,100), "Click on the 'Back' button to return to the previous Text Area."); //To reset to GUI matrix, just make it equal to a 4x4 identity matrix GUI.matrix = Matrix4x4.identity; //A Label that won't change position GUI.Label(new Rect(300,350,500,100),"This Text Label remains at the same position, no matter what."); } }
Right at the top of the script, a Matrix4x4 object, a Vector3 and a pair of boolean variables are being declared. As previously stated, the Matrix4x4 is going to be the one that will replace the GUI matrix later on the code. The Vector3 is there to aid in the task of building the aforementioned Matrix4x4 as a translation matrix. The pair of booleans are declared to tell if one of the buttons have been pressed (lines 7 through 12).
At the Start() method, the Matrix4x4 is initialized as a identity matrix and the Vector3 objects is initialized as a a null vector (lines 15 through 21). The Update() method is where it all happens. In the above script, it’s basically a if else block that checks whether the value of the next and previous booleans are true or false; changing according to the button pressed at the interface (lines 24 through 44). If next is true, the positionVec X component is interpolated the SmoothStep() method, which takes three parameters.
The first one is the value the interpolation is going to start, the second is the value where the interpolation ends and the third, can be thought as the speed which in the interpolation must happen. In the above script, the parameters are, respectively: the positionVec X component, the screen’s width and the Time.deltaTime value multiplied by 10 (line 30). So, what will happen is that the X component of postionVec will be gradually interpolated using the third parameter until the X component of the Vector3 has the same value as the screen width. Effectively, this will move the whole GUI system origin out of the screen when it’s matrix translated with the recently interpolated component of the Vector3.
To create a translation matrix, the TRS() method is called from the Matrix4x4 object, taking three parameters. The first one is going to be positionVec and since the rotation and scale of the GUI system must remain the same, the second and third parameters are filled with Quaternion.identity and Vector3.one (line 34). That’s it! With that, all that’s necessary is to replace the GUI.matrix with the trsMatrix. This can only be done inside the OnGUI() method, which starts at line 46 and ends at line 76.
After replacing the GUI coordinate system with the trsMatrix at line 50, some elements are being rendered, namely a pair of Buttons elements, two TextAreas elements and a Label. All elements, except for the Label are being rendered with their X position relative to the screen’s width. That’s because the GUI’s system reference X value is going to be shifted from zero to Screen.width at the Update() method, so it makes sense to make everything dependent on the screen width. The Label doesn’t change position because the current GUI.matrix it’s using as the reference for positioning is the identity matrix.
Also, the two buttons declared here changes the value of the next and previous boolean variables accordingly. It’s worth mentioned that the OnGUI() method resets the GUI.matrix to identity each call, so line 75 (the GUI.Label() method call) could be placed before line 49 (GUI.matrix = trsMatrix;), yielding the same results.
Final Thoughts
Some readers might be wondering why manipulate the GUI system matrix to create a simple horizontal transition when the same could be easily done by changing the X coordinate of a GUI group. And surely, some are wondering why use the Matrix.TRS() method to make a simple translation, when all it takes is to change the last element of the first line of the trsMatrix (trsMatrix.m03).
For the above example, the aforementioned alternatives could easily be used as it’s just a simple horizontal translation. However, for more complex transitions, such as the ones that changes the rotation and the scale, a matrix is necessary. Remember that, in Unity, there’s no way to change the scale or rotation of some GUI element without altering the current GUI.matrix. Furthermore, on those cases, changing the GUI.matrix is necessary.
Here’s a video of the transition code in action:
Thanks for this,
Very clear, got me out of a Jam.
Keep up the good work mate.
Thanks!
Thank You very much !
Hi…can you give us some tips on how to position the GUI transition to bottom???
thanks man… you’re the best :D
i want a translation to right to left how ?