Thursday, October 27, 2011

Slick Applet

I wanted to take the game that I'm creating and run it as an applet.  Slick actually makes it very easy to do so, but the hard part is gathering all the information you need to do it.  I thought I would post everything I had to do to get it to work.  Hopefully it will help someone else from hours of research to get it to work.

The great part about slick is once you get your game running as an application, you don't have to change a single line of code to run it as an applet. You just have to set things up properly (jars, html, etc). I'll assume that you have your game already functioning and just describe how to get that game to run as an applet.

First, you should get the necessary jar files.  I went straight to Lwjgl's download site and found the lwjgl_applet.zip file.  I copied all of these jar files into my applet folder (/var/www/myApplet for me because I'm using apache on linux).  You will also need to copy your slick.jar file in there.

Next up, you'll need to compile your game into a jar file.  I used an ant script to take care of that.  Here is what my build and jar targets look like:

    <target name="build" description="build library">
        <mkdir dir="build"/>
        <javac includeantruntime="false" srcdir="src/"
               encoding="utf-8" includes="**" destdir="build/" source="1.5">
            <classpath>
                <pathelement location="lib/lwjgl.jar"/>
                <pathelement location="lib/slick.jar"/>
            </classpath>
        </javac>
    </target>


    <target name="jar" depends="build">
        <mkdir dir="dist"/>
     <jar destfile="dist/rpg.jar">
      <fileset dir="build" includes="**"></fileset>
             <fileset dir="." includes="media/**"></fileset>
     </jar>
    </target>

My jar target needed to include all of the classes that were compiled (in the /build folder) and all of the media that my game uses (images, sounds, etc. located in the /media folder).  This creates a jar file (named rpg.jar) in the /dist directory.  Now we can copy that to our applet folder.

Next we need to create an html file to tell the browser how to load the applet.  Here is the html I used:

<html>
 <body>
  <applet code="org.lwjgl.util.applet.AppletLoader"
    archive="lwjgl_util_applet.jar"
    codebase="."
    width="800" height="600">
  
    <param name="al_title" value="AppletTitle">
    <param name="al_main" value="org.newdawn.slick.AppletGameContainer">
    <param name="game" value="myPackage.MyMainClass">  
  
    <param name="al_jars" value="rpg.jar, lwjgl.jar, slick.jar">
  
    <param name="al_windows" value="windows_natives.jar">
    <param name="al_linux" value="linux_natives.jar">
    <param name="al_mac" value="macosx_natives.jar">
  
    <param name="separate_jvm" value="true">
  </applet>
 </body>
</html>

Now that we have that part. The only thing that is left is to sign the jar files. I guess you don't really need to sign them, but its probably a good idea. A keystore for signing the jar files can be created by using the keytool that comes with the jdk:
$> keytool -genkey -alias mykey -keystore .keystore
Then sign each of the jar files in the directory:
$> jarsigner -keystore .keystore -storepass <password> -keypass <password> <jarfile.jar> mykey

That's all there is to it. Now use your browser to hit your applet.html file. It is also a good idea to turn on the java console for debugging purposes. In linux you should be able to type 'ControlPanel' in the terminal and find the 'Show Console' option. In windows? Idk, google should help.

Hopefully this saves some time for others creating a slick applet.

Saturday, July 23, 2011

Unicode Font

Today I needed to draw text to the screen.  It is fairly simple, just use graphics.drawString("text", xPixel, yPixel).  However, I ran into a problem when I wanted to create my own font so that my text would be larger.  I first used slick's TrueTypeFont class.  It was easy to use, and before long I could draw the text with the right size:

TrueTypeFont font = new TrueTypeFont(new java.awt.Font ("Verdana", Font.BOLD, 20), false);
...
graphics.setFont(font);
graphics.drawString(...);
OR
font.drawString(....);

The only downside is TrueTypeFont is deprecated.  Technically it is still usable, but using deprecated classes or methods rubs me the wrong way.  The API says to use the UnicodeFont class instead.  After some research I also learned that the UnicodeFont class is more efficient.

I assumed that UnicodeFont would work as simply as TrueTypeFont, but I was mistaken.  I modified my code to use UnicodeFont, but once I did that it stopped drawing the text.  After some research I learned that I can't just create the font, I also have to create an Effect, add the glyphs and load the glyphs.  But I just want to make the text a little bigger!</aggravated lament>  Loading the glyphs gives this class an advantage by being able to only load the characters you need.  However, this seems way to difficult for someone that just wants to make their text a little bigger.  My two simple lines of code for creating a TrueTypeFont and setting that font became 5 lines of code that are a lot harder to read and understand:

UnicodeFont font = new UnicodeFont(new java.awt.Font ("Verdana", Font.BOLD, 20)); font.getEffects().add(new ColorEffect(java.awt.Color.white);
font.addNeheGlyphs();
font.loadGlyphs();
graphics.setFont(font);

Maybe I'm just picky, but I don't want to stick this ugly block of code in every place that I just want to make my text a little bigger.  So, I created a class that abstracted out all of the ColorEffect/Glyphs/Confusingness.  Now when I want to make my font a little bigger I can just use:

SimpleFont font = new SimpleFont("Verdana", Font.BOLD, 20);
graphics.setFont(font.get());

Plus I still get some of the efficiency benefits that UnicodeFont offers by only loading the core ascii characters.  Hopefully my research will save others time in drawing their text just a little bigger.  Here is the SimpleFont class I created:


import org.newdawn.slick.SlickException;
import org.newdawn.slick.UnicodeFont;
import org.newdawn.slick.font.effects.ColorEffect;
import java.awt.Color;
import java.awt.Font;
public class SimpleFont {
    private UnicodeFont font;
    public SimpleFont(String fontName, int style, int size, Color color) throws SlickException {
        this(new Font(fontName, style, size), color);
    }
    public SimpleFont(String fontName, int style, int size) throws SlickException {
        this(new Font(fontName, style, size));
    }
    public SimpleFont(Font font) throws SlickException {
        this(font, Color.white);
    }
    public SimpleFont(Font font, Color color) throws SlickException {
        this.font = new UnicodeFont(font);
        ColorEffect colorEffect = new ColorEffect(color);
        this.font.getEffects().add(colorEffect);
        this.font.addNeheGlyphs();
        this.font.loadGlyphs();
    }
    public void setColor(Color color) throws SlickException {
        font.getEffects().clear();
        font.getEffects().add(new ColorEffect(color));
        font.clearGlyphs();
        font.addNeheGlyphs();
        font.loadGlyphs();
    }
    public UnicodeFont get() {
        return font;
    }
}