Changing the cursor at runtime

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.

How to do it...

  1. To begin, we have to create a UI element that will allow us to change our cursor. In this example, we can create a panel by right-clicking on the Hierarchy panel and then navigating to UI | Panel. Finally, rename it to CursorChangingPanel. Of course, as usual, it is possible to resize it, change the Source Image, change the text inside, and finally place it as we wish on the Canvas.
  2. Since our script will be ready to use and it contains handlers, we don't need to set anything. In order to create it, select CursorChangingPanel and, in the Inspector, navigate to Add Component | New Script. Name it ChangingCursorScript and then click on Create and Add.
  3. Double-click on the script to edit it. Now, we are going to use event handlers, and in order to do this, we need a new 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;.
  4. The next step is to declare the handlers. In some way, our script depends on them and extends itself with pre-designated functions. So, after 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 {
  5. We need three 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;
  6. Now, it's time to implement the pre-designated functions that we have quoted before. Here, the first functions, that it is called when in the pointer enters the UI element, where this script is attached. We change the cursor to the new one, but calling SetCursor(), here it is:
      public void OnPointerEnter(PointerEventData eventData){
        Cursor.SetCursor(cursorTexture, hotSpot, cursorMode);
      }
  7. The next one is the opposite to the previous one, and it resets the cursor when the pointer exits from the UI element:
      public void OnPointerExit(PointerEventData eventData){
        Cursor.SetCursor(null, Vector2.zero, cursorMode);
      }

    Tip

    The preceding two functions cannot have a different signature — names plus parameters. This is because they are all called, since we are using handlers.

  8. Save the script. Since the script is ready to work, we only have to set the 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.

How it works...

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.

There's more...

By changing the cursor at runtime, it is possible to create animated cursors.

Animating the cursor

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);
      }
    }
  }

See also

For more information, you can refer to all of the official documentation related to these topics:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.225.72.245