Custom cursor: image and hotspot
Configure a cursor slot, validate an image, and restore the system pointer.
For an ordinary pointer, change the system cursor through Input.SetCustomMouseCursor(). A sprite following the mouse remains a game object: it is drawn in game frames and does not become a system pointer.
Prepare the image
- Use a small transparent image, such as a 32×32 or 64×64 PNG; import losslessly and avoid VRAM compression.
- Set the hotspot: the image pixel representing the click point. Use an arrow tip or crosshair center.
- The shared implementation limits size to 256×256. This does not guarantee that size on every target platform; test exports and use the smallest necessary image.
- Keep the hotspot inside the image. For 32×32, valid integer coordinates are 0–31; (32, 0) is not an image pixel.
Complete installation/reset helper
This class owns one cursor slot: it creates a texture from a nonempty Image, checks size/hotspot, and installs the image. Dispose() resets that slot to its system appearance and releases the created texture.
using System;
using Reckfell;
public sealed class CursorTheme : IDisposable
{
private readonly ImageTexture _texture;
private readonly Input.CursorShape _shape;
private bool _disposed;
public CursorTheme(Image image, Vector2 hotspot, Input.CursorShape shape = Input.CursorShape.Arrow)
{
if (image is null || image.IsEmpty() || image.GetWidth() > 256 || image.GetHeight() > 256)
throw new ArgumentException("Cursor requires a nonempty image no larger than 256 by 256.", nameof(image));
if (!hotspot.IsFinite() || hotspot.X < 0 || hotspot.Y < 0 ||
hotspot.X >= image.GetWidth() || hotspot.Y >= image.GetHeight())
throw new ArgumentOutOfRangeException(nameof(hotspot));
if (shape < Input.CursorShape.Arrow || shape > Input.CursorShape.Help)
throw new ArgumentOutOfRangeException(nameof(shape));
_shape = shape;
_texture = ImageTexture.CreateFromImage(image);
Input.SetCustomMouseCursor(_texture, shape, hotspot);
}
public void Dispose()
{
if (_disposed) return;
Input.SetCustomMouseCursor(null!, _shape);
_texture.Dispose();
_disposed = true;
}
}Obtain an image from an imported texture with ResourceLoader.Load<Texture2D>(path).GetImage() and pass it to CursorTheme. Create the theme once when entering a UI context; keep it in a field and call Dispose() on exit. Do not apply a cursor every frame.
The reset's null! deliberately supplies an empty resource: the native API uses it to restore the system image. ! suppresses a C# nullable warning here; it does not create an object.
Resetting does not restore a previous custom theme. The example assumes one slot owner; when several screens change cursors, coordinate them through one service and explicitly retain the current theme.
Slot image and active shape are different settings
SetCustomMouseCursor replaces the selected Input.CursorShape image, defaulting to Arrow. Configuring Ibeam, for example, does not replace the arrow. SetDefaultCursorShape selects a default shape, but a UI control can request another shape.
If the cursor changes over a text field or button, check its slot and Control settings rather than reinstalling an image every frame. Setting an image does not make a hidden or captured cursor visible; see mouse coordinates.
Choose a configuration location
For one permanent theme, use project settings display/mouse_cursor/custom_image and display/mouse_cursor/custom_image_hotspot. Runtime installation serves changing game contexts. Do not use SetCustomMouseCursor to customize the editor's own cursor: native Input skips the call when Engine.IsEditorHint() is true.
Diagnose a wrong pointer
Click offset: inspect hotspot, not a world-object position. Black background: inspect image alpha and import. Correct arrow but old I-beam: only Arrow was configured. Another screen's theme disappears on exit: multiple owners reset one slot. No image in captured mode: inspect mouse mode.
Checks rejected empty/oversized images, invalid slots, and negative, edge, or nonfinite hotspots. RGBA installation and repeated reset executed through the Windows backend without errors. Cursor screenshots, appearance across DPI settings, GUI overrides, real clicks, and other platforms were not tested.