LWJGL 2D Breakout Tutorial – Setup Summary

I stream-of-consciousness documented my unnecessarily complex journey through figuring out how to set up LWJGL enough to draw images on the screen. Since it took me almost 2 weeks and 3 posts to figure out, I clearly made some mistakes along the way. If you’d like to read of my trials, check out the posts, starting from here. Luckily, now that I’ve done it once, I can do it again, and much more concisely. So here are the steps from going from nothing to a working LWJGL 2D game environment.

I am currently running Ubuntu 12.04.3 LTS, and I’m going to set up my environment in Eclipse Kepler. We will be using LWJGL and some dependencies like Slick2D and Java3D vecmath. First, we need some java.

Let’s add the oracle java installer repo from WebUpd8 so we can do this all at once.

sudo apt-add-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install openjdk-7-jdk openjdk-7-jre maven oracle-java7-installer git

Once that’s completed you should set your $JAVA_HOME variable to your oracle directory.

export JAVA_HOME='/usr/lib/jvm/java-7-oracle/'

Now that our java is set up, let’s get the latest Eclipse. Download the correct version from here (Mine was Linux 64-bit) and install it. I personally put my Eclipse into /opt/eclipse/ and run it from there using /opt/eclipse/eclipse

Once Eclipse is installed, open it up and we’ll need to install Maven for Eclipse, or the m2e plugin.
maven_for_eclipse

Once m2e is installed, you’ll need to restart Eclipse, and then we can create a new maven project. I put my code into /home/midas/git/breakout-lwjgl

new_maven_project
pick_maven_type
save_project_location

And this gives us a new blank Maven project. Now we need to modify the pom.xml file to understand our dependencies and build process.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>breakout-lwjgl</groupId>
	<artifactId>breakout</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>breakout</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<natives.version>0.0.6</natives.version>
		<lwjgl.version>2.8.4</lwjgl.version>
		<slick.version>2013.08-SNAPSHOT</slick.version>
		<junit.version>4.10</junit.version>
	</properties>

	<repositories>
		<repository>
			<id>mavenNatives</id>
			<name>Maven Natives Repository</name>
			<url>http://mavennatives.googlecode.com/svn/repo</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</repository>
		<repository>
			<id>slick2d</id>
			<name>Slick2D</name>
			<url>file:${project.basedir}/repo</url>
		</repository>
	</repositories>

	<pluginRepositories>
		<pluginRepository>
			<id>central</id>
			<name>Maven Plugin Repository</name>
			<url>http://repo1.maven.org/maven2</url>
			<layout>default</layout>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
			<releases>
				<updatePolicy>never</updatePolicy>
			</releases>
		</pluginRepository>
	</pluginRepositories>

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>javax.jnlp</groupId>
			<artifactId>jnlp-api</artifactId>
			<version>7.0</version>
			<scope>system</scope>
			<systemPath>${java.home}/lib/javaws.jar</systemPath>
		</dependency>
		<dependency>
			<groupId>org.lwjgl.lwjgl</groupId>
			<artifactId>lwjgl</artifactId>
			<version>${lwjgl.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slick2d</groupId>
			<artifactId>slick2d-core</artifactId>
			<version>${slick.version}</version>
		</dependency>
		<dependency>
			<groupId>java3d</groupId>
			<artifactId>vecmath</artifactId>
			<version>1.3.1</version>
		</dependency>
	</dependencies>

	<build>
		<pluginManagement>
			<plugins>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-compiler-plugin</artifactId>
					<configuration>
						<source>1.6</source>
						<target>1.6</target>
					</configuration>
				</plugin>

				<plugin>
					<groupId>com.googlecode.mavennatives</groupId>
					<artifactId>maven-nativedependencies-plugin</artifactId>
					<version>${natives.version}</version>
					<executions>
						<execution>
							<id>unpacknatives</id>
							<phase>generate-resources</phase>
							<goals>
								<!--suppress MavenModelInspection (this line is for IDEA) -->
								<goal>copy</goal>
							</goals>
						</execution>
					</executions>
				</plugin>
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-dependency-plugin</artifactId>
					<executions>
						<execution>
							<id>copy-dependencies</id>
							<phase>package</phase>
							<goals>
								<goal>copy-dependencies</goal>
							</goals>
							<configuration>
								<outputDirectory>${project.build.directory}</outputDirectory>
								<overWriteReleases>false</overWriteReleases>
								<overWriteSnapshots>true</overWriteSnapshots>
							</configuration>
						</execution>
					</executions>
				</plugin>
				<plugin>
					<artifactId>maven-assembly-plugin</artifactId>
					<configuration>
						<archive>
							<manifest>
								<addClasspath>true</addClasspath>
								<mainClass>breakout_lwjgl.breakout.App</mainClass>
							</manifest>
						</archive>
						<descriptorRefs>
							<descriptorRef>jar-with-dependencies</descriptorRef>
						</descriptorRefs>
					</configuration>
					<executions>
						<execution>
							<id>make-assembly</id>
							<phase>package</phase>
							<goals>
								<goal>single</goal>
							</goals>
						</execution>
					</executions>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>
</project>

At this point our pom.xml file is set up, but the things we depend on aren’t all in place. First, let’s add the oracle java 7 JRE to our project as it’s primary library.
Go to Project Properties.
project_properties

Oh, and before we go to the Libraries tab, make sure you set up the native library location correctly: it should point to breakout/target/natives then click on the Libraries tab.
native_library_location_correct
From there click Add Library… And pick JRE System Library and click Next.
add_library_add_jre
Pick the Alternate JRE radio button, and click on the Installed JREs… button next to it.
alternate_jre_installed_jres
Pick Standard VM and click Next.
add_standard_vm
Now for JRE Home, navigate to your java 7 oracle install path, and the name should fill in.
jre_definition_add_external_jars
Navigate to your javaws.jar inside your java-7-oracle install. This is located on my machine at /usr/lib/jvm/java-7-oracle/jre/lib
add_javaws_jar
Now that we’ve added the javaws.jar to the new java-7-oracle JRE, click ok all the way out until we’re back at the Add Library screen. In the drop down list, pick your new java-7-oracle JRE environment.
switch_to_java_7

Now some of our dependencies are cleared up, we can work on setting up Slick2D next. I found a convenient Slick2D maven repo on github, so I decided to use it here. I keep all of my git projects in /home/midas/git/ so that’s where I’m going to clone the new slick2d repo.

cd /home/midas/git/
git clone https://github.com/nguillaumin/slick2d-maven.git
cd slick2d-maven
mvn clean package

**Note** This assumes your JAVA_HOME is set to your oracle version. If for some reason it’s not, you can run this instead: JAVA_HOME=’/usr/lib/jvm/java-7-oracle/’;mvn clean package

This will compile and package several slick2d jars. We are only interested in the core at the moment, so make a new directory called ‘repo’ in your project path and copy the new core jar there.

mkdir /home/midas/git/breakout-lwjgl/breakout/repo
cp /home/midas/git/slick2d-maven/slick2d-core/target/ slick2d-core-2013.08-SNAPSHOT.jar /home/midas/git/breakout-lwjgl/breakout/repo/

And to finish up our dependencies, we can make use of the maven native dependencies plugin.

cd /home/midas/git/breakout-lwjgl/breakout
mvn nativedependencies:copy

This will put all of our native libraries into /home/midas/git/breakout-lwjgl/breakout/target/natives which is the same path we set up in the project properties.

Now all we need are a PNG image to draw. Make a new ‘res’ directory in your project and copy this PNG there.

fire_ball

Now just update the App.java code that was generated to this:

package breakout_lwjgl.breakout;

import java.io.IOException;

import javax.vecmath.Vector2f;

import org.lwjgl.input.Keyboard;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
import org.newdawn.slick.util.ResourceLoader;
import org.newdawn.slick.Color;

public class App {

	public boolean[] keysPressed = new boolean[255];
	public Vector2f ballPosition = new Vector2f();
	public Texture ballTexture;

	public void start() {
		try {
			Display.setDisplayMode(new DisplayMode(800, 600));
			Display.create();
		} catch (LWJGLException e) {
			e.printStackTrace();
			System.exit(0);
		}

		GL11.glMatrixMode(GL11.GL_PROJECTION);
		GL11.glLoadIdentity();
		GL11.glEnable(GL11.GL_TEXTURE_2D);
		GL11.glEnable(GL11.GL_BLEND);
		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
		GL11.glOrtho(0, 800, 600, 0, -1.0f, 1.0f);
		GL11.glMatrixMode(GL11.GL_MODELVIEW);

		try {
			this.init();
		} catch (IOException e) {
			e.printStackTrace();
		}

		while (!Display.isCloseRequested()) {
			this.update();
			this.draw();
		}

		Display.destroy();
	}

	public void init() throws IOException {
		this.ballPosition.x = 50;
		this.ballPosition.y = 50;

		this.ballTexture = TextureLoader.getTexture("PNG", ResourceLoader.getResourceAsStream("res/fire_ball.png"));
	}

	public void update() {
		while (Keyboard.next()) {
			if (Keyboard.getEventKeyState()) {
				this.keysPressed[Keyboard.getEventKey()] = true;
			} else {
				this.keysPressed[Keyboard.getEventKey()] = false;
			}
		}

		if (this.keysPressed[Keyboard.KEY_LEFT]) {
			this.ballPosition.x -= 1.0;
		}
		if (this.keysPressed[Keyboard.KEY_RIGHT]) {
			this.ballPosition.x += 1.0;
		}
		if (this.keysPressed[Keyboard.KEY_UP]) {
			this.ballPosition.y -= 1.0;
		}
		if (this.keysPressed[Keyboard.KEY_DOWN]) {
			this.ballPosition.y += 1.0;
		}
	}

	public void draw() {
		GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
		Color.white.bind();
		this.ballTexture.bind();

		GL11.glBegin(GL11.GL_QUADS);
		GL11.glTexCoord2f(0, 0);
		GL11.glVertex2f(this.ballPosition.x, this.ballPosition.y);
		GL11.glTexCoord2f(1, 0);
		GL11.glVertex2f(this.ballPosition.x + this.ballTexture.getTextureWidth(), this.ballPosition.y);
		GL11.glTexCoord2f(1, 1);
		GL11.glVertex2f(this.ballPosition.x + this.ballTexture.getTextureWidth(), this.ballPosition.y + this.ballTexture.getTextureHeight());
		GL11.glTexCoord2f(0, 1);
		GL11.glVertex2f(this.ballPosition.x, this.ballPosition.y + this.ballTexture.getTextureHeight());
		GL11.glEnd();

		Display.update();
	}

	public static void main(String[] argv) {
		App displayExample = new App();
		displayExample.start();
	}
}

Now we need to run maven install to get the jars to build.

maven_install

If it does work, all you need to do now is click the green Run App button in Eclipse, and you should end up with a game window that looks like this, and contains a ball image you can move around using the arrow keys.

moving_ball_in_game

If at any point you get errors, feel free to contact me or leave a comment. I spent a long time figuring this stuff out, and I’m totally willing to help you figure out what went wrong. Or maybe I made a mistake and I need to correct it. But seriously, message me if it doesn’t work.

Here are my references:
lwjgl.org – Setting Up LWJGL with Maven
Install Oracle Java 7 in Ubuntu via PPA repository
Slick 2D Maven Distribution

Advertisements
LWJGL 2D Breakout Tutorial – Setup Summary

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s