First Person Shooter with LWJGL

Hello everyone. I’m trying to make my first 3D game and I’am having a lot of troubles how to shoot based on my rotation in the screen. I would like to know the best way of doing that.
Here is what I done so far,as you can see I use the RETURN KEY to activate the shoot.

MAIN CLASS

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;

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

import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;


public class Main 
{
public static void main(String[] args) 
{
initDisplay();

gameLoop();
cleanUp();
}

public static Texture loadTexture(String key)
{
try
{
return TextureLoader.getTexture("png", new FileInputStream(new File("res/" + key + ".png")));
}
catch (IOException ex)
{
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}

return null;
}

public static void gameLoop()
{
Texture wood = loadTexture("wood");

Camera cam = new Camera(70,(float)Display.getWidth()/(float)Display.getHeight(),0.3f,1000);
Player player = new Player(-cam.getX(),cam.getY(),cam.getZ());

boolean shooting = false;
float bullX = 0,bullY = 0,bullZ = 0;


while(!Display.isCloseRequested())
{
boolean forward = Keyboard.isKeyDown(Keyboard.KEY_W) || Keyboard.isKeyDown(Keyboard.KEY_UP);
boolean backward = Keyboard.isKeyDown(Keyboard.KEY_S) || Keyboard.isKeyDown(Keyboard.KEY_DOWN);
boolean left = Keyboard.isKeyDown(Keyboard.KEY_A);
boolean right = Keyboard.isKeyDown(Keyboard.KEY_D);

if(forward)
cam.moveZ(0.002f);
if(backward)
cam.moveZ(-0.002f);
if(left)
cam.moveX(0.002f);//cam.rotateY(-0.1f);
if(right)
cam.moveX(-0.002f);//cam.rotateY(0.1f);

if(Keyboard.isKeyDown(Keyboard.KEY_LEFT))
cam.rotateY(-0.1f);
if(Keyboard.isKeyDown(Keyboard.KEY_RIGHT))
cam.rotateY(0.1f);

if(Keyboard.isKeyDown(Keyboard.KEY_RETURN)){
		shooting = true;
		bullX = -cam.getX();
		bullY = -cam.getY();
		bullZ = -cam.getZ();
		
	
}

if(shooting){
	double dx = 0.01 * Math.cos(Math.toRadians(cam.getRY() + 90));
	double dz = 0.01 * Math.sin(Math.toRadians(cam.getRY() + 90));
	
	
	bullX-=dx;
	bullZ-=dz;
	
	
}


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
cam.useView();

glPushMatrix();
{
glColor3f(1.0f,0.5f,0f);
wood.bind();

glBegin(GL_QUADS);
{
	glTexCoord2f(0,0);glVertex3f(0,0,0);
	glTexCoord2f(0,1);glVertex3f(0,0,-10);
	glTexCoord2f(1,1);glVertex3f(10,0,-10);
	glTexCoord2f(1,0);glVertex3f(10,0,0);
	
	
	glColor3f(0f,0.5f,0f);
	glVertex3f(0,0,-5);
	glVertex3f(0,1,-5);
	glVertex3f(1,1,-5);
	glVertex3f(1,0,-5);
	
	
	
	if(shooting){
		glColor3f(1f,0f,0f);
		glVertex3f(bullX,bullY,bullZ - 3);
		glVertex3f(bullX,bullY+1,bullZ - 3);
		glVertex3f(bullX+1,bullY+1,bullZ - 3);
		glVertex3f(bullX+1,bullY,bullZ - 3);
	}
	
}
glEnd();

glLoadIdentity();

glBegin(GL_QUADS);
{
	
	glColor3f(0f,0.5f,0f);
	glVertex3f(0,0,-5);
	glVertex3f(0,1,-5);
	glVertex3f(1,1,-5);
	glVertex3f(1,0,-5);
	

	
}
glEnd();


}
glPopMatrix();
Display.update();

}
}

public static void cleanUp()
{
Display.destroy();
}

public static void initDisplay()
{
try
{
Display.setDisplayMode(new DisplayMode(800,600));
Display.create();
}
catch (LWJGLException ex)
{
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}

Camera:

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.util.glu.GLU.*;

public class Camera 
{
private float x;
private float y;
private float z;
private float rx;
private float ry;
private float rz;

private float fov;
private float aspect;
private float near;
private float far;

public Camera(float fov, float aspect, float near, float far)
{
x = 0;
y = -1f;
z = 0;
rx = 0;
ry = 0;
rz = 0;

this.fov = fov;
this.aspect = aspect;
this.near = near;
this.far = far;
initProjection();
}

private void initProjection()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fov,aspect,near,far);
glMatrixMode(GL_MODELVIEW);

glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
}

public void useView()
{
glRotatef(rx,1,0,0);
glRotatef(ry,0,1,0);
glRotatef(rz,0,0,1);
glTranslatef(x,y,z); 
}

public float getX()
{
return x;
}

public float getY()
{
return y;
}

public float getZ()
{
return z;
}

public void setX(float x)
{
this.x = x;
}

public void setY(float y)
{
this.y = y;
}

public void setZ(float z)
{
this.z = z;
}

public float getRX()
{
return rx;
}

public float getRY()
{
return ry;
}

public float getRZ()
{
return rz;
}

public void setRX(float rx)
{
this.rx = rx;
}

public void setRY(float ry)
{
this.ry = ry;
}

public void setRZ(float rz)
{
this.rz = rz;
}

public void moveZ(float amt)
{
z += amt * Math.sin(Math.toRadians(ry + 90));// * Math.sin(Math.toRadians(rx + 90));
x += amt * Math.cos(Math.toRadians(ry + 90));
//y += amt * Math.sin(Math.toRadians(rx));
}

public void moveX(float amt)
{
z += amt * Math.sin(Math.toRadians(ry));
x += amt * Math.cos(Math.toRadians(ry));
}

public void rotateY(float amt)
{
ry += amt;
}

public void rotateX(float amt)
{
rx += amt;
}

public void rotateZ(float amt)
{
rz += amt;
}
}

A few things are wrong,

1). I hope your code isn’t actually like that in your editor, use Ctrl+F in eclipse to format it.
2). Have separate voids for render and update.
3). I have done shooting before, but its pretty complicated, especially if you don’t know much about mathematics.
4).

glBegin(GL_QUADS);
{
   glTexCoord2f(0,0);glVertex3f(0,0,0);
   glTexCoord2f(0,1);glVertex3f(0,0,-10);
   glTexCoord2f(1,1);glVertex3f(10,0,-10);
   glTexCoord2f(1,0);glVertex3f(10,0,0);
   
   
   glColor3f(0f,0.5f,0f);
   glVertex3f(0,0,-5);
   glVertex3f(0,1,-5);
   glVertex3f(1,1,-5);
   glVertex3f(1,0,-5);
   
   
   
   if(shooting){
      glColor3f(1f,0f,0f);
      glVertex3f(bullX,bullY,bullZ - 3);
      glVertex3f(bullX,bullY+1,bullZ - 3);
      glVertex3f(bullX+1,bullY+1,bullZ - 3);
      glVertex3f(bullX+1,bullY,bullZ - 3);
   }
   
}

I don’t know if its possible to set multiple vertexes in a quad like that… Mostly because it is a QUAD meaning quadrilateral, meaning 4 vertexes. Put them in separate glBegins & glEnds


//Render floor
glBegin(GL_QUADS);
{
   glTexCoord2f(0,0);glVertex3f(0,0,0);
   glTexCoord2f(0,1);glVertex3f(0,0,-10);
   glTexCoord2f(1,1);glVertex3f(10,0,-10);
   glTexCoord2f(1,0);glVertex3f(10,0,0);
}glEnd();

//Render green quad
glBegin(GL_QUADS);
{   
   glColor3f(0f,0.5f,0f);
   glVertex3f(0,0,-5);
   glVertex3f(0,1,-5);
   glVertex3f(1,1,-5);
   glVertex3f(1,0,-5);
}glEnd();
   
//Render bullet
if(shooting){
   glBegin(GL_QUADS);
      glColor3f(1f,0f,0f);
      glVertex3f(bullX,bullY,bullZ - 3);
      glVertex3f(bullX,bullY+1,bullZ - 3);
      glVertex3f(bullX+1,bullY+1,bullZ - 3);
      glVertex3f(bullX+1,bullY,bullZ - 3);
   glEnd();
}

One last thing: Use Display.sync(60); before Display.update();
Because if your on a fast machine, the bullet’s coordinates will fly faster, this slows the game down to 60 updates a second.

You didnt help me at all,but thanks.

Well, I tried. All I’m saying is that its hard to make a bullet fly. Use a physics library, like JBullet - Although it is hard, most first person shooters use a library like it. (Jbullet is a port of Bullet for java.)

This statement is incorrect.

First let me state that the mode of rendering you are using (immediate mode) is very old, deprecated, and slow. Look into using VBOs they are much faster. Second the way you are using push and pop matrix is completely useless. You are pushing the identity matrix then popping it back to the identity matrix. All of these points make me thing that you are very new to openGL in which case you should take on much, much smaller projects before you try to take on a 3D FPS.

Anyway, you can do this problem in many ways mattering on what you are more comfortable with. Ill just show you the way i do it to get more use out of the GPU. I give my Bullet a speed and put it in a 4d vector with coordinates (0, 0, speed, 0) (the reason the w component is a 0 and not a 1 is because this is simply a direction not a location)

Next multiply your vector by two matricies. the first one being the rotation around the x axis and one around the y axis (you should store these rotations, they are the same ones of the camera right as the player shoots). In terms of immediate mode you would do something like this.


if(shooting)
{
           glPushMatrix();
           glLoadIdentity();
           //load in camera rotation and location when shot was fired
           glTranslatef(initBullx, initBully, initBullz);
           glRotatef(rotAroundYaxis, 0, 1, 0);
           glRotatef(rotAroundXaxis, 1, 0, 0);
           BullZ += speed;
           glTranslatef(0, 0, bullZ);

           //render bullet here as if it is at the origin facing the Z direction

           glPopMatrix();
 
}

Okay,but using this method how am I supposed to do the math for collision?

What I really need is a way to make the shoot system and Im not sure how to do it.

This is exactly why we start small.

I don’t know if you understand but this isn’t a good idea. Start in 2D and don’t use deprecated OpenGL, trust me its much more worth it to learn shaders and all that jazz. I spent a year learning the deprecated fixed function pipeline and now I’m a mess with OpenGL because I’m trying to convert to only modern and its difficult.

The other thing you need to learn is higher level math. You quite obviously, no offense, don’t know much about the math you are trying to utilize here. No one is just going to write a collision detection and bullet system for you. These are things programmers must know how to do for themselves.

Yes I understand. I started small with 2d development,then i tought i was ready to start with 3d because the 2d development was easy.
Unfortunately Im having a lot of troubles with math. Im not sure what to do now :S

Thank you all for the help

Honestly, pick up a good math primer. I’ve always been meh with math, and I bought a primer for about 20$. Probably one of the best decisions of my math related life because the author explains everything with many real life examples instead of just throwing math at you. Sure, there are a lot of good tutorials online. But they all assume you’ve already taken a college level math course!

You can apply the same rotation you perform on the blocks to instead of producing coordinates divide them by your camera position and turn them into gradients. Or you can use ATAN2 twice for the xyz however that would be considerably more difficult seeing as you have rotation already included.

Um… what are you trying to say here?

For the gradients of the projectile if you use the same rotation math for a block but instead for where you are firing. I would store my values as floats then you can directly calculate the gradients using basic trig.