What is a Sustainable Developer?

I was recently asked to describe what I felt were the traits that exemplified modern, professional software engineers. I wrote pages of notes trying to describe how I felt and why, but the most effective way I found to describe what a Sustainable Developer does is to point out the differences from the traditional (i.e. bad) way of developing code.

Traditional development practices

  • new features are done as quickly as possible
  • changes are done as quickly as possible
  • each developer works in a single part of the code
  • developers rarely talk with each other except to decide on an API
  • bugs are an inherent part of having custom software
  • servers and software will randomly break and we work all night to get it back up
  • the tech team’s work is too volatile to do meaningful long-term planning
  • bigger changes mean bigger risks
  • eventually the code is rewritten because the existing codebase is unmanageable

Sustainable development practices

  • Developers are a team and everyone is responsible for every part of the code
  • Developers follow the Boy Scout Method: if you touch code, you must leave it better than when you found it, never worse
  • Developers use emergent design and the SOLID principles to guide how code is written
  • The developers will work closely with the customer to deliver exactly the feature required
  • New features and changes are done in order of business priority
  • Happy developers leads to good decisions – deadline pressures are detrimental to solving a problem effectively
  • Code quality is never something that can be compromised; only features, time or resources are the dials to change
  • Developers don’t write bugs in the first place so they never have to debug later
  • Software is trustworthy; changes are never scary because the code is well encapsulated, easy to read and never “clever”
  • Code will have automated unit tests over it to alert other programmers when they might be introducting an unexpected side effect
  • servers are stable and trustworthy; instability and failures are rarities
  • Development teams are never larger than 5-10 people; developers cannot communicate effectively to a large group
  • Pair-programming is a must when training new developers in the codebase or when sharing knowledge between senior and junior developers
  • Team health and current status are always clearly communicated – less “unexpected” surprises and planning is a meaningful activity

Summary

So really, this boils down to about 6 major viewpoints that differentiate a sustainable developer from a traditional one.

Stability and quality are the primary focus of Sustainable developers

Having bugs in the code is comparable to having cracks in a housing foundation; each one is dangerous and expensive to fix. Nothing unexpected should ever happen when using or changing the software.

Sustainable Developers maintain codebases for the long-term

We don’t work in churn-and-burn projects; we live in this codebase now, we better prevent an infestation of bugs. The code needs to be easy to read, easy to maintain and even easier to debug. Code that does something wrong should be very easy to spot because the code is simple, clear and concise.

Communication between the developers and the customer drives all code work

We only build what is requested, and we build exactly what is requested. Requirements gathering is a difficult part of the job, but prevents us from wasting time on incorrect or useless features.

Communication within the development team

We all have strengths and weaknesses, learning and cooperation is best for the team. Daily standups so the team is aware what others are working on, weekly or monthly retrospectives to analyze longer-term issues or to air grievances within the team are all important for keeping the developers happy and the code running smoothly.

Education and experimentation

Well-informed developers make well-informed decisions; lectures, classes, building prototypes, and research are all crucial parts of a developer’s day-to-day.

Time pressures are kept away from developers whenever possible

Effective planning is critical to keep developers from the “death march” typically associated with traditional development. Late nights and sleep deprivation only lead to bad coding decisions and bugs in the future. If a developer is informed that a feature must be out by a certain date, the temptation to cut corners to try and hit that date is large, but the long-term cost is much larger.

Advertisements

Unreal Editor 4 for Linux

I recently discovered that the Unreal Editor 4 has an early-access branch available for Linux! So I decided to pull it down and give it a whirl in Ubuntu 15.04.

So if you want to use the free/open-source version of the editor, first you have to request access to the github repository. You’ll need to make an Epic Games account and once you’re logged in, link your github username to your account from the Profile tab. These instructions can be found here: https://www.unrealengine.com/ue4-on-github

Once you have access to the repo, make sure you’re on a beefy computer, since we’ll be compiling massive amounts of C++ code.

Update: Ugh, ok, so this was even more intense to compile than I expected. So I could continue using my computer while this runs, I decided to add some niceness to the compilation process. This will slow down the build process, but it won’t murder your computer if you need to use it, either.

git clone -b 4.8 https://github.com/EpicGames/UnrealEngine.git
cd UnrealEngine
./Setup.sh
./GenerateProjectFiles.sh
nice -n20 make SlateViewer
nice -n20 make UE4Editor ARGS=-clean
nice -n20 make UE4Editor UE4Game UnrealPak CrashReportClient ShaderCompileWorker UnrealLightmass
cd Engine/Binaries/Linux && ./UE4Editor

Only 2 hours later, I finally have it working!
unreal_editor_in_linux_desktop

I’ve got several thousand shaders to compile before I can actually get into using it, but it looks like the editor is fully featured and working pretty well.

Ubuntu 15.04 Audio Output Keyboard Shortcut

My computer is located in my bedroom, which is awesomely convenient except when I want to play audio. Usually it’s not a problem to play it out loud, but in the evening it’s gotta be headphones or muted. Ubuntu makes it easy to change audio sources using the Sound Manager in the navbar, but change sources 3-4 times a day and it starts getting annoying quick.

audio_selector

I’m surprised that there is no easy way to switch sources, so I decided to set up a custom keyboard shortcut to run a script that toggles between sources.

First, you’ll need the script.

#!/bin/bash

declare -i active_sink=`pacmd list-sinks | sed -n 's/.*\*.*index: \([0-9]\)/\1/p'`
 declare -i next_sink_index=0
 declare -i available_sinks=(`pacmd list-sinks | sed -n 's/.*index: \([0-9]\)/\1/p'`)
 for index in ${!available_sinks[@]};
 do
 if [ ${available_sinks[$index]} -eq $active_sink ]; then
 next_sink_index=${index}+1
 fi
 done
 if [ $next_sink_index -ge ${#available_sinks[@]} ]; then
 next_sink_index=0
 fi
 new_sink=${available_sinks[$next_sink_index]}
 pacmd "set-default-sink ${new_sink}"
 declare -i apps_playing=`pacmd list-sink-inputs | sed -n 's/.*index: \([0-9]\)/\1/p'`

 for app in $apps_playing;
 do
 pacmd "move-sink-input $app $new_sink"
 done

Essentially, this script uses pacmd list-sinks and pacmd list-sinks-inputs to scrape out information about the currently available and playing audio. It builds a list of valid outputs, and then it will flip all playing sources through all available outputs.

Place the script wherever you’d like, make it executable and then set up the keyboard shortcut.

System Settings > Keyboard > Shortcuts > Custom Shortcuts > +

shortcut_define

Name the shortcut something memorable, and then set the command to point to your sound-switcher script. Mine is /home/midas/sound-switcher.sh

After clicking Apply, you just need to bind it to a hotkey or combination.

keyboard_shortcuts

I picked F9 because my keyboard has a little music note there, so it makes the most sense for me.

Hopefully this makes your audio-flipping life a little easier. Let me know if you come across any problems, and I’ll be happy to help.

nginx CORS whitelist map

Above your server {} block, you need to add a whitelist map.

map $http_origin $cors_header{
  default "";
  include /etc/nginx/cors-whitelist.map;
}

Then you need to create a cors-whitelist.map file in /etc/nginx.

"~^(http:\/\/localdomain1\.com)$" "$http_origin";
"~^(http:\/\/localdomain3\.com)$" "$http_origin";

And finally, add in the appropriate headers in your server block:

server {
  listen 80;
  listen [::]:80;

  add_header 'Access-Control-Allow-Origin' "$cors_header";
  add_header 'Access-Control-Allow-Credentials' 'true';
  add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

root /var/www/html;
[...]

It’s a little redundant in the map file, but it maximizes readability if you have a lot of servers that need CORS access.

How to record desktop images into gif format on Ubuntu 14.04

First, you need to install a few requirements:
sudo apt-get install gifsicle imagemagick
sudo add-apt-repository ppa:maarten-baert/simplescreenrecorder
sudo apt-get update
sudo apt-get install simplescreenrecorder

Now you need to use simple screen recorder to capture whatever video you like. I used it to snag some gameplay of a game I was working on. It has an excellent GUI, and I drew a rectangle on the screen around the game I wanted to record, and saved it.

Now that you have a video, it’s time to convert it into an exciting gif! First, use avconv to break the mp4 into it’s component frames. The stuff in brackets is optional.

avconv -i lights_gameplay.mp4 -vsync 1 [-r 25] -an -y -qscale 1 [-s 800x600] lights/out_%04d.png

Woo! This is a big confusing command and is difficult to just discover what it’s doing. So here’s a breakdown!

  • -i [filename] this is the input filename
  • -an Ignore the audio
  • -y allow overwrites without asking
  • -r [fps] frames per second, if you want to set it to something different than your video
  • -qscale [amount] 1-31, with 1 being the best and 31 being awful
  • -vsync [method] I have no idea what this does. Just set it to 1.
  • -s [output resolution] If you want to start with a particular image scale.

I used this because my video was already perfect.
avconv -i lights_gameplay.mp4 -vsync 1 -an -y -qscale 1 lights/out_%04d.png

Note: I didn’t convert directly to gif here because you lose the color information. Since I didn’t select *exactly* the game window, I used an image editing program (gimp) to figure out how many pixels I wanted to crop off of the edges.

I want to remove 14 pixels from the left side, and 12 pixels from the top, so that my remaining image is 800×600 (the size of my game screen).

for i in lights/*.png ; do convert "$i" -crop 800x600+14+12 +repage "$i" ; done

At this point, there was a bit of “video editing” I wanted to do. I just opened the folder with the pngs and deleted out the frames I wanted to remove. To reduce the file size, I also decided to scale the images down. This is not required, but if your gif ends up massive, this is the first recommendation I would make for improving it.

for i in lights/*.png ; do convert "$i" -resize 50% "$i" ; done

Now that our frames are just what we want, let’s finally turn them into gifs! (This takes a long time if you have a bunch of frames, so just be patient!)
for i in lights/*.png ; do convert "$i" "${i%.*}.gif" ; done

Gifsicle is an animated gif manipulation tool. We’re using it just to piece together an animated gif from the frames, but it allows us to change some standard gif parameters in the process. For instance, this sets the delay between frames to 3, and sets the gif to loop forever.
gifsicle --delay=3 --loop lights/*.gif > lights_raw.gif

Finally, try to have imagemagick strip out extraneous data (bits of each frame that don’t change)
convert -layers Optimize lights_raw.gif lights_gameplay.gif

or, if you want to be really aggressive in compressing the gif (but you run the risk of artifacts)
convert lights_raw.gif -fuzz 30% -layers Optimize lights_gameplay.gif

And here’s the finished product! Only a tiny 7.9 mb!

lights_gameplay

Drakon MUD Server: Dev Diary 1

So I’ve been tinkering around with writing a MUD server in java, one that uses all the new network features we’ve developed since MUDs were a big deal. Basically, I want to use an SSH connection to secure the communication, and support an external API so other developers could write more elaborate clients. My ultimate goal is to use this multiplayer real-time server and exposed API to provide the backend and interaction for multiplayer games on mobile clients.

Honestly, I have no idea how I’m going to do this, because I’ve never written a MUD server or toyed around with SSH like this.

So my first diary (and probably the first few iterations of them) will be research, trying stuff out and seeing what works and what doesn’t.

Step 1: SSH Research

So if I want my server to be secure, I’m going to need to know HOW to secure it, so I might as well start by writing an SSH server, and adding a MUD server underneath it. So how does one write an SSH server?
A bit of Googling brought up Apache MINA: While this project promises a lot of things, the important thing here is it’s support for “SSHd : A Java library supporting the SSHH protocol”

Awesome, this should be easy! I just pull down the code from https://github.com/apache/mina-sshd, compile it and that should give me the dependencies I need. Yea, it’s not that easy.

I won’t describe my dependency hell to you because it’s a little tangential, but if you want more details (or help) just send me a message. I started a new java project with dependencies on:

  • commons-codec-1.9
  • gson-2.2.4
  • log4j-1.2.17
  • slf4j-api-1.7.6
  • slf4j-log4j12-1.7.6
  • sshd-core-0.10.1

Set up a simple echo server

There are a few example SSHd servers in the code, and a really basic example of how to use the library can be found here.

int port = 5180;
SshServer sshServer = SshServer.setUpDefaultServer();
sshServer.setPort(port);
sshServer.setKeyPairProvider(Utils.createTestHostKeyProvider());
sshServer.setShellFactory(new EchoShellFactory());
sshServer.setPasswordAuthenticator(new BogusPasswordAuthenticator());

try {
server.start();
} catch (IOException e) {
e.printStackTrace();
}

This is pretty much a straight copy from the test file. But an SSH server that lets anyone connect is kind of silly, since we’re trying to do this securely. So instead of a BogusPasswordAuthenticator, let’s make a DrakonPasswordAuthencator. I want it to read in user data from a JSON file, compare usernames and passwords, and if the info matches, “log in” that user. Which really just means preload that user-specific data.

Programming by intention usually leads to stuff I understand pretty well, so the first thing I did was design out what the users.json file would look like.


[
{
"id" : 1,
"name": "admin",
"password": "admin",
"password": "d033e22ae348aeb5660fc2140aec35850c4da997",
"email": "admin@localhost"
}
]

NOTE: using flaws (or features) of JSON, I put the password in plaintext above the actual password definition. When parsing the file, the last key is the only one saved, so I can “comment” the user data file with the plaintext password. Don’t need a double password definition, and definitely would not store plaintext passwords.

Password is a SHA1 hash of the password “admin”, so to log in to the server we would want to type something like:
$ ssh admin@localhost -p 5180

Now I just need a way to parse the user file and decide if the login information is correct or not. First, I write my own PasswordAuthenticator.


package com.eyeofmidas.drakon.auth;

import java.util.ArrayList;

import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.session.ServerSession;

import com.eyeofmidas.drakon.user.User;
import com.eyeofmidas.drakon.user.UserFileReader;

public class DrakonPasswordAuthenticator implements PasswordAuthenticator {

@Override
public boolean authenticate(String username, String password, ServerSession session) {
UserFileReader userFileReader = new UserFileReader();
ArrayList users = userFileReader.read("data/users.json");
for(User user : users) {
if(user.isAuthUser(username, password)){
return true;
}
}
return false;
}

}

The UserFileReader really just opens a connection to the file and reads in the json data one element at a time. It will read in all the users, building an ArrayList of User objects, and then return it to the authenticator. The User object is mostly a dummy object that holds the unique information for one particular user, but it also has a function “isAuthUser” that does a bit of hashing and matching to determine if the username and password match the user object.


package com.eyeofmidas.drakon.user;

import org.apache.commons.codec.digest.DigestUtils;

public class User {

private int id;
private String name;
private String password;
private String email;

public void setId(int nextInt) {
id = nextInt;
}

public void setName(String nextString) {
name = nextString;
}

public void setPassword(String nextString) {
password = nextString;
}

public int getId() {
return id;
}

public String getName() {
return name;
}

public String getEmail() {
return email;
}

public boolean isAuthUser(String username, String userPassword) {
userPassword = DigestUtils.sha1Hex(userPassword);
return (name.equals(username) && password.equals(userPassword));
}

public void setEmail(String nextString) {
email = nextString;
}

}

Enable password authentication

So now we have a class that reads in a json collection of user data, creates an arraylist of Users, and our authenticator can now use that to determine who is logging in. Have to tell the server about it, though!


sshServer.setPasswordAuthenticator(new DrakonPasswordAuthenticator());

Cool! Now our server will only echo back to us if we’ve got the right username and password! Next time I’ll work on making the EchoServer do more than just echo, and maybe toy around with using private/public keys for authentication.

You can follow me along with my code here: https://github.com/EyeOfMidas/drakon

And I will gradually update this blog as I make changes.

HTML CSS blur effect

I was trying to blur out a bit of content on a page I was working on in Ruby on Rails, and I was having a problem getting HAML and SASS to play nice and stop breaking my filter in Firefox. Luckily I was able to figure it out; turns out to make Mozilla Firefox blur something, you need to use the SVG filter embedded in the url definition. Note: this is not very performant in Firefox, so try to use it sparingly, especially on pages with scrolling.


.blur {
  filter: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'><filter id='blurfilter' x='0' y='0'><feGaussianBlur in='SourceGraphic' stdDeviation='3'></feGaussianBlur></filter></svg>#blurfilter");
  -webkit-filter: blur(4px);
  filter: blur(4px);
}

just include this CSS class, and then tag any element with it. If the blur is too much (or not enough) just change the blur([number]px) and the stdDeviation='[number]’ fields to whatever you like.

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

LWJGL 2D Breakout Tutorial – Slick2D and images

Update: Just trying to get set up? Check out the streamlined setup tutorial LWJGL 2D Breakout Tutorial – Setup Summary.

This is the third post in a series. You should probably go back and start from the first post. LWJGL 2D Breakout Tutorial – Environment Setup

Ok, so we’ve got a shape drawing, but I really want to draw *images*. Luckily, we spent all that time setting up the slick2D dependency, so it should be a piece of cake!

First we need to include our new dependencies in our App.java file.

import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
import org.newdawn.slick.util.ResourceLoader;
import org.newdawn.slick.Color;

And… well, shoot. It looks like something’s wrong with the Slick2D dependency inclusion, because all of those are yelling about an error.

Ah, I see what the problem is; I told you to include the wrong dependency in your pom.xml file. The new slick dependency should be:

<dependency>
	<groupId>org.slick2d</groupId>
	<artifactId>slick2d-core</artifactId>
	<version>${slick.version}</version>
</dependency>

So we need to copy that other compiled .jar from the slick2d repo that we ran before. So copy slick2d-core-2013.08-SNAPSHOT.jar from ~/.m2/repository/org/slick2d/slick2d-basic-game-archetype/ into our project’s repo file, and remove the old jar that was there.

cp ~/.m2/repository/org/slick2d/slick2d-basic-game-archetype/slick2d-core-2013.08-SNAPSHOT.jar ~/git/breakout-lwjgl/breakout/repo/

Great! Now our dependencies should all be working and… wait a minute… Now I’m getting a dependency error saying we’re missing javax.jnlp api. Ugh. So there’s a problem with all of this, and that’s you can only get the jnlp from javaws.jar. That’s a problem because that jar file is ONLY found in the oracle version of java. Ok, so we need some major changes to our environment to make this work. Sorry guys.

sudo apt-get install oracle-java7-installer

Ok, now we need to recompile our slick2d project with the new library.

export JAVA_HOME='/usr/lib/jvm/java-7-oracle/'
cd ~/git/slick2d-maven
mvn clean package

and copy it back to our repo…

cp ~/git/slick2d-maven/slick2d-core/target/slick2d-core-2013.08-SNAPSHOT.jar ~/git/breakout-lwjgl/breakout/repo/

And now our slick2d dependency is up to date. So now we need to modify our pom.xml file to reflect our new dependencies and where we get them from.

<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>

*sighs* You have no idea how long it’s taken me to figure this out. Also, if you notice any extraneous or incorrect elements in the future, please let me know.

So now we’ve got our updated dependencies, a fresh new oracle-java-7 install and a pom.xml file that should set everything up correctly. But Eclipse is still complaining. So we need to adjust our project settings.

project_propertiesnative_library_location_correctadd_library_add_jrealternate_jre_installed_jresadd_standard_vmjre_definition_add_external_jarsadd_javaws_jarswitch_to_java_7

At this point I found it necessary to restart eclipse so that my dependencies would take effect, but that might vary per environment. Doesn’t hurt, at least.

FINALLY! Now I am seeing no red warnings anywhere, so lets go ahead and finish up our code.

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();
	}
}

That’s the whole App.java file now. Note that we had to modify the OpenGL settings to support 2d textures and alpha channels (since we’re going to use a PNG).
Also, now instead of defining our poly size, we’re letting the size of the texture do that for us. So now pick a friendly PNG texture (I used a ball from a breakout game I’ve made previously) and put it into a folder called “res” in your project.
project_with_res

fire_ball

Now right click on the project and go to Run As -> Maven clean
maven_clean

You also might need to redo the native dependencies, so navigate to your project folder in the terminal and type

mvn nativedependencies:copy

if you don’t have them.

Then run maven install and everything should go smoothly. If it doesn’t at this point, send me a message or leave a comment! I learned a ton debugging these issues over the last several days so please ask for help instead of crying in your beer. Not that I did that.

With this, our project should be entirely set up and compiling with all it’s fancy dependencies… so let’s run it. Press the green Run App button in eclipse, and try out your fancy new moving image.

moving_ball_in_game

LWJGL 2D Breakout Tutorial – OpenGL drawing and keyboard input

Update: Just trying to get set up? Check out the streamlined setup tutorial LWJGL 2D Breakout Tutorial – Setup Summary.

This is the second post in a series, you should probably go back and read the first post. LWJGL 2D Breakout Tutorial – Environment Setup

Ok, so we were able to run our Hello World project that Eclipse created for us, but that’s not really anywhere close to making a game. So let’s make a window!

package breakout_lwjgl.breakout;

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

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

		Display.destroy();
	}

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

Sweet! Ok, let’s run this.

app_window_failure

Oh… that’s no good. I thought we had our environment set up correctly. It looks like it can’t find the libraries. We need to get the native local libs so we can run on my current machine. Luckily, we have maven! Open a terminal and navigate to your project location.

mvn nativedependencies:copy

This will find and copy all of the native libs we need to actually run a LWJGL project. But remember, running a maven clean after this will result in these files being deleted. You’ll have to copy them over again if you do a clean. (I wonder if there’s an easy way to automate this…)

Run maven install on your project through Eclipse, and when it’s completed, give it another try.

It’s alive! We have a LWJGL game window running and ready for our awesome code! So… what now? Let’s draw something. How about a square? We can use OpenGL to do this. Let’s add the import for it (import org.lwjgl.opengl.GL11) at the top and then put in some OpenGL code.
Replace the while loop in the previous code with this.

GL11.glMatrixMode(GL11.GL_PROJECTION);
		GL11.glLoadIdentity();
		GL11.glOrtho(0, 800, 600, 0, -1.0f, 1.0f);
		GL11.glMatrixMode(GL11.GL_MODELVIEW);

		while (!Display.isCloseRequested()) {
			GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

			GL11.glColor3f(0.4f, 1.0f, 0.4f);

			GL11.glBegin(GL11.GL_QUADS);
			GL11.glVertex2f(50, 50);
			GL11.glVertex2f(150, 50);
			GL11.glVertex2f(150, 150);
			GL11.glVertex2f(50, 150);
			GL11.glEnd();

			Display.update();
		}

little_green_square

Neat! It’s a little green square! Note here that I’m doing some things that will make 3D work a little tricker. But since I’m working on a 2D breakout for right now, this shouldn’t really matter.

In particular, I have set the ortho view to invert the y axis, so that the things I draw will have the top-left corner set to 0,0.

GL11.glOrtho(0, 800, 600, 0, -1.0f, 1.0f);

Ok, so a square is cool and all… but what about moving it around? Can it respond to the keyboard? Piece of cake! But now we’re getting into code and design philosophies, and I have a pretty strong opinion here. It is VERY ESSENTIAL to being programming your game with your drawing code and your update code COMPLETELY SEPARATE. Things could get messy the more complex your game is, and tracking down a bug where the user can only collide with something when he’s facing a particular direction is a nightmare to debug that I would never wish on anyone. So keep your logic and drawing code separate.

Here’s my updated version, with a few more functions to begin separating things out.

package breakout_lwjgl.breakout;

import javax.vecmath.Vector2f;

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

public class App {
	
	public boolean[] keysPressed = new boolean[255];
	public Vector2f squarePosition = new Vector2f();
	public Vector2f squareSize = new Vector2f();
	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.glOrtho(0, 800, 600, 0, -1.0f, 1.0f);
		GL11.glMatrixMode(GL11.GL_MODELVIEW);
		
		this.init();

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

		Display.destroy();
	}
	
	public void init() {
		this.squarePosition.x = 50;
		this.squarePosition.y = 50;
		this.squareSize.x = 100;
		this.squareSize.y = 100;
	}
	
	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.squarePosition.x -= 1.0;
		}
		if(this.keysPressed[Keyboard.KEY_RIGHT]) {
			this.squarePosition.x += 1.0;
		}
		if(this.keysPressed[Keyboard.KEY_UP]) {
			this.squarePosition.y -= 1.0;
		}
		if(this.keysPressed[Keyboard.KEY_DOWN]) {
			this.squarePosition.y += 1.0;
		}
	}
	
	public void draw() {
		GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

		GL11.glColor3f(0.4f, 1.0f, 0.4f);

		GL11.glBegin(GL11.GL_QUADS);
		GL11.glVertex2f(this.squarePosition.x, this.squarePosition.y);
		GL11.glVertex2f(this.squarePosition.x + this.squareSize.x, this.squarePosition.y);
		GL11.glVertex2f(this.squarePosition.x + this.squareSize.x, this.squarePosition.y + this.squareSize.y);
		GL11.glVertex2f(this.squarePosition.x, this.squarePosition.y + this.squareSize.y);
		GL11.glEnd();

		Display.update();
	}

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

This version has split out the init step, and then will call update before it calls draw. This means we have a chance to listen to input and update parameters every single frame.

Check out the next post in this series: LWJGL 2D Breakout Tutorial – Slick2D and images