Hello.
I am working on a 2D game engine / prototype and I am having trouble with something - getting the 'absolute' world coordinates based off mouse coordinates.
My 2D camera, or 'Viewport' is identified by its position, a vector, and a zoom factor, that is between .5F - 1.5F (50% - 150%). In order to render objects on the screen, I subtract the camera's coordinates with the object's coordinates. For zoom, I use GL11's glScalef(zoomFactor, zoomFactor, 0) to accomplish the zooming effect.
How would I go about getting the "world coordinates' based on where I click with the mouse? I have tried numerous methods to do this when the camera is zoomed in/out and it always gives an incorrect world coordinate.
I would like to get the exact world coordinates from where a mouse is clicked relate to the 2D camera and its zoom/scale factor. Without zoom/scale in consideration, it works, but when I apply a zoom/scale and try to do something like:
double worldX = (mX + worldCamera.getPosition().getX()) * worldCamera.getZoom();
double worldY = (mY + worldCamera.getPosition().getY()) * worldCamera.getZoom();
Or any other methods suggested that I found on StackerOverflow (from other people's questions) it does not work
When testing this, I would click on a 'Block' or game object in my 2D world and print out the mouse coordinates and the calculated world coordinates. However, when I apply a zoom factor to it and move the camera around, the calculated world coordinates are way off.
And just in-case anyone is curious, here is the 2D camera code I have so far:
package dgk.prototype.game;
import dgk.prototype.util.Vec2D;
import static org.lwjgl.glfw.GLFW.*;
public class Viewport {
public static final int WIDTH = 800;
public static final int HEIGHT = 600;
/*
The tween for the Viewport, if it is locked onto a moving target, or simply a GameObject.
*/
public static final double TWEEN = .5D;
private Vec2D position;
private IEntity target = null;
/*
Zoom value between .1 and 1.0f. (1 to 100%)
*/
private float zoom = 1.0f;
public Viewport(double x, double y) {
this.position = new Vec2D(x, y);
}
public Vec2D getPosition() {
return this.position;
}
public boolean hasTarget() {
return (target == null) ? false : true;
}
public IEntity getTarget() {
return target;
}
public float getZoom() {
return zoom;
}
public void setZoom(float zoom) {
this.zoom = zoom;
}
public void onUpdate(GameWindow gameWindow) {
if(hasTarget()) {
return;
}
if(gameWindow.isKeyPressed(GLFW_KEY_A)) {
getPosition().add(new Vec2D(-1, 0));
}
if(gameWindow.isKeyPressed(GLFW_KEY_D)) {
getPosition().add(new Vec2D(1, 0));
}
if(gameWindow.isKeyPressed(GLFW_KEY_W)) {
getPosition().add(new Vec2D(0, -1));
}
if(gameWindow.isKeyPressed(GLFW_KEY_S)) {
getPosition().add(new Vec2D(0, 1));
}
if(gameWindow.isKeyPressed(GLFW_KEY_UP)) {
zoom += .01f;
if(zoom >= 1.5f) {
zoom = 1.5f;
}
System.out.println(this);
}
if(gameWindow.isKeyPressed(GLFW_KEY_DOWN)) {
zoom -= .01f;
if(zoom <= .25f) {
zoom = .25f;
return;
}
System.out.println(this);
}
//System.out.println(this);
}
@Override
public String toString() {
return "Viewport - (x: " + getPosition().getX() + ", y: " + getPosition().getY() + ", zoom: " + (100 * zoom) + "%, hasTarget: " + hasTarget() + ", target: " + getTarget() + ")";
}
}
The specific code I use for the mouse position / world coordinates calculations:
GLFW.glfwSetMouseButtonCallback(handle, (window, button, action, mods) -> {
if(button == GLFW_MOUSE_BUTTON_1 && action == GLFW_PRESS) {
DoubleBuffer xBuffer = BufferUtils.createDoubleBuffer(1);
DoubleBuffer yBuffer = BufferUtils.createDoubleBuffer(1);
glfwGetCursorPos(handle, xBuffer, yBuffer);
double mX = xBuffer.get(0);
double mY = yBuffer.get(0);
double worldX = (mX + worldCamera.getPosition().getX()) * worldCamera.getZoom();
double worldY = (mY + worldCamera.getPosition().getY()) * worldCamera.getZoom();
System.out.println("Mouse X: " + mX + ", Mouse Y: " + mY);
System.out.println("World X: " + worldX + ", World Y: " + worldY);
//System.out.println("World X: " + (800 - Math.abs((mX + worldCamera.getPosition().getX()) / worldCamera.getZoom()) - (800 - worldCamera.getPosition().getX())) + ", World Y: " + (600 - Math.abs((mY + worldCamera.getPosition().getY()) / worldCamera.getZoom()) - (600 - worldCamera.getPosition().getY())));
}
});