Converting between screen coordinates and scene/world coordinates
I am trying to learn OpenGL by coding a game for Android, but I have found myself in a pickle.
The game so far is a ship (a cube travelling along the Y axis), and I want it to shoot bullets (smaller cubes for now, for the sake of simplicity) towards the part of the screen that I touch. The Y coordinate of the ship is continously increasing due to it's movement and the camera is following it, using Matrix.setLookAtM, making the ship appear stationary.
Now for the question! Let us say I click on a part of the screen and assume Android spits the coordinates 100, 85 at me. How do I turn these coordinates into an angle relative to the ship (this is important)? By means of basic trigonometry, I could find the angle from the center of the ship to the point I touched on the screen. Although since I do not know the screen coordinate for the center of my ship (I only know it's coordinates in the world), I have come to a halt.
I would be grateful if anyone could point me in the right direction.
If you wanted an angle, you'd use arc tangent of your difference vector to find this. So, you'd do something like this:
Vector2 playerShipPosition; // x, y position of your ship
Vector2 touchPosition; // x, y position of where your finger touched the screen
Vector2 diff = touchPosition - playerShipPosition; // difference vector
float angle = atan2f(-diff.y, diff.x); // find the angle in radians as +/- PI
I wrote the code above in C++ as I haven't touched Java in a while. Java does have a built-in math function called atan2f though.
The variables: playerShipPosition and touchPosition, are your known variables that you've described above. The key is to find the difference in these two positions. Always subtract the destination point from the start point, otherwise your vector will face in the opposite direction. Once you have it, we use 'diff' vector's x and y components in atan2f(). This will give you the angle.
I'm making a few assumptions here:
1) This is a essentially a 2D game
If the game is in 3D, I'll need to know more information to give you a better answer that'll work in your game.
2) World-space units are measured in screen pixels
If you're working off of a world-space unit/screen pixels ratio, then you just need to make sure both playerShipPosition and touchPosition are in the same coordinate space. For example, if your ship, projectiles, and other scene elements would be in world units, and the pixel/unit ratio is 10 pixels per world-space unit. playerShipPosition is in world-space units, and Android's going to return your touch's position to screen coordinates. So, touchPosition would be Android's screen coordinates divided by 10. This gives you the touchPosition in world-space units. Again, assuming 2D here.
3) The positive y-axis of your world-space coordinate system is downward
If your ship's world-space coordinates are working off of a typical cartesian plane where the y-axis is upward, then diff.y won't be negative when you pass it into atan2f() as the 1st parameter. You will, however, have to add additional logic to convert the touch coordinates provided by Android to world-space because its positive y-axis is downward.
I don't understand how the ship and the point of the screen that I touch even lies in the same coordinate system
Transforming the ship's in-game world 3d-coordinates with a 'ModeViewProjection' matrix gives you the center of the ship in screen 2d-coordinates (in OpenGL screen coordinates are floats from 0 to 1, with Y axis inverted). You can then convert 0-1 coords to 0-width and 0-height, respectively, with a simple relation equation. That said, do you know, how to transform the coordinates with a modelviewprojection matrix? It's just matrix multiplication of the original model matrix of the ship by the view-projection matrix of the camera. Are you familiar with matrix multiplication?
Y axis flipped?
Android touch positions:
- relative to the top-left corner
- increase towards the bottom-right corner
OpenGL positions:
- relative to the bottom-left corner / or the center (it depends)
- increase to towards the top-right corner