[4.9] Custom Cursors using UMG Widgets (with image change on mouse-over!)

Hi forum

I recently figured out something that I found was not documented very well or otherwise to be found on AnswerHub or here, on the forums. But I’ve seen plenty of people struggle with it, so I’m going to give you my approach on the matter.

What we’re going to do is build a simple system in which you have your custom cursor, independent of the OS’s cursors, that changes into another cursor when you mouse-over certain actors (for example, interactables like a chest).

So let’s get started!

orangeCursor.png
awesomeCursor.png
Here are our cursor images that we’re going to use for this game. The orange cursor is the default, the Awesome cursor is what we’ll use when we mouse-over a square tile actor.

Let’s import the images into the editor. Right-click, Sprite Actions > Apply Paper2D Texture Settings. Call the orange cursor orangeCursor and the Awesome cursor awesomeCursor.

Right-click in the content browser and click Blueprint Class;
Search for ‘User Widget’ under All Classes;
Create a Widget of class User Widget;
Let’s name it mouseWidget;
Open mouseWidget for editing.

On the Designer panel, we’ll delete the Canvas panel and under Common, drag an Image onto the [mouseWidget] in the Hierarchy. To the top-right of the Canvas Panel, where it says “Fill Screen”, click and select the option “Desired on Screen” to display the image in its true proportions. Our cursor images are 32x32 pixels, so in the Details panel, expand the Brush option and set the Image size to 32 in both X and Y dimensions. We’ll choose our orangeCursor as the brush image. But note that this will not actually determine the appearance of your cursor! It is just a placeholder so that we can see which of the widgets is our cursorWidget for if we want to add this cursor to some other encapsulating Widget system in the future for some reason. To the right of ‘Brush’, click ‘bind’ and create a new binding. This is what our Widget looks like on the Canvas panel (right-click: open in new tab to see the full image):

Creating a new binding opens the Graph view. Create a new variable and call it ‘cursorImg’. Make sure it’s of the Texture2D type. Set your orangeCursor image as its default image. Back on the Designer panel, click the bind button again and select your cursorImg variable as the binding.

Now let’s set the widget up to follow the mouse position wherever it goes. Set up the following blueprint nodes in the Graph view of the mouseWidget:

That’s all for our widget.

Create a new PlayerController blueprint. We’ll call it Mouse_PC. Click to open its Initial Values and scroll down until you see Mouse Interface. We need to make sure Enable Mouseover Events is enabled:
Screen Shot 2015-09-14 at 15.10.50.png
We don’t need the OS default cursor, so we’ve disabled it here, too.
(The enable click events is not strictly necessary for the scope of this tutorial, but may be useful in case you also want to add click interactions later.)

Next, in its Event Graph, set up the following blueprint nodes:


We create a Widget of class mouseWidget and set its cursorImg variable to our orangeCursor texture. Then we promote the resulting reference to a variable for future use. We call it mouseReference. Then, add the Widget to the Viewport.

We are done with our Player Controller.

Finally, we’ll set up an actor that we will hover our mouse over. This actor will tell the Player Controller that it has been moused over and that the cursor should change. Create a square texture sprite (just make it a white square; doesn’t matter). In its Viewport, add a PaperSprite component and make it the square texture sprite that you just created.

Now, in its Event Graph, add the following nodes:


At the begin of play, create a reference to the Mouse_PC Player Controller. We’ll need it later. We create this reference so we don’t need to keep casting to the Mouse_PC whenever we want to tell it to change its cursor.
The next bit is easy. From our Mouse_PC reference, we grab the reference to the mouseWidget we made earlier. And then, ‘as the mouseWidget’, we change the cursorImg to either awesomeCursor or orangeCursor depending on whether we moused over the actor or leave its bounds.

Finally, create a custom GameMode and set up for the Player Controller to be the default Player Controller for this level.
Screen Shot 2015-09-14 at 14.53.13.png
In the World Settings, set this new Game Mode to be the Game Mode Override.
Screen Shot 2015-09-14 at 14.53.35.png

Drag your actor into the level and test!

And voila!
Screen Shot 2015-09-14 at 00.11.58.png
Screen Shot 2015-09-14 at 00.12.10.png

You can add as many mouse cursors as you like. Just keep grabbing the reference to your Player Controller, which grabs a reference to the mouseWidget and change the cursorImg as you please!

This tutorial can also be extended to 3D space. It doesn’t necessarily only work on sprites. I just found it simpler to explain this with sprites.

Nice, thanks for the info.

The custom cursor options do the mouse rendering for you. There’s no reason to add to the viewport or manage the draw location. It’s in Project Settings > User Interface > Cursors.

I’d then move my mouse over logic into the cursor, and every tick do a trace at the current location to figure out what I was over.

Also possible, but the problems with those cursors is that there’s only a limited amount (say 8?). What if I wanted to have 50 cursors in my game?

Is a trace per tick cheaper performance-wise than using specifc actors’ mouse enter and mouse leave events? If so, yeah, that’s the way to go.

EDIT:
Ah no, I see what you mean. You have a cursor widget assigned as your default cursor and then have the logic of changing images in the cursor itself! Hm, possible. Let me experiment with that.

EDITII:

I’ve played around with it a bit. Is this what you mean?

This is the only functionality still remaining. I’m using the Project Settings > UI > Cursors > Default Cursor and have my mouseWidget in there.

Then these nodes are the only nodes that deal with mouse cursors. The player controller now has ‘show cursor’ to true (else there’d be no cursor). Additionally, my ‘tile actor’ has a tag now called ‘Interactable’. Once the mouse hovers over this actor with tag ‘Interactable’, it turns into Pointer Valid (analogous to awesomeCursor). Else, it’s Pointer Invalid (orangeCursor). When it hovers over nothing or over another actor which doesn’t have that tag, it remains as ‘Pointer Invalid’.

I’ll probably clean up this code with a branch to check if the cursorImg isn’t already set to Pointer Invalid; else you’d be setting it to Pointer Invalid repeatedly for no real reason.

I like this approach. It cleans up the amount of places where there’s code pertaining to the cursor, namely only in the cursor itself (which makes more sense).

Yup, you’ve got it :slight_smile:

I like that better. I’ll change the first post soon.

Hey there,

first of all thanks for the tutorial. I created a Widget and set it to the Default Cursor in the Project settings.
Sadly the Cursor click seems to happen in the middle of the Cursor. My Cursor is placed in the top left corner.

Do i need to make the Cursor image bigger and place the upper left corner as the middle pixel?

EDIT: Ok, placing it in the middle solves it:

Just for the calculation:

My cursor image itself (so the real visible cursor) has 22 pixel width and 27 pixel height.
To place the upper left pixel in the middle of the actual cursor, i added “width - 1” and “height - 1” to the image size (in photoshop)
to get 43 pixel width and 53 pixel height. Now the click feels correctly and also the cursor reaches the viewport site at the correct
point.

2 Likes

Yeah, I found that it will have that behaviour of receiving click events in the centre of your picture.

Additionally, you could also alter the cursor image’s Render Transform in the UMG widget Editor and shift it in X and Y by half the image’s dimensions (eg. a 20x20 cursor image is shifted in both X and Y by 10) so that the widget itself is simply moved a little to give you the desired behaviour of clicking where the pointer points.

I’ll add that to the tutorial too when I get round to editing the first post.

You can also set the cursor pivot under “render transform” to {0, 0} instead of {.5, .5} and the cursor will no longer be centered

the cursor under project settings has some issues though, it’s not showing up when I build my game but it does show in PIE/PIE standalone. Also the initialization order seems to differ between PIE and standalone

set pivot seems no effect, it only affects rotation and scale.

Hello. I found the answer to this question. The system works without fail regardless of (Anchors) or (Screen Size). Hope I could help you !!!

How do you set your cursor widget to render in front of all other widgets?

Necroing this one.

I’m trying to make custom cursors in UMG. I’m setting a widget in the Project Settings and ensuring my Player Controller is using the same setting (Default in all cases). However, the cursor doesn’t change to my custom widget. Changing the Player Controller setting does update to the built in cursors (Hand, Slashed Circle, etc). Is there something else that has to be done to make this work?

I’m trying to make custom cursors in UMG. I’m setting a widget in the Project Settings and ensuring my Player Controller is using the same setting (Default in all cases). However, the cursor doesn’t change to my custom widget. Changing the Player Controller setting does update to the built in cursors (Hand, Slashed Circle, etc). Is there something else that has to be done to make this work?

The unconnected code here works at runtime, but using the built in system through Project Settings doesn’t for some reason. Not sure what I’m missing. I’d prefer not to have to change this every time I swap screens/modes/maps, etc… Any help would be appreciated.