Hot questions for Using Lightweight Java Game Library in mouse

Question:

I want to implement a FPS style mouse look in my lwjgl3 java application, but since there isn't any Mouse.getDX() or Mouse.getDY(), I'm looking for a different approach using the glfw bindings. I wrote this method that gets called in my update() method:

public double[] pollMouseDelta() {
    DoubleBuffer x = BufferUtils.createDoubleBuffer(1);
    DoubleBuffer y = BufferUtils.createDoubleBuffer(1);

    glfwGetCursorPos(WINDOW, x, y);
    x.rewind();
    y.rewind();

    double tempX = mouseX;
    double tempY = mouseY;

    mouseX = x.get();
    mouseY = y.get();

    return new double[] {
           mouseX - tempX,
           mouseY - tempY
    };
}

where mouseX and mouseY are global variables. In my update method I do the following:

double[] mouseDelta = pollMouseDelta();

camera.rotate(Camera.Direction.LEFT_RIGHT, (float) (0.2f * -mouseDelta[0]));
camera.rotate(Camera.Direction.UP_DOWN, (float) (0.2f * mouseDelta[1]));

camera.update();

I also set the GLFW_CURSOR mode to GLFW_CURSOR_DISABLED. But the camera is stuttering and making big jumps. Also, sometimes the mouse seems to be inverted.

Any suggestions?


Answer:

Here is a code snippet of with the basis for my FPS style camera. As you can see I am calculating the delta of the mouse position with the center of the screen along the X and Y axis.

You can see in my System.out.println calls the values I am calculating for deltas and the fact that it should be rotating by this amount. I then multiply these values by my sensitivity and rotate the camera by this amount.

import org.lwjgl.BufferUtils;
import org.lwjgl.Sys;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;

import java.nio.ByteBuffer;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;

import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.glfw.GLFW.glfwGetCursorPos;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.system.MemoryUtil.*;

public class Main {

    // We need to strongly reference callback instances.
    private GLFWErrorCallback errorCallback;
    private GLFWKeyCallback   keyCallback;

    // The window handle
    private long window;

    public void run() {
        System.out.println("Hello LWJGL " + Sys.getVersion() + "!");

        try {
            init();
            loop();

            // Release window and window callbacks
            glfwDestroyWindow(window);
            keyCallback.release();
        } finally {
            // Terminate GLFW and release the GLFWerrorfun
            glfwTerminate();
            errorCallback.release();
        }
    }

    private void init() {
        // Setup an error callback. The default implementation
        // will print the error message in System.err.
        glfwSetErrorCallback(errorCallback = errorCallbackPrint(System.err));

        // Initialize GLFW. Most GLFW functions will not work before doing this.
        if ( glfwInit() != GL11.GL_TRUE )
            throw new IllegalStateException("Unable to initialize GLFW");

        // Configure our window
        glfwDefaultWindowHints(); // optional, the current window hints are already the default
        glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // the window will stay hidden after creation
        glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // the window will be resizable
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);


        int WIDTH = 800;
        int HEIGHT = 600;

        // Create the window
        window = glfwCreateWindow(WIDTH, HEIGHT, "Hello World!", NULL, NULL);
        if ( window == NULL )
            throw new RuntimeException("Failed to create the GLFW window");

        // Setup a key callback. It will be called every time a key is pressed, repeated or released.
        glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {
            @Override
            public void invoke(long window, int key, int scancode, int action, int mods) {
                if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
                    glfwSetWindowShouldClose(window, GL_TRUE); // We will detect this in our rendering loop
            }
        });

        // Get the resolution of the primary monitor
        ByteBuffer vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
        // Center our window
        glfwSetWindowPos(
                window,
                (GLFWvidmode.width(vidmode) - WIDTH) / 2,
                (GLFWvidmode.height(vidmode) - HEIGHT) / 2
        );

        // Make the OpenGL context current
        glfwMakeContextCurrent(window);
        // Enable v-sync
        glfwSwapInterval(1);

        // Make the window visible
        glfwShowWindow(window);
    }

    private void loop() {
        // This line is critical for LWJGL's interoperation with GLFW's
        // This line is critical for LWJGL's interoperation with GLFW's
        // OpenGL context, or any context that is managed externally.
        // LWJGL detects the context that is current in the current thread,
        // creates the ContextCapabilities instance and makes the OpenGL
        // bindings available for use.
        GLContext.createFromCurrent();


        // Create a FloatBuffer to hold our vertex data
        FloatBuffer vertices = BufferUtils.createFloatBuffer(9);
        // Add vertices of the triangle
        vertices.put(new float[]
                {
                        0.0f,  0.5f,  0.0f,
                        0.5f, -0.5f,  0.0f,
                        -0.5f, -0.5f,  0.0f
                });
        // Rewind the vertices
        vertices.rewind();


        int vbo = glGenBuffers();
        int vao = glGenVertexArrays();

        glBindBuffer (GL_ARRAY_BUFFER, vbo);
        glBufferData (GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW);
        glBindVertexArray(vao);

        glEnableVertexAttribArray (0);
        glBindBuffer (GL_ARRAY_BUFFER, vbo);
        glVertexAttribPointer (0, 3, GL_FLOAT, false, 0, 0);

        final String vertex_shader =
                "#version 410\n" +
                        "in vec3 vp;\n" +
                        "void main () {\n" +
                        "  gl_Position = vec4 (vp, 1.0);\n" +
                        "}";

        final String frag_shader =
                "#version 400\n"    +
                        "out vec4 frag_colour;" +
                        "void main () {"         +
                        "  frag_colour = vec4 (0.5, 0.0, 0.5, 1.0);" +
                        "}";

        int shader_programme = glCreateProgram();


        int vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertexShaderID, vertex_shader);
        glCompileShader (vertexShaderID);

        if(glGetShaderi(vertexShaderID, GL_COMPILE_STATUS) == 0){
            System.err.println(glGetShaderInfoLog(vertexShaderID, 1024));
            System.exit(1);
        }

        glAttachShader (shader_programme, vertexShaderID);

        int fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragmentShaderID, frag_shader);
        glCompileShader (fragmentShaderID);

        if(glGetShaderi(fragmentShaderID, GL_COMPILE_STATUS) == 0){
            System.err.println(glGetShaderInfoLog(fragmentShaderID, 1024));
            System.exit(1);
        }

        glAttachShader (shader_programme, fragmentShaderID);

        glLinkProgram (shader_programme);

        if(glGetProgrami(shader_programme, GL_LINK_STATUS) == 0){
            System.err.println(glGetProgramInfoLog(shader_programme, 1024));
            System.exit(1);
        }

        glValidateProgram(shader_programme);

        if(glGetProgrami(shader_programme, GL_VALIDATE_STATUS) == 0){
            System.err.println(glGetProgramInfoLog(shader_programme, 1024));
            System.exit(1);
        }

        boolean mouseLocked = false;
        double newX = 400;
        double newY = 300;

        double prevX = 0;
        double prevY = 0;

        boolean rotX = false;
        boolean rotY = false;

        glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);


        while ( glfwWindowShouldClose(window) == GL_FALSE ) {

            if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1) == GLFW_PRESS) {
                glfwSetCursorPos(window, 800/2, 600/2);

                mouseLocked = true;
            }

            if (mouseLocked){
                DoubleBuffer x = BufferUtils.createDoubleBuffer(1);
                DoubleBuffer y = BufferUtils.createDoubleBuffer(1);

                glfwGetCursorPos(window, x, y);
                x.rewind();
                y.rewind();

                newX = x.get();
                newY = y.get();

                double deltaX = newX - 400;
                double deltaY = newY - 300;

                rotX = newX != prevX;
                rotY = newY != prevY;

                if(rotY) {
                    System.out.println("ROTATE Y AXIS: " + deltaY);

                }
                if(rotX) {
                    System.out.println("ROTATE X AXIS: " + deltaX);
                }

                prevX = newX;
                prevY = newY;


                System.out.println("Delta X = " + deltaX + " Delta Y = " + deltaY);

                glfwSetCursorPos(window, 800/2, 600/2);
            }

            // wipe the drawing surface clear
            glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glUseProgram (shader_programme);
            glBindVertexArray (vao);
            // draw points 0-3 from the currently bound VAO with current in-use shader
            glDrawArrays (GL_TRIANGLES, 0, 3);
            // update other events like input handling
            glfwPollEvents ();
            // put the stuff we've been drawing onto the display
            glfwSwapBuffers (window);

        }
    }

    public static void main(String[] args) {
        new Main().run();
    }

}

Question:

I am having trouble finishing my mouse ray picking algorithm for a game I am creating using java (and opengl/lwjgl). I implemented ray tracing using inspiration from here and here. I followed a lwjgl book for the implementation of the game. The following code is the mouse ray picking algorithm:

// Calculate the normalized device coordinates
Vector2d mouseCoords = mouseInput.getPositionVector();
mouseCoords.mul((float)2 / window.width(), (float)2 / window.height());           
Vector4f mouseNDS = new Vector4f((float)mouseCoords.x, (float)mouseCoords.y, -1f, 1f);     

// Calculate the ray in cam space 
Vector4f eyeRay = mouseNDS.mul(renderer.getTransformations().getProjectionMatrix().invert());
eyeRay = new Vector4f(eyeRay.x, eyeRay.y, eyeRay.z, 0f);

// Calculate the ray in world space
Vector4f worldRay4f = eyeRay.mul(renderer.getTransformations().getViewMatrix(camera).invert());
Vector3f worldRay = new Vector3f(worldRay4f.x, worldRay4f.y, -worldRay4f.z).normalize();    

Eventually, I want to intersect it with the ground plane (y = 0). This is my code for this:

float lambda = camera.getPos().dot(new Vector3f(0, 1f , 0)) / worldRay.dot(new Vector3f(0, 1f, 0));      

Vector3f ray_scaled = worldRay.mul(lambda);
Vector3f ground_vec = new Vector3f();
camera.getPos().sub(ray_scaled, ground_vec);

This code works only if the camera is pointing in the negative y direction (i.e. directly down), and keeps working when I apply a position change. However, if I rotate the camera, the code breaks, i.e. the ground vector does not end under the mouse position anymore.

I suspect something is wrong with the inversion of the viewMatrix of the camera. The viewMatrix is calculated by this code:

public Matrix4f getViewMatrix(Camera camera) {
        Vector3f cameraPos = camera.getPos();
        Vector3f rotation = camera.getRot();

        viewMatrix.identity();
        viewMatrix.rotate((float)Math.toRadians(rotation.x), new Vector3f(1, 0, 0))
                  .rotate((float)Math.toRadians(rotation.y), new Vector3f(0, 1, 0))
                  .rotate((float)Math.toRadians(rotation.z), new Vector3f(0, 0, 1));
        viewMatrix.translate(-cameraPos.x, -cameraPos.y, -cameraPos.z);
        return viewMatrix;
}

Can anyone point me in the right direction?


Answer:

There is an issue when you set the world ray (worldRay). The z component has not to be inverted:

Vector3f worldRay = new Vector3f(worldRay4f.x, worldRay4f.y, -worldRay4f.z).normalize();

Vector3f worldRay = new Vector3f(worldRay4f.x, worldRay4f.y, worldRay4f.z).normalize();   

If the camera points in the negative y direction, then the x and z component of worldRay4f is 0.0 and the error is not noticeable.


The origin of the window coordinates is at the top left. In normalized device space the top left is (-1, 1) and the bottom left is (-1, -1). So the y coordinate has to be flipped when transforming the mouse coordinate to normalized device space:

Vector2d mouseCoords = mouseInput.getPositionVector();
Vector4f mouseNDS = new Vector4f(
    (float)mouseCoords.x * 2f / window.width() - 1f,
    1f - (float)mouseCoords.y * 2f / window.height(),
    -1f, 1f);   

Question:

I am making a 3D game and I have just got the ability to allow the mouse to move the camera and then put the mouse back to the centre. But I want don't want the user to see an annoying mouse at the centre of the screen! So what I'm asking is: how do I make the mouse invisible? / how do I make the cursor disappear? I thought that there would be a Mouse.setVisible(false); but doesn't seem to exist. Thanks in advance. Also I want to do it without making a blank image. I'm using LWJGL 2 for java


Answer:

You can do it with LWJGL 3 as follows:

To hide the cursor but make it able to leave the window:

glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);

To keep it in the window as well, similar to LWJGL 2's grabbed mode:

glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

To revert its state back to normal:

glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);

Question:

I am wondering what is a good approach on "unlimited mouse movement"? (Like in first person games where you can look around infinitely)

I am using OpenGL and LWJGL (which provides bindings for Java). I have the following possible bindings: https://www.lwjgl.org/customize (listed under contents) Currently I am only using GLFW to handle the mouse input.

My current approach is the following, but obviously the cursor eventually reaches the screen edge:

public class MouseInput {

    private final Vector2d previousPosition;
    private final Vector2d currentPosition;

    private final Vector2f displayVector;

    private boolean inWindow = false;

    // [some code here]

    public void init() {

        glfwSetCursorPosCallback(window.getHandle(), (windowHandle, xpos, ypos) -> {
            currentPosition.x = xpos;
            currentPosition.y = ypos;
        });

        glfwSetCursorEnterCallback(window.getHandle(), (windowHandle, entered) -> {
            inWindow = entered;
        });

        // [some code here]

    }

    public void input() {

        displayVector.x = 0;
        displayVector.y = 0;

        if (previousPosition.x > 0 && previousPosition.y > 0 && inWindow) {

            double deltaX = currentPosition.x - previousPosition.x;
            double deltaY = currentPosition.y - previousPosition.y;

            if (deltaX != 0) {
                displayVector.y = (float) deltaX;
            }
            if (deltaY != 0) {
                displayVector.x = (float) deltaY;
            }

        }

        previousPosition.x = currentPosition.x;
        previousPosition.y = currentPosition.y;

    }

    // [some code here]

}

Now I can use the calculated displayVector somewhere else to rotate the camera.

Do I have to use something different than GLFW? I tried setting the position of the cursor back to the center after every input(), but that was very glitchy.

I am not looking for a correction of my code, but for a good approach which is the best practice.


Answer:

glfwSetInputMode():

  • GLFW_CURSOR_DISABLED hides and grabs the cursor, providing virtual and unlimited cursor movement. This is useful for implementing for example 3D camera controls.

Question:

I am trying to implement a zoom to an isometric map using LWJGL. Currently I have the functions

public static void setCameraPosition(float x, float y) {

    x *= zoom;
    y *= zoom;

    cameraX = x;
    cameraY = y;

    x -= (Display.getWidth() / 2) * zoom;
    y -= (Display.getHeight() / 2) * zoom;

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    GLU.gluLookAt(x, y, 1f, x, y, 0, 0.0f, 1.0f, 0.0f);
}   

which sets the camera center to a point (x, y),

public static Point getMouseCoordinates() {
    float x = Mouse.getX() * getZoom() + getCameraLeft();
    float y = (Display.getHeight() - Mouse.getY()) * getZoom() + getCameraTop();
    return new Point((int) x, (int) y);
}

which returns the current mouse coordinates, and

public static void setZoom(int newZoom) {

    if (newZoom >= 4) newZoom = 4;
    else if (newZoom <= 1) newZoom = 1;

    if (zoom == newZoom) return;

    float x = ?; <-----
    float y = ?; <-----

    zoom = newZoom;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0,  0+Display.getWidth() * zoom , 0+Display.getHeight() * zoom, 0, 1, -1);
    setCameraPosition((int) x, (int) y);
}

which is supposed to set the zoom to an integer value between 1 and 4. As you can see, I would like to set the camera position after changing the zoom to a certain point - and that point needs to be calculated so that the current mouse position does not change (aka zooming in to the mouse position, which is for example what Google Maps does). I have been trying for a good 2 days now, I've tried so many things, but I just couldn't figure out the equation to calculate x and y.

Please note that all points returned and entered are relative to the position of the map, specifically to the top piece of the map (whose top corner point is (0, 0)). The values getCameraLeft() and getCameraTop() in the getMouseCoordinates() function return

public static float getCameraLeft() {
    return cameraX - zoom * (Display.getWidth() / 2);
}

and

public static float getCameraTop() {
    return cameraY - zoom * (Display.getHeight() / 2);
}

.

Any help would be appreciated. I'm hoping, I did not express myself too complicated.


Answer:

I finally found the correct equation:

        float x = getMouseCoordinates().getX() + (getCameraX() - getMouseCoordinates().getX()) * (float) newZoom / (float) zoom;
        float y = getMouseCoordinates().getY() + (getCameraY() - getMouseCoordinates().getY()) * (float) newZoom / (float) zoom;

Thank you anyways, I'm sure eventually someone would have given me the correct answer :)

Question:

I'm making a 3D game engine, and i've made my own way of handing events fired and passing them to each GuiComponent until its either returned true (handled), or it gets through them all, in which case it disposes the event.

The issue is, the events are firing more than one. I have made sure i'm not creating multiple instances of the eventHandler class. I though perhaps the Mouse class in LWJGL fires multiple times? If not, what is wring with the current setup? Thanks

EventHandler:

public abstract interface EventHandler {
    public abstract boolean handleEvent(Event event);
}

Event:

public class Event {

    public enum events {
        MOUSEPRESSED, MOUSEDRAGGED, MOUSEMOVED
    }

    private events event;

    public float x, y;

    public Event(events event, float x, float y) {
        this.x = x;
        this.y = DisplayManager.HEIGHT - y;
        this.event = event;
    }

    public Event setPos(float x, float y) {
        this.x = x;
        this.y = DisplayManager.HEIGHT - y;
        return this;
    }

    public void setEvent(events event) {
        this.event = event;
    }

    public boolean equals(events event) {
        return event.equals(this.event);
    }
}

GuiButton:

public class GuiButton extends GuiComponent implements EventHandler {

    @Override
    public boolean passEvent(Event event) {
        if (!visible) return false;
        if (event.equals(Event.events.MOUSEPRESSED) && super.passEvent(event)) {
            texture = texture2;
            return handleEvent(event);
        } else texture = texture1;
        return false;
    }

    @Override
    public boolean handleEvent(Event event) {
        return false;
    }
}

GuiPanel:

public class GuiPanel extends GuiComponent {

    protected List<GuiComponent> components = new ArrayList<GuiComponent>();

    @Override
    public boolean passEvent(Event event) {
        for (GuiComponent c : components) {
            if (c.passEvent(event)) return true;
        }
        return false;
    }

    @Override
    public void setVisible(boolean visible) {
        super.setVisible(visible);
        for (GuiComponent c : components) c.setVisible(visible);
    }

    @Override
    public void update() {
        for (GuiComponent c : components) {
            if (c.isVisible()) c.update();
        }
    }

GuiComponent:

public abstract class GuiComponent extends Rectangle {

    public void setVisible(boolean visible) {
        this.visible = visible;
    }

    public boolean isVisible() {
        return visible;
    }

    public boolean passEvent(Event event) {
        if (this.contains(event.x, event.y)) return true;
        return false;
    }

    public abstract void update();
}

Component creation:

    main = new GuiPanel(0, 0, 100, DisplayManager.HEIGHT, "null", loader);
    guiCompoents.add(main);

    entityPanel = new GuiPanel(30, 100, 100, 300, "null", loader);

    b2 = new GuiButton(100, 100, 100, 30, "Entitiesn", "Entitiesh2", loader) {
        public boolean handleEvent(Event event) {
            if (event.equals(Event.events.MOUSEPRESSED)) {
                System.out.println("button2 recieved event");
                createEntity(tree1);
                return true;
            }
            return false;
        }
    };
    entityPanel.add(b2);
    entityPanel.setVisible(false);

    b1 = new GuiButton(30, 100, 100, 30, "Entitiesn", "Entitiess", loader) {
        public boolean handleEvent(Event event) {
            if (event.equals(Event.events.MOUSEPRESSED)) {
                System.out.println("button1 recieved event");
                entityPanel.setVisible(!entityPanel.isVisible());
                return true;
            }
            return false;
        }
    };
    main.add(b1);

    main.add(entityPanel);

EDIT: Okay, upon further searching, I tried the following where i'm detecting events firing:

if (Mouse.getDX() != 0 || Mouse.getDY() != 0) {
        event.setEvent(Event.events.MOUSEMOVED);
        event.setPos(Mouse.getX(), Mouse.getY());
        passEvent(event);
    }

And the event is fired multiple times. The Mouse class is inbuilt into LWJGL, so this seems to be the problem. Is there a way to fix this?


Answer:

Okay, so after searching around, I came across this thread here, which fixes the issue. I'm not entirely sure why, I shall take a look at the documentation for the Mouse class, but this seems to work and only fires the event once, and it gives me a released event, which is awesome. Hope this helps someone else in the future! There was nothing about this issue specifically anywhere on the internet.

Question:

Hello I am making a 3D game and now that I've started making something that lets the user interact with a mouse I have been a little stuck (well really stuck). What I'm trying to do is when the user moves the mouse it gets moved back to the centre (or were the coordinates I entered are) without effecting the Mouse.getDX() and Mouse.getDY(). Here is my code for the part were I test for moving the mouse.

    public void onMouser(){
    yaw+=Mouse.getDX();
    pitch-=Mouse.getDY();

    Mouse.setCursorPosition(750, 500);
}

Thanks in Advance


Answer:

public void calculatePitchAndYaw() {
    pitch += Mouse.getY() - HEIGHT /2;
    yaw += Mouse.getX - WIDTH / 2;
    Mouse.setCursorPosition(WIDTH / 2, HEIGHT /2);
}

Try something like this. So you wont turn back to your initial position.

Question:

I'm using java and LWJGL. I created a mouse listener for a canvas, but when I set the Displays parent to the canvas it doesn't work.

The mousehandlerClass:

private static class handlerClass implements MouseListener {
    public handlerClass() {
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        System.out.println("Canvas clicked");
    }

    @Override
    public void mousePressed(MouseEvent e) {

    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }
}

Here is where I set the canvas as parent in my DisplayManager class:

public void createDisplayJFrame(Canvas canvas) {
    ContextAttribs attribs = new ContextAttribs(3, 2).withForwardCompatible(true).withProfileCore(true);
    try {
        Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
        Display.setParent(canvas);
        Display.create(new PixelFormat(), attribs);

    } catch (LWJGLException ex) {
        //System.out.println(ex);
    }
    GL11.glViewport(0, 0, WIDTH, HEIGHT);
    lastFrameTime = getCurrentTime();
}

Here is where I add the MouseListener:

public class UIMain extends javax.swing.JFrame {

/**
 * Creates new form UIMain
 */
private static Canvas canvas;
public static DisplayThread dt;
HandlerClass handler = new HandlerClass();

public UIMain() {
    initComponents();
    canvas = new Canvas();
    canvas.addMouseListener(handler);
    canvas.setSize(500, 500);
    canvas.setBackground(Color.WHITE);
    canvas.isDisplayable();
    canvas.setVisible(true);
    jPanel2.add(canvas, BorderLayout.CENTER);
}

My DisplayThreadClass:

public class DisplayThread extends Thread {

private Canvas canvas;
ArrayList<Entity> entities = new ArrayList();

public DisplayThread(Canvas canvas) {
    this.canvas = canvas;
}

public void run() {
    new DisplayManager().createDisplayJFrame(canvas);
    //Created entities and added to entities
    ......
    MasterRenderer renderer = new MasterRenderer();
    while (!Display.isCloseRequested()) {
        DisplayManager.updateDisplay();
        //Here is the solution   if(org.lwjgl.input.Mouse.isButtonDown(org.lwjgl.input.Mouse.getEventButton())){
            System.out.println("Mouse was clicked");
        }
    }
    renderer.cleanUp();
    DisplayManager.closeDisplay();
}

When the canvas is not set as the parent (Nothing on the canvas) then the mouseListener works. But when the displays parent is set to the canvas. It does nothing. How can I determine when the mouse is clicked on the canvas when the canvas is set as parent?


Answer:

Although the actual issue may be resolved: This is probably related to some "magic" that is done in LWJGL, and may be related to LWJGL Display mounted on Canvas fails to generate Mouse Events - so if you used a Frame instead of a JFrame, it should already work.

However, if you want to use swing, and add a real MouseListener to the canvas, you can consider using an LWJGL AWTGLCanvas:

import static org.lwjgl.opengl.GL11.*;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.AWTGLCanvas;
import org.lwjgl.util.glu.GLU;

public class LwjglCanvasMouseEvents
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        LwjglCanvas canvas = null;
        try
        {
            canvas = new LwjglCanvas();
        }
        catch (LWJGLException e)
        {
            e.printStackTrace();
        }
        canvas.addMouseListener(new MouseAdapter()
        {
            @Override
            public void mousePressed(MouseEvent e)
            {
                System.out.println(e);
            }
        });
        f.getContentPane().add(canvas);
        f.setSize(400, 400);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

}

class LwjglCanvas extends AWTGLCanvas
{
    private int currentWidth;
    private int currentHeight;

    public LwjglCanvas() throws LWJGLException
    {
        super();
    }

    @Override
    public void paintGL()
    {
        if (getWidth() != currentWidth || getHeight() != currentHeight)
        {
            currentWidth = getWidth();
            currentHeight = getHeight();
            glViewport(0, 0, currentWidth, currentHeight);
        }
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        GLU.gluOrtho2D(0.0f, currentWidth, 0.0f, currentHeight);

        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();

        glBegin(GL_TRIANGLES);
        glColor3f(1.0f, 0.0f, 0.0f);
        glVertex3f(0, 0, 0);
        glColor3f(0.0f, 1.0f, 0.0f);
        glVertex3f(200, 0, 0);
        glColor3f(0.0f, 0.0f, 1.0f);
        glVertex3f(100, 200, 0);
        glEnd();

        glPopMatrix();
        try
        {
            swapBuffers();
        }
        catch (LWJGLException e)
        {
            e.printStackTrace();
        }
        repaint();
    }
}

Question:

When I shoot in the position the character starts at the bullet goes in the right direction. But if I move to a different position the bullet does not go in the right direction. To clarify things mx is mouse x position, my is mouse y position, px is player x position, and py is player y position.

package Player;

import java.io.IOException;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import org.newdawn.slick.Color;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
import org.newdawn.slick.util.ResourceLoader;

import Game.Main;

public class Bullet {
public double x = 0, y = 0;
public double sx, sy;
public Texture texture;

public Bullet(double mx, double my, double px, double py){
    sx = mx-px;
    sy = py-my;
    x = px;
    y = py;
    sx = sx/Math.sqrt((mx-x)*(mx-x) + (my-y)*(my-y));
    sy = sy/Math.sqrt((mx-x)*(mx-x) + (my-y)*(my-y));



}
public void logic(){
    renderBullet();

     x+=sx * 8;
     y+=sy * 8;






}

public void renderBullet(){
    try {
        texture = TextureLoader.getTexture("PNG", ResourceLoader.getResourceAsStream("res/image.png"));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    Color.white.bind();
    texture.bind(); // or GL11.glBind(texture.getTextureID());
       GL11.glBegin(GL11.GL_QUADS); 

       GL11.glTexCoord2f(0,0);
        GL11.glVertex2d(x,y);
        GL11.glTexCoord2f(1,0);
        GL11.glVertex2d(10+x,y);
        GL11.glTexCoord2f(1,1);
        GL11.glVertex2d(10+x,10+y);
        GL11.glTexCoord2f(0,1);
        GL11.glVertex2d(x,10+y);

    GL11.glEnd();
}

}


Answer:

For some reason while in a different position at the start you have to multiply the sx and sy equation by a -1.

public Bullet(double mx, double my, double px, double py){
    if(x==640 && y== 320){
    sx = mx-px;
    sy = py-my;
    x = px;
    y = py;
    sx = sx/Math.sqrt((mx-x)*(mx-x) + (my-y)*(my-y));
    sy = sy/Math.sqrt((mx-x)*(mx-x) + (my-y)*(my-y));

}
    if(x!=640 && y!= 320){
    sx = px-mx;
    sy = my-py;
    x = px;
    y = py;
    sx = sx/Math.sqrt((mx-x)*(mx-x) + (my-y)*(my-y));
    sy = sy/Math.sqrt((mx-x)*(mx-x) + (my-y)*(my-y));

}

}