Skip to content

Instantly share code, notes, and snippets.

@Darkhogg
Last active September 28, 2015 16:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Darkhogg/1467056 to your computer and use it in GitHub Desktop.
Save Darkhogg/1467056 to your computer and use it in GitHub Desktop.
Scaffolding for a Slick2D game for Ludum Dare
Generic scaffolding for fast deploying of Slick2D games.
* Includes a `Main` class with a `main` method that serves as an entry point for applications.
* Includes a class within `Main`, `Main$WrapperGame`, which wraps the actual `Game` implementation for use with the Slick2D `AppletLoader` class, which also serves as a common starting point for the `main` method.
* Includes an automatic modification of the `java.library.path` system property which *adds* the path `lib/natives-*system*` to the path, where *system* is one of `linux`, `windows`, `mac` or `solaris`.
* Includes a basic class `MyGame` ready to be filled with the game implementation.
* Includes an HTML file with an applet ready to be used.
* Includes an Ant buildfile ready to be executed, which generates an executable JAR file, a ZIP containing that JAR and the `lib` folder, and a `README.txt` file, if present; and another ZIP file with the `src`, `res` and `lib` folders.
To start working with this, you will need to refactor the included classes. Be careful to update all references to the classes. For your own convenience, everything is packed so that the only thing references from the outside is the `Main` class.
The applet and buildfile assumes the following directory tree:
```
/
src/
**/*.java
res/
bin/
**/*.class
lib/
applet/
*_natives.jar
lwjgl_util_applet.jar
natives-*/
*.(so|dll|...)
*.jar
README.txt
```
In summary:
* The source files goes in a `src` directory, with the typical structure of a Java source folder
* Any resources which are not Java sources goes under the `res` directory
* The compiled Java classes *AND* a copy of the resources goes under the `bin` directory. This is the only directory that enters the JAR file.
* The LWJGL and Slick JAR files goes under the `lib` directory
* Native JAR files and the LWJGL applet JAR goes under `lib/applet`
* Native librearies goes under `lib/natives-*system*`
# Dependencies
The obvious dependencies are LWJGL and Slick2D. An extra dependency is the `OperatingSystem` class, which you can find here: <https://github.com/Darkhogg/DhJavaUtils/blob/master/src/es/darkhogg/util/OperatingSystem.java>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>MyGame</title>
<style type="text/css">
body {
background: #333;
color: white;
}
a {
color: red;
text-decoration: none;
}
b {
font-style: italic;
}
</style>
</head>
<body>
<applet
code="org.lwjgl.util.applet.AppletLoader"
archive="lib/applet/lwjgl_util_applet.jar"
codebase="."
width="640" height="480" >
<param name="al_title" value="MyGame"/>
<param name="al_main" value="org.newdawn.slick.AppletGameContainer"/>
<param name="al_jars" value="Game.jar, lib/lwjgl.jar, lib/lwjgl_util.jar, lib/jinput.jar, lib/slick.jar, lib/slick-util.jar"/>
<param name="al_logo" value="appletlogo.gif"/>
<param name="al_progressbar" value="appletprogress.gif"/>
<param name="game" value="Main$WrapperGame" />
<param name="al_windows" value="lib/applet/windows_natives.jar"/>
<param name="al_linux" value="lib/applet/linux_natives.jar"/>
<param name="al_mac" value="lib/applet/macosx_natives.jar"/>
<param name="al_solaris" value="lib/applet/solaris_natives.jar"/>
<param name="separate_jvm" value="true"/>
</applet>
<p>
Description goes here
</p>
</body>
<html>
<project name="MyGame" default="all">
<property name="dir.src" value="src" />
<property name="dir.res" value="res" />
<property name="dir.bin" value="bin" />
<property name="dir.lib" value="lib" />
<property name="file.jar" value="Game.jar" />
<property name="file.zip.bin" value="Game-Bin.zip" />
<property name="file.zip.src" value="Game-Source.zip" />
<!-- Builds a JAR file containing all classes -->
<target name="jar">
<!-- generate the classpath -->
<manifestclasspath property="classpath" jarfile="${file.jar}">
<classpath>
<fileset dir="${dir.lib}" includes="**/*.jar" />
</classpath>
</manifestclasspath>
<!-- generate the JAR -->
<jar destfile="${file.jar}">
<fileset dir="${dir.bin}" includes="**" />
<manifest>
<attribute name="Main-Class" value="Main" />
<attribute name="Class-Path" value="${classpath}" />
</manifest>
</jar>
<!-- Add executable permissions to the owner of the JAR -->
<chmod perm="u+x" file="${file.jar}" />
</target>
<!-- Builds a ZIP file containing the generated JAR and the library folder -->
<target name="zip-bin" depends="jar">
<zip destfile="${file.zip.bin}">
<fileset dir="." includes="${dir.lib}/**,${file.jar},README.txt" excludes="**/applet/**" />
</zip>
</target>
<!-- Builds a ZIP file containing the library, source and resources folders -->
<target name="zip-src">
<zip destfile="${file.zip.src}">
<fileset dir="." includes="${dir.lib}/**,${dir.src}/**,${dir.res}/**,README.txt" excludes="**/applet/**"/>
</zip>
</target>
<!-- Builds everything -->
<target name="all" depends="jar,zip-bin,zip-src" />
</project>
import java.lang.reflect.Field;
import org.lwjgl.Sys;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.Game;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.ImageBuffer;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.imageout.ImageOut;
import org.newdawn.slick.util.Log;
import es.darkhogg.util.OperatingSystem;
/**
* A class that serves as an entry point for the game
*/
public final class Main {
/**
* Modifies the <tt>java.library.path</tt> system property so it contains the appropriate folder with the LWJGL
* natives
*/
private static void setupLibraryPath () throws SecurityException, NoSuchFieldException, IllegalAccessException {
OperatingSystem os = OperatingSystem.getCurrent();
// If the OS is supported by LWJGL (Linux, Mac, Windows, Solaris)
if ( os == OperatingSystem.LINUX | os == OperatingSystem.MAC | os == OperatingSystem.SOLARIS
| os == OperatingSystem.WINDOWS )
{
String dirname = "natives-" + os.getName().toLowerCase();
String pathsep = System.getProperty( "path.separator" );
String dirsep = System.getProperty( "file.separator" );
String oldlibpath = System.getProperty( "java.library.path" );
// <oldpath>;lib/natives-os
String newlibpath = oldlibpath + pathsep + "lib" + dirsep + dirname;
System.setProperty( "java.library.path", newlibpath );
// Propagate the change
Field fieldSysPath = ClassLoader.class.getDeclaredField( "sys_paths" );
fieldSysPath.setAccessible( true );
if ( fieldSysPath != null ) {
fieldSysPath.set( System.class.getClassLoader(), null );
}
}
}
/**
* Launches the game using an <tt>AppGameContainer</tt>
*
* @param args
* Command line arguments, currently ignored
*/
public static void main ( String[] args ) {
try {
setupLibraryPath();
AppGameContainer container = new AppGameContainer( new WrapperGame() );
container.start();
} catch ( Throwable ex ) {
fatal( ex );
}
}
/**
* Prints the exception in the console and an alert window and exits
*
* @param ex
* The exception that caused the fatal error
*/
/* package */static void fatal ( Throwable ex ) {
Log.error( ex );
Sys.alert( "Fatal Error", "fatal error ocurred during game execution: " + ex.toString() );
System.exit( 1 );
}
/**
* A class that wraps the main game class so both the application and applet have a common entry point
*/
public static final class WrapperGame implements Game {
private final Game game = new MyGame();
private Image buffer = null;
private Input input = null;
@Override
public boolean closeRequested () {
return game.closeRequested();
}
@Override
public String getTitle () {
return game.getTitle();
}
@Override
public void init ( GameContainer cont ) throws SlickException {
cont.setForceExit( false );
cont.setShowFPS( true );
game.init( cont );
}
@Override
public void update ( GameContainer cont, int delta ) throws SlickException {
if ( input == null ) {
input = cont.getInput();
}
if ( input.isKeyPressed( Input.KEY_F12 ) ) {
long millis = System.currentTimeMillis();
String ssname = "screenshot-" + millis + ".png";
Log.info( "Saving screenshot in '" + ssname + "'" );
ImageOut.write( buffer, ImageOut.PNG, ssname );
}
game.update( cont, delta );
}
@Override
public void render ( GameContainer cont, Graphics gr ) throws SlickException {
if ( buffer == null ) {
buffer = new ImageBuffer( MyGame.WIDTH, MyGame.HEIGHT ).getImage( Image.FILTER_NEAREST );
}
Graphics bufgr = buffer.getGraphics();
game.render( cont, bufgr );
gr.drawImage( buffer,
0f, 0f, MyGame.WIDTH*MyGame.SCALE, MyGame.HEIGHT*MyGame.SCALE,
0f, 0f, MyGame.WIDTH, MyGame.HEIGHT );
}
}
}
import org.newdawn.slick.Game;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
public final class MyGame implements Game {
/* package */static final int WIDTH = 320;
/* package */static final int HEIGHT = 240;
/* package */static final int SCALE = 2;
@Override
public boolean closeRequested () {
return true;
}
@Override
public String getTitle () {
return "MyGame";
}
@Override
public void init ( GameContainer cont ) throws SlickException {
}
@Override
public void update ( GameContainer cont, int delta ) throws SlickException {
}
@Override
public void render ( GameContainer cont, Graphics gr ) throws SlickException {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment