Bite-Sized Godot: Custom cursors


Source code

The software cursor

The first approach many people have when they want to use a custom cursor in their game is to place a sprite into a scene and then have it update its position to the mouse’s position each frame.

# Code for an example scene
extends Node2D

func _process(delta):
	$cursor.global_position = get_global_mouse_position()

The problem with this method is that this custom cursor will always be at least one frame behind where the mouse is, which can make the game feel sluggish and unresponsive, even at higher frame rates. The video below shows just how inaccurate this can be.

The hardware cursor

So how do we get a more responsive cursor? We can use a hardware cursor to tie our custom cursor directly to the mouse! And luckily for us, the developers of Godot have made it incredibly easy to do this. Just open your project settings and go to Display > Mouse Cursor. From here you can choose the image to use as your custom cursor. By default, Godot will match the top-left corner of the image to the mouse’s position, but if you need to align it with a different part of the image, say the middle of a crosshair graphic, you can adjust the offset, in pixels, in this window. In my example, my crosshair is a 32x32px image, so I set the offset to 16x16px so that the crosshair will be centered on the mouse.

Now, our custom cursor is fast, accurate, and responsive. I can’t show you the comparison to the native mouse cursor this way, but trust me, it feels a lot better than the software cursor.

Changing the cursor with code

But what if we want to change our cursor through code, such as showing different images in different contexts? Godot also provides an easy method for this using the Input.set_custom_mouse_cursor function. Using this function, we can change cursor images on the fly, or go back to using the system cursor if desired. As an example, the code below removes our custom cursor, by passing null as the image parameter, when the mouse moves to a position along the x-axis that is greater than or equal to 512, but adds it when the new position is less than that (also making sure to apply our offset). I’ve added a basic background to show when this should happen.

extends Node2D

var cursor = preload("res://cursor/cursor.png")

func _input(event):
	if event is InputEventMouseMotion:
		if get_global_mouse_position().x >= 512:
			Input.set_custom_mouse_cursor(null)
		else:
			Input.set_custom_mouse_cursor(cursor, Input.CURSOR_ARROW, Vector2(16, 16))

The first parameter is the image we want to use as our cursor. We can either pass an image to tell Godot to use that as our cursor, or pass null to tell Godot to go back to using the native system cursor. The second parameter of the function, Input.CURSOR_ARROW, is there to tell Godot that we want to use our graphic as the default cursor arrow. The final parameter is our custom cursor offset. Only the first parameter is required for this function. If unspecified, Godot will default to applying our custom cursor as the Input.CURSOR_ARROW shape with an offset of Vector2(0, 0).

Other cursor shapes

But if we have to tell Godot which cursor to change, that would imply that we can also use custom cursors for more than just the default cursor. So consider this next example, where I have a basic scene with a LineEdit inside of it. When the mouse enters a LineEdit, it changes to what’s called the IBeam shape. By using the same set_custom_mouse_cursor function, but changing our second parameter to Input.CURSOR_IBEAM, we can tell Godot to use a custom image when we mouse over editable text. So by using this technique and varying the cursor we want to override, we can use a completely custom set of cursors for all parts of our game!

extends Control

var cursor = preload("res://cursor/cursor.png")
var cursor_ibeam = preload("res://cursor/cursor_ibeam.png")

func _ready():
	Input.set_custom_mouse_cursor(cursor, Input.CURSOR_ARROW, Vector2(16, 16))
	Input.set_custom_mouse_cursor(cursor_ibeam, Input.CURSOR_IBEAM, Vector2(16, 16))

Conclusion

And that’s a look at custom cursors in Godot. There is a short page of official documentation if you’d like to know more, and you can find a list all of the cursor shapes you can customize here.