The cursor is another important UI element that is not directly controlled by UI classes. This is the case since they are new in Unity, while the cursor was already implemented earlier. However, changing the cursor at runtime could be very useful for the player to distinguish different actions, and it can also be graphically nicer. For instance, in a Real-Time Strategy (RTS) game, the cursor can change when the player decides to move units or orders them to attack enemies.
At this stage, you are also ready to learn other techniques to deal with UI events, directly inside your scripts, instead of setting them through the Inspector, maybe also using the Event Trigger component. In fact, here you will learn how to use event handlers to triggers events in your script.
In this example, we will see how to change the cursor when it enters or overlaps another UI element. This is the most common case of cursor changing, and you will come across different games that have this mechanism.
using
statement that we haven't used so far. This is because the script needs to import all the functions relative to the event system. So, let's write at the beginning of our script using
UnityEngine.EventSystems;
.MonoBehaviour
add these two interfaces: IPointerEnterHandler
and IPointerExitHandler
, all of them separated by commas. Thus, the entire class line should be as follows:public class ChangingCursorScript : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler {
public
variables to store all the parameters that we need for a new cursor. The first one is, of course, its texture. The second one is a vector for storing the hotspot (that is, the distance from the top-left corner of the texture) to place the real pointer of the cursor (the place where we can actually click). Finally, we have the mode of the cursor. Furthermore, we can initialize both the vector and the mode with default values, but in general, they have to be set from the Inspector. So let's write this code:public Texture2D cursorTexture; public CursorMode cursorMode = CursorMode.Auto; public Vector2 hotSpot = Vector2.zero;
SetCursor()
, here it is:public void OnPointerEnter(PointerEventData eventData){ Cursor.SetCursor(cursorTexture, hotSpot, cursorMode); }
public void OnPointerExit(PointerEventData eventData){ Cursor.SetCursor(null, Vector2.zero, cursorMode); }
texture
cursor in the script, and nothing else. The last thing to do is click on play and see whether it works as it should.Here, we created a script that changes the cursor when it enters a UI element.
When we implement handlers, we have to write specific functions with a specific signature so that they can be called when the event that they are "listening" for occurs. In this case, when the pointer enters our panel, the OnPointerEnter()
function is called, because this script is attached to it. A similar thing happens to the OnPointerExit()
function.
Of course, we can implement this mechanism for the previous recipe in its entirety, where it was needed to trigger a specific function when it occurs. Furthermore, for this specific function, there is also a parameter called eventData
. This is a PointerEventData
, and it contains useful information that we may want to use in order to achieve the goal of the function.
By changing the cursor at runtime, it is possible to create animated cursors.
Besides determining how the change of cursor is performed, in some games, we can also have animated cursors. Unluckily, there isn't a way to do this natively. As a result, we need coroutines to keep changing the cursor in order to animate it.
First, we need to change the cursorTexture
variable to an array of textures so that we can have a different texture, one for each frame. Therefore, we should have the following line:
public Texture2D[] cursorTexture;
Then, we also need another variable to be set in the Inspector that represents how many seconds should elapse before the change to the next frame, like this:
public float secondsBetweenFrames;
Now, in OnPointerEnter()
, we need to make the animateCursor()
coroutine start. We will write this later, so this is what the function becomes:
public void OnPointerEnter(PointerEventData eventData){ StartCoroutine (animateCursor()); }
Alternatively, in OnPointerExit()
, we need to stop the coroutine and restore the cursor to its original state. Therefore, we can write it in this way:
public void OnPointerExit(PointerEventData eventData){ StopCoroutine (animateCursor()); Cursor.SetCursor(null, Vector2.zero, cursorMode); }
Now let's create the coroutine. We need to create an infinite loop using a while(true)
cycle so that our cursor keeps changing until we stop the coroutine. Then we need to scan the array of textures. As a result, we can create a for
cycle for it. Finally, we can assign the current texture, the one that our code is scanning, and wait for the amount of time that is specified in the secondsBetweenFrames
variable using a yield
statement. Here is the code:
IEnumerator animateCursor(){ while (true) { for(int i = 0; i<cursorTexture.Length; i++){ Cursor.SetCursor(cursorTexture[i], hotSpot, cursorMode); yield return new WaitForSeconds(secondsBetweenFrames); } } }
For more information, you can refer to all of the official documentation related to these topics:
3.22.41.235