LWJGL 16k Race game

Here is a 16K entry I was working on for the LWJGL 16K contest.

It is a little racing game where you fly a Klingon warbird against some federation ships. Use the arror keys to navigate and the space bar to fire. The race is only one lap around the circuit so be quick off the mark.

I have an unexplained pause around frame 80 after the start of the race. It is not garbage collection. Maybe someone with a bit more experiance in LWJGL could point me in the right direction to find the problem.

Please let me know if you encounter problems.

The game is NOW at http://javaunlimited.net/hosted/race16k/

Seems to have some serious issues with playing the sounds, really bad pauses. Other than that it’s kind of neat.

yeah I agree about the sound pausing the game whenever it plays (good thing there isnt any BGM!). Might want to check on your sound code :wink:

Other than that, cool game :smiley:

Windows XP // 2.1GHz // AMD Athlon 3200+ // 512MB RAM // Java 1.5 // nVidia GeForce4 MX

Thanks, I will check the sound code. Although I think I still get the pause at the start of the game even if no sound is played. Are you seeing pauses at other times when the sound is playing. I will turn sound off to see what happens.

For me the game stops for about 1/8th of a second every time a sound starts to play. I don’t see any other pauses but that be because they are hidden in the sound pauses.

Thanks, for the info. I am just playing the sound in the same thread as the rendering. I will play the sound in a new thread and see if that fixes the problem.

Ok I changed the sound code to run the sounds in a new thread. I also fixed a few glitches and now allow you to shoot the other racers which slows them down.

You can now also hit escape to restart the level if you don’t get off to a good start.
The new changes are at www.elmkom.matzoo.com NOW at http://unlimited.woogley.net/hosted/race16k/

Let me konow if the sound is fixed.

The game slows down a little when shooting. It has to do with the way I am detection collisions. I am drawing the shots and then reading back the framebuffer to see if the loaction of the shot is the right color or is hidden. If hidden there is a collision. This way I don’t have to check all posible things that could be hit and lets the shots collide with the walls and bolders. It looks like transforming the 3D shot location to the 2D framebuffer position and then reading the buffer is slow. I was using HPOcclusionTest before which is much faster but it is not supported on all platforms so I dropped it.
Does any one know of a faster way of doing this.

Sorry for the dead link. The server I was on got wiped. :frowning:

Here is the new link.

http://elmkom.tripod.com NOW at http://javaunlimited.net/hosted/race16k/

I loaded the game. It said, “Press Enter to Race” or something like that. I went to hit Enter, and before I pressed anything, the game disappeared. I loaded the game again, I got to that screen, and then after a couple seconds the game disappeared again :stuck_out_tongue: I’m using Java 1.5.0_02.

pretty cool little game, plays smooth and the mini-map is nice. As for collision detection, there is no way it should be a performance issue with that number of entities so you really should look for a new algorithm. Your gameplay is essentially 2d so you would be fine using the java.awt.Area class (search the forums for more on this) for collision. You could probably even get away with using circular collision bounds… I’m doubting pixel perfect collision is going to make much of an impact on the gameplay, polygonal collision bounds will certainly be sufficient. The Area class works with a 2-dimensional coordinate system, but since your movement only takes place along 2 axes, you can just pretend the z axis is the y axis :). The other thing you may consider doing is creating collision groups, each group has an id and maintains a list of groups that it collides with. Before doing collision detection check if collider1’s group collides with collider2’s group, if so then proceed with collision detection.

That’s really impressive. Fun, too!

I like the explosion and hit effects. When I stop being so damn lazy I’d like to try my hand at a 16k game as well :slight_smile:

Not sure why the game exits before a key hit. I have tested with 1.4 but I have not used any thing that should not work in 1.5. Do you see any exceptions in the webstart console. Also what platform are you on.

Thanks for the ideas on the collision detection. I am used polygon intrsections for the ship and asteroid collisions which is fast. But to detect a collision with the back ground I was trying to avoid such a polygon based intersection. As the course and obsticles are generated randomly. I would have to calculate the set of polygons representing the intersection between a fixed height that the missiles are fired at and the course and obsticles. I am not sure I could fit this into 16K. Plus I thought it was kind of cool to add anything into the scene and have the collision detection work automatically when the missiles became hidden.

If any one knows of a fast way to determine if a 3D point is hidden from view I would still like to know. It seems to me that the hardware should know this so why should I need to calculate it again.

For determining point visibility, you could render the scene once more into a pbuffer. The value to render into the pbuffer is simply the depth value of each pixel, so should be a fast render.

Then to determine if a 3d point is visible, transform and project the 3d point onto the viewport, then simply test its depth vs. the depth written into your pbuffer at that pixel. If the pbuffer is closer, then your point is occluded.

Dunno if this helps, or even possible at 16k.

That’s pretty much what I am doing. I am rendering once. Then transforming the point from 3d to 2d space and then reading back the frame buffer to check the color instead of depth. It easier to know the exact color to look for than the exact depth. I am new to opengl. So maybe I am missing somthing. Is a pbuffer like the framebuffer or is this something different. It looks like the slow down is due to having to grab the projection and modeview matrix, then transform the point. If I already know the 2d point ,like for the players ship which stays in the same spot, the buffer read is not too bad. I do this 4 times each frame to check if the edges of the ship hit the walls. In fact I even repaint the pixels I changed color on for the test and it still runs at 80 frames/sec. But when I fire a shot I have to first transform the point from 3d to 2d and it slows to 40 frames/sec. I use the gluProject to transform the point. Here is a snippet of the code. Any advice or improvements? I don’t acctually create the buffers each time, I just moved the code into the snippet for completness.


        FloatBuffer modelView = BufferUtils.createFloatBuffer(16); 
        FloatBuffer projView = BufferUtils.createFloatBuffer(16); 
        IntBuffer viewport = BufferUtils.createIntBuffer(16); 

        GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelView); 
        GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projView); 
        GL11.glGetInteger(GL11.GL_VIEWPORT, viewport); 
        float [][] modelArray = new float[4][4];
        float [][] projVArray = new float[4][4];
        modelView.rewind();
        projView.rewind();
        for(int i = 0;i<4;i++)
        {
            for(int j = 0;j< 4;j++)
            {
                modelArray[i][j] = modelView.get(i*4+j);
                projVArray[i][j] = projView.get(i*4+j);
            }
        }
        int[] intViewArray = new int[16];
        viewport.rewind();
        for(int i = 0;i<16;i++)
        {
            intViewArray[i] = viewport.get(i);
        }

        float[] projArray = new float[3]; 
        GLU.gluProject(x,y,z, modelArray, projVArray, intViewArray, projArray); 
      

Hmm, odd. Transforming a point from 3d to 2d is super simple & fast… you should be able to do it a BAJILLION times per frame with less than a 80->40 fps drop.

Several features of your code make me suspicious.

You can probably eliminate at least the 2 matrix gets to projection matrix & viewport. Your viewport should be known already, from when you set it, and it doesn’t change.

Your projection matrix is very simple and can just be stored in your code.

The fact that gluProject uses a bunch of 2d arrays makes me uneasy. Those things are super expensive in Java. Also looking at the src code for gluProject(), it’s nothing to write home about. It remultiplies the matrices with each other every time you call the function, not to mention its heavy use of arrays, 1 & 2 d alike.

Given a FloatBuffer (16) projectionMatrix and 3d position pos_c already transformed into camera space, you can transform it into the viewport pos like this: (code touched up for this example, may contain small typos/errors, treat as pseudocode):


Rectangle2di viewport = new Rectangle2di();
Matrix4f projectionMatrix = new JwMatrix4f();
 
 public boolean projectCameraSpacePointToViewport(Vector3f pos_c, Vector3f viewportPos, boolean computeZ)
{
	if (pos_c.z < nearPlane || pos_c.z > farPlane)
	    return false;

	final float projectedW = (projectionMatrix.m03 * pos_c.x) + (projectionMatrix.m13 * pos_c.y)
		+ (projectionMatrix.m23 * pos_c.z) + projectionMatrix.m33;

	if (Math.abs(projectedW) < 0.0001f)
	    return false;

	final float ooProjectedW = 1.0f / projectedW;

	final float projectedX = ooProjectedW
		* ((projectionMatrix.m00 * pos_c.x) + (projectionMatrix.m10 * pos_c.y) + (projectionMatrix.m20 * pos_c.z));
	final float projectedY = ooProjectedW
		* ((projectionMatrix.m01 * pos_c.x) + (projectionMatrix.m11 * pos_c.y) + (projectionMatrix.m21 * pos_c.z));

	if (!MathUtils.withinEpsilonInclusive(-1.0f, projectedX, 1.0f)
		|| !MathUtils.withinEpsilonInclusive(-1.0f, projectedY, 1.0f))
	    return false;

	final float halfViewportWidth = viewport.getWidth() * 0.5f;
	final float halfViewportHeight = viewport.getHeight() * 0.5f;

	viewportPos.x = (projectedX * halfViewportWidth) + viewport.getLeft() + halfViewportWidth;
	viewportPos.y = (projectedY * halfViewportHeight) + viewport.getTop() + halfViewportHeight;

	if (computeZ)
	{
	    viewportPos.z = ooProjectedW
		    * ((projectionMatrix.m02 * pos_c.x) + (projectionMatrix.m12 * pos_c.y)
			    + (projectionMatrix.m22 * pos_c.z) + projectionMatrix.m32);
	}

	return true;
}

//------------------- setup code for projectionMatrix:

private float farPlane = 8192.0f;
private float nearPlane = 0.1f;

private float fovHorizontal = MathUtils.PI / 2.0f;
private float fovVertical = 1.0f;

VolumeFrustum frustum = new VolumeFrustum();

private float oo_viewportHeight = 0.0f;

private float oo_viewportWidth = 0.0f;
private float aspect = 1.0f;

private void setup()
{
        if (viewport.getWidth() != 0)
            oo_viewportWidth = 1.0f / viewport.getWidth();
        else
            oo_viewportWidth = 1000000.0f;

        if (viewport.getHeight() != 0)
            oo_viewportHeight = 1.0f / viewport.getHeight();
        else
            oo_viewportHeight = 1000000.0f;

        // calculate the vertical FOV based on the horizontal fov

        aspect = viewport.getWidth() * oo_viewportHeight;

        fovVertical = fovHorizontal / aspect;

        frustum.setupFrustum(getNearPlane(), getFarPlane(), getFovHorizontal(), fovVertical, viewport.getWidth(),
                viewport.getHeight());

        final float viewDepth = farPlane - nearPlane;

        final float w = 1.0f / (float) Math.tan(fovHorizontal * 0.5f);
        final float h = 1.0f / (float) Math.tan(fovVertical * 0.5f);
        final float Q = (viewDepth != 0.0f) ? (farPlane / viewDepth) : 1.0f;

        projectionMatrix.m00 = w;
        projectionMatrix.m10 = 0.0f;
        projectionMatrix.m20 = 0.0f;
        projectionMatrix.m30 = 0.0f;

        projectionMatrix.m01 = 0.0f;
        projectionMatrix.m11 = h;
        projectionMatrix.m21 = 0.0f;
        projectionMatrix.m31 = 0.0f;

        projectionMatrix.m02 = 0.0f;
        projectionMatrix.m12 = 0.0f;
        projectionMatrix.m22 = Q;
        projectionMatrix.m32 = -nearPlane * Q;

        projectionMatrix.m03 = 0.0f;
        projectionMatrix.m13 = 0.0f;
        projectionMatrix.m23 = 1.0f;
        projectionMatrix.m33 = 0.0f;

        projectionMatrix.store(projectionMatrixBuffer);
        projectionMatrixBuffer.rewind();
 }

i think the site is down, doesn’t work for me!

Won’t launch:

java.lang.NullPointerException
	at com.sun.deploy.util.URLUtil.fileToURL(Unknown Source)
	at com.sun.deploy.net.DownloadEngine.getResource(Unknown Source)
	at com.sun.javaws.LaunchDownload.downloadJarFiles(Unknown Source)
	at com.sun.javaws.LaunchDownload.downloadEagerorAll(Unknown Source)
	at com.sun.javaws.Launcher.downloadResources(Unknown Source)
	at com.sun.javaws.Launcher.prepareLaunchFile(Unknown Source)
	at com.sun.javaws.Launcher.prepareToLaunch(Unknown Source)
	at com.sun.javaws.Launcher.launch(Unknown Source)
	at com.sun.javaws.Main.launchApp(Unknown Source)
	at com.sun.javaws.Main.continueInSecureThread(Unknown Source)
	at com.sun.javaws.Main$1.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)

I’m running Mustang b44.

Make sure you try the new link at

http://elmkom.tripod.com NOW at http://javaunlimited.net/hosted/race16k/

The original site got wiped. I just modified the original link in the post. I did not know you could modify a post after it was replied to :-[ Still learning.

Thanks for the code to transform 3d to 2d. I will try it to see if it makes a difference. I will also have to see if it takes more or less space than the call to gluProject. I usually use the calls instead of duplicating the code as in the 16K contest code in the lwjgl jars files does not count towards the size. I at least can use your idea to save the fetch of the viewport and projection matrix each time. I would have thought that shuch a simple thing would be part of the libs or event be built into opengl. I mean we have the hardware that can transform points it its sleep but yet we have to do transforms in software.

I modified and uploaded a new version of the code to use the tips from anarchotron, thanks. :slight_smile:
It runs much smoother now around 70 fps. It was even worse than you thought I was getting the matrix for every shot not just once per frame. I also changed from using the gluProject but that did not make much of a difference.