2

what I would like to achieve is having the cursor of my game stay in the the "gameplay" area of my window, so the user cannot move the cursor out of those bounds. I DO NOT want the cursor to stay in ONE position, I still want the user to be able to move his mouse around and click, I just want the mouse to be "encaged" in an area. Please see this demonstration:

Game screenshot for demonstration

I want the cursor to stay in the green box just outside the pink markers I made. So I heard that there was a way to achieve this by using the "Robot" in java or by setting the MouseGrabbed to true, but without finding adequate tutorials, all tests have failed.

I am quite new to Slick2D and java game development in general, so please be very specific and guide me through your ideas. Thanks in advance!

Nick DeFazio
  • 2,412
  • 27
  • 31
Plumetone
  • 101
  • 1
  • 9

1 Answers1

3

If I'm understanding you correctly you want the following:

  1. Have a cursor that is limited to the lower green box in your screenshot
  2. Still allow the native cursor to be usable(ungrabbed) when navigating outside of the game window (i.e users can click the x button and such)

I've achieved this before by rendering my own cursor and hiding the native one while in the game window. There's a few steps to accomplishing this. I should mention that this was done with a slightly older version than the current LWJGL offerings, and I'm not sure which version you are running.

Step 1: Disabling the native cursor

You want to disable the native cursor when inside your game window. Grabbing was too aggressive in my case since it disabled the mouse for a windowed game entirely. When initializing your game, try the following:

    try {
        final Cursor emptyCursor = new Cursor(1, 1, 0, 0, 1, BufferUtils.createIntBuffer(1), null);
        Mouse.setNativeCursor(emptyCursor);
    } catch (final LWJGLException e) {
        //TODO: Consider better exception handling
        e.printStackTrace();
    }

What this does is render the native mouse as nothing while in your game window. This means the arrow you normally see will disappear when you mouse over your game. This does NOT mean that the mouse is not functional, we have just hidden it.

Step 2: Track mouse movement when gathering keyboard/mouse input

public void collectInput() {
    while(Mouse.next()){
        this.mouseX = Mouse.getX();
        final int newMousePosition = Mouse.getY();

        //Only move the cursor on the Y axis if it is between the upper and lower bounds
        if(newMousePosition < this.upperBound && newMousePosition > this.lowerBound){
            this.mouseY = newMousePosition;
        }
        this.mouseY = Display.getHeight()- Mouse.getY();
        //TODO: Consider adding logging here
    }
}

I had a collectInput() method that would grab keypresses/mouse events I thought were necessary. All I'm doing here is grabbing the current X/Y of the mouse in my game window. The Y coordinate is subtracted from the total display height to deal with render coordinates vs mouse coordinates later on. In my case I just used the bounds of my entire window, but you may want to consider not updating X/Y coordinates if they go outside of your green box.

EDIT Based on your comment, I updated the code block here to not update the Y coordinate if the new coordinate is not within some boundaries. You will want to determine what your x and y boundaries are, and only update your mouse X/Y coordinates if the new coordinates gathered from the Mouse class lie within them.

Step 3: Render your own cursor

Finally, you will want to render your cursor. This looks like any other render you would do with LWJGL. My example assumes you have a texture for this:

//Render mouse texture
    Color.white.bind();
    this.mouseTexture.bind();
    GL11.glEnable(GL11.GL_TEXTURE_2D);
    GL11.glBegin(GL11.GL_QUADS);
    GL11.glTexCoord2f(0, 0);
    GL11.glVertex2f(this.mouseX, this.mouseY);
    GL11.glTexCoord2f(1, 0);
    GL11.glVertex2f(this.mouseX + this.cursorHeight, this.mouseY);
    GL11.glTexCoord2f(1, 1);
    GL11.glVertex2f(this.mouseX + this.cursorHeight, this.mouseY + this.cursorWidth);
    GL11.glTexCoord2f(0, 1);
    GL11.glVertex2f(this.mouseX, this.mouseY + this.cursorWidth);
    GL11.glEnd();
    GL11.glDisable(GL11.GL_TEXTURE_2D);

What this results in is that when I am using the mouse in the game window, my custom cursor is rendered. It's hard to tell from the image, but the white circle is now my cursor, and it moves wherever I move the mouse. It's important to note here that the regular native cursor is not being shown due to step 1: Controlling the mouse in the window

But when I leave the game window, the native mouse is shown, and my custom cursor is left in the last place it received input: enter image description here

Nick DeFazio
  • 2,412
  • 27
  • 31
  • Dang, thanks so much for your thorough answer. I took example from your idea and transformed it to suit my needs. So what I did was grab a 32x32 cursor from the web, load that in my program with Slick2D, grab the mouse so it disappears and have the cursor image tied to the mouse coordinates with `Mouse.getX();` and so on. So now, the cursor is my "mouse" and it never leaves the window since it's an image. The question I have now is: How do I have the cursor image not go beyond the lower green rectangle? Because it can go past the green upper green strip with the hearts etc. which is a nono. – Plumetone Oct 24 '15 at 20:59
  • Added to the answer to show how to do this. You just need to establish some boundaries and check for them when updating your x/y coordinates. If the position the mouse if moving to is outside of your boundaries (the green box in your case) do not reassign mouseX and/or mouseY. – Nick DeFazio Oct 24 '15 at 21:25
  • Thanks so much! So where would I place your block in Step 2, in my Slick2D gameplay state? (init? render? update?) And last question, a bit off topic, but would you know how to toggle the mouse directions to be inverted? As in, if the user moves the mouse to the left, the cursor goes to the right, if he moves it up, the cursor goes down etc. If you can't answer it's fine! But this is my ultimate goal and I'm trying to gather as much information. – Plumetone Oct 24 '15 at 21:38
  • Hard to say without seeing any code, but chances are it's in your gameplay state class. I'm assuming that's where you are gathering mouse/keyboard input. Not sure about the other part though. – Nick DeFazio Oct 24 '15 at 21:43