Custom Mouse Cursor

Hi there.

I’m developing a RTS game and right now I wanted to change the cursor

Here’s the bit of code I have:

JmeCursor x = (JmeCursor) assetManager.loadAsset("Interface/Mouse/mouse1.ico");
        inputManager.setMouseCursor(x);

I can get it showing without any problem.

But the cursor is too small, want to resize it a bit,

I’ve tryed with the following code, but It gives me the following error:

x.setHeight(64);
        x.setWidth(64);
        x.setNumImages(1);
        x.setyHotSpot(64- 3);
        x.setxHotSpot(3);

Any idea? Any Better solution than this? I want static cursors.

Seen some other posts on foruns, but everything is too complicated to implement, want something simple.

I guess that you need to have 64x64 pixel image.

Tryed now with a 64x64 ico, same error.

What about the following ?

        final Texture cursorTexture = assetManager.loadTexture("/path/to/any/cursor.png");
        final Image image = cursorTexture.getImage();

        final ByteBuffer imgByteBuff = (ByteBuffer) image.getData(0).rewind();
        final IntBuffer curIntBuff = BufferUtils.createIntBuffer(image.getHeight() * image.getWidth());

        while (imgByteBuff.hasRemaining()) {
            int rgba = imgByteBuff.getInt();
            int argb = ((rgba & 255) << 24) | (rgba >> 8);
            curIntBuff.put(argb);
        }

        final JmeCursor c = new JmeCursor();
        c.setHeight(image.getHeight());
        c.setWidth(image.getWidth());
        c.setNumImages(1);
        c.setyHotSpot(0);
        c.setxHotSpot(0);
        c.setImagesData((IntBuffer) curIntBuff.rewind());
        inputManager.setMouseCursor(c);

Instead of using JmeCursor, just make a Picture object with your cursor, attach it to the guiNode and in the simpleUpdate update its position according with the mouse position.

@Override
public void simpleUpdate(float tpf) {
    Vector2f pos=getInputManager().getCursorPosition();
    CURSOR.setLocalTranslation(pos.x,pos.y-CURSOR_HEIGHT,Float.MAX_VALUE);
}

I’m not sure if this solution is good. This way the cursor is dependent on the fps rate, even with 60fps it is not so smooth like system’s cursor, there is always a small lag.

Here is how the JME-JFX bridge changes jme cursors:

The reason this stuff is so complicated is, that it is actually converting the cursors to a bytebuffer the different OS do understand and can use in their own cursor system.

Unless you have less than 30 fps is not really noticeable, and a game that runs at 30 fps is already quite unplayable.
The pros are that is really easy to do, you can use the image and resolution you want and you are sure that it will work in the same way in all platforms.

It is noticeable, I notice this even at 144hz.
Most people wont mind however. (I fucking hate it)
And especially strategy games are quite playable down to 15fps if the cursor is hardware.

With .png, the mouse appears all buggy (white square, image all broken).

With .ico it doesnt work

Going to try this one. I’ll Give a feedback later on

This code converts 50x50 texture image to JmeCursor. The code is dirty, was written in hurry and, like every code that is not important and is working, was left without cleaning.
Maybe you can use it.

public static JmeCursor textureToCursor(Texture tex)
{
    Image image = tex.getImage();
    ByteBuffer imgByteBuff = (ByteBuffer) image.getData(0).rewind();
    IntBuffer curIntBuff = BufferUtils.createIntBuffer(50 * 50);
    
    for (int y = 0; y < 50; y++) //image.getHeight()
    {
        if (y >= image.getHeight())
        {
            for (int i = 0; i < image.getWidth(); i++)
            {
                curIntBuff.put(0xff000000);
            }
            continue;
        }
        
        for (int x = 0; x < image.getWidth(); x++)
        {
            int rgba = imgByteBuff.getInt();
            if (x >= 48) continue;
            
             int argb = ((rgba & 255) << 24) | (rgba >> 8);
             curIntBuff.put(argb);
        }
    }

    JmeCursor c = new JmeCursor();
    c.setHeight(image.getHeight()); //image.getHeight()-2);
    c.setWidth(48); //image.getWidth());
    c.setNumImages(1);
    c.setyHotSpot(50 - 3); //image.getHeight()-3);
    c.setxHotSpot(3);
    c.setImagesData((IntBuffer) curIntBuff.rewind());
    
    return c;
}
1 Like

cur and ani files work best from my knowledge.

Heheh… amen to that. Even better if you leave a FIXME comment with something along the lines of “Address this when we are rich and on a beach somewhere but feeling nostalgic about what our old code was like…”

Years ago my programming guru told me: if something is working and don’t need do be upgraded or extended - don’t touch it.

Indeed… though I’m likely to put more time into shoring up core code than ancillary code. I want the foundation of my house to be rock solid but I don’t care as much about the sand under the paving stones for my walkway.

Thus on a rapidly developed project, you can often distinguish how close to core you are by how well written and maintained the code is. Which for me instantly translates into sloppy = unimportant which could explain many fundamental clashes I’ve had with team mates who saw formatting as unimportant. :slight_smile:

It is exactly like you told, beside that the Dungeon Game is not rapidly developed… Mouse cursor is an example, there are many, many other things written like that, especially small utility functions or code that is executed once. “It’s done, it’s working, forget about it, let’s do something important” :wink: The core? Oh, it’s never done for 100%.
And it is exactly the same with projects I’m doing at work.

The funny thing is that the more experienced you are, the more comfortable such way of programming is for you. On some forum I had an argument with some young student. He used to write everything like it would be shown in books. Every line of his code was a tribute to purity and ‘clean way of programming’. Every class, function used hundreds of design patterns, there were no unnecessary line…

I guess that he must be proud of it. What a waste of time :wink:

Reminds me of folks who write unit tests for prototype code we already know won’t live past next week… :slight_smile:

It still gives me an error:

“java.lang.IllegalArgumentException: Number of remaining buffer elements is 2500, must be at least 4032. Because at most 4032 elements can be returned, a buffer with at least 4032 elements is required, regardless of actual returned element count”.

final Texture cursorTexture = assetManager.loadTexture("Interface/Cursors/mouse1.png");
inputManager.setMouseCursor(textureToCursor(cursorTexture));

It gives me an error on the inputManager line.

I had problems in Windows, certain cursor sizes just broke the damn thing. Too big that is, but this in general I managed to get to work. Here, I hope this helps: