SVG-based tower defense engine

Hi all,

I’ve written a tower defense engine in Java 6 using the GTGE library as game engine, and LWJGL as rendering engine.
Below are the specs of the engine :

TECHNICAL

  • LWJGL rendering
  • Tested on windows XP and various flavours of Linux (might even try solaris/x86 soon. LWJGL does not work with Solaris/SPARC… too bad)
  • Windowed or fullscreen modes
  • Screen resolution & ratio independence
  • Little JFC/Swing window at game startup to select resolution and windowed/fullscreen mode
  • Full SVG graphics EVEN FONTS (SVG files are rendered in-memory at game startup depending on resolution)
  • Black bars are added to top/bottom or left/right when playing fullscreen on non-16:9 screens
  • .properties files based game-content (no need to recompile to add/modify levels and tweak towers and enemies; possibility to easily create an add-on system)
  • Particles systems (flamethrower and laser beam)

GAME CONTENT

  • One level featuring 10 waves of enemies
  • A clone level to test the multi-level capabilities
  • A third level to try out the multi-spawn-points capabilities
  • A main menu with level selection and start/quit buttons
  • An incredible amount of different enemies (two of them !)
  • 4 different towers : Plasma tower (shoots fast and straight); Missile tower (shoots homing missiles); Laser tower (Laser beam with nice VFX); Flame tower (flamethrower)
  • Each tower can be upgraded 2 times
  • The player starts manually each wave of enemies
  • If one of the enemies reaches the end of the level, it’s “game over folks” and return to main menu

MISC. NOTES

  • I drew the sprites myself in Inkscape very quickly, and I suck as CG artist (meh is teh coderz), so they look ugly artistically speaking.
  • The game as-is is cheated as the two most powerful towers cost 1$ to build and upgrade (testing purposes) while the weakest one is 50$ to build, 100$ for lv2, and 200$ for lv3. Can be changed in .properties text files.

Basically, anyone able to draw pretty sprites with inkscape, and able to use a text editor, could “skin” the game to their likings, create new enemies, and use those in their own levels.

You can download it as a .zip file here : http://www.mediafire.com/?ymd2a3g8w5jdupx

Once unzipped, click TDV.bat or TDV.sh depending on your OS (Windows, or Linux. Mac users can modify the .sh to have it work on their systems).
If it doesn’t work, it probably means that java is not in your PATH. Edit TDV.bat to replace the word java by (for example) “C:\Program Files\Java\jre6\bin\java.exe”, keeping the quotes.

some screenshots or video might be nice (an encouragement to download and try it). A jws or applet version would also be nice.

From what I’ve seen the ppl here are rather lazy and usually only try a game if they have the above :slight_smile:

A pair of screenshots

http://img199.imageshack.us/img199/9066/tdvscreen1.png

http://img135.imageshack.us/img135/1350/tdvscreen2.png

Concerning JWS, I have to google it a little, and find hosting for my files I guess.
For the applet, I don’t know how native libs would integrate though.

Nice, game looks like its shaping up well. Personally i’d have picked Slick2D over GTGE but still if its working for you it should be good enough…

The top two hosts at the moment are GameJolt and Games4j.

For this you’d use LWJGL’s AppletLoader, it’ll deploy the natives for you, see the LWJGL Wiki for more info on this.

Cool stuff, technically that’s pretty impressive how you linked OpenGL graphics and SVG.

How did you do the inkscape integration? Using batik (http://xmlgraphics.apache.org/batik/) or is there something in the Golden T Game Engine that does it?

It actually doesn’t look too bad. Are gradients supported? If you throw in some radial gradients it will look a lot nicer. Bezier curves will also spruce it up, they’ll make it less square looking and modern.

Good job

[quote]How did you do the inkscape integration?
[/quote]
Using batik indeed. However, the batik jars’ hell made the download go from 3MB to 17MB… Maybe I’ll try using fatjar one day to shrink batik (if there’s no legal issues with that too).
There’s a .properties file containing for each sprite the svg file path, and a fixed width (or height) that is the sprite size in full HD (1920*1080). Depending on the chosen resolution, they are rendered in-memory by batik to the right size.

[quote]It actually doesn’t look too bad. Are gradients supported? If you throw in some radial gradients it will look a lot nicer. Bezier curves will also spruce it up, they’ll make it less square looking and modern.
[/quote]
Thanks, with time I came to like those sprites too, but I guess seeing them so often helped (oh, and the fact that I drew them myself too ^^ ). Everything in SVG that is supported by both Inkscape and Batik can be used for sprites, alpha channel included. I noticed that inkscape bitmap textures (like camouflage) do not work for example (inkscape extension). As said, I’m just a coder, and have no talent/wish/time to do “pretty” graphics.

[quote]Personally i’d have picked Slick2D over GTGE but still if its working for you it should be good enough…
[/quote]
GTGE’s development seems stalled ATM, but one or two coders are still working on it, and they are planning an interesting release feature-wise.
What I really liked in GTGE was a very simple integration of OpenGL : they implemented a Graphics2D subclass that implements the usual 2D functions with LWJGL or JOGL calls. I extended the LWJGL one to add additive alpha blending, and a little optimisation when the same sprite is to be rendered a lot of times at different places (particles !)

I’ll look at GameJolt and Games4j for JWS version, but I’ll keep the .zip release as it lets the user modify everything. Seeing the current game content, if some artist/game designer/level designer want to add stuff, I’ll be more than happy.
I don’t know if I’ll have time to add loads of code to it (working on another game, a much more ambitious project), but if anyone has ideas to turn the engine into a game, I can help.

Thanks for the explanation.

I’m wrestling with Batik and inkscape at the moment. I agree Batik is too fat. An interesting thing i saw KevGlass do in Slick2D is use java’s default XML reader to read the SVG files as Strings. Then using those strings, I just used a subset of batik to convert the path coordinate strings to java.awt.geom.Shapes. Here’s some code:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package svgloader;

import java.awt.geom.Path2D;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
import org.apache.batik.parser.AWTPathProducer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
 *
 * @author Keith
 */
public class Main {

	public Main(){
		InputStream in = this.getClass().getResourceAsStream("worldMapModified.svg");

		try {
			// From slick2D, which requires minimal batik packages:
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document doc = builder.parse(in);

			Element root = doc.getDocumentElement();
			String widthString = root.getAttribute("width");
			while (Character.isLetter(widthString
					.charAt(widthString.length() - 1))) {
				widthString = widthString.substring(0, widthString.length() - 1);
			}

			String heightString = root.getAttribute("height");
			while (Character.isLetter(heightString
					.charAt(heightString.length() - 1))) {
				heightString = heightString.substring(0,heightString.length() - 1);
			}

			float docWidth = Float.parseFloat(widthString);
			float docHeight = Float.parseFloat(heightString);
			System.out.println(this.getClass().getSimpleName()+": docWidth == "+docWidth);
			System.out.println(this.getClass().getSimpleName()+": docHeight == "+docHeight);

			NodeList nodeList = root.getElementsByTagName("path");
			int numPolygons = 0;
			int numPoints = 0;
			for (int i = 0; i < nodeList.getLength(); i++){
				Node node = nodeList.item(i);
				if (node instanceof Element){
					Element element = (Element)node;
					String dString = element.getAttribute("d");
					StringReader sr = new StringReader(dString);
					ExtendedGeneralPath egp = null;
					try{
						egp = (ExtendedGeneralPath)AWTPathProducer.createShape(sr, Path2D.WIND_EVEN_ODD);
					}catch(IOException e){
						e.printStackTrace();
					}
					// do something useful with the egp Shape object like draw it
				}
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static void main(String[] args){
		new Main();
	}
}

And then you can include just 3 or 4 small batik jars to make the AWTPathProducer work, rather than the whole batik distribution.

But I guess that because you’re rendering the SVG files to images on-the-fly you need batik’s rasteriser and therefore all of the jars. But you could cache the images and use the SVG tag info to figure out where to paint the cached images then you could do away with the bloated batik jars.

That is pretty cool

[quote]I’m wrestling with Batik and inkscape at the moment
[/quote]
Just an advice then, in Inkscape, always use “Save as”, and select “SVG (Plain)” as format and not the inkscape svg. Inkscape will complain about loss of information, but these information would not be readable by Batik.

[quote]An interesting thing i saw KevGlass do in Slick2D is use java’s default XML reader to read the SVG files as Strings.
[/quote]
Well, I used Batik because I don’t want to parse SVG myself and call the drawing primitives accordingly. I’m way too lazy.

[quote]But I guess that because you’re rendering the SVG files to images on-the-fly you need batik’s rasteriser and therefore all of the jars.
[/quote]
Indeed, but why the hell do I have to include “pdf-transcoder.jar” to my classpath for rasterization ??? >:(

Caching the images would imply to select a set of available resolutions, and I want to be as system-agnostic as possible. Wanna play fullscreen on a 7681024 screen ? possible. Wanna play on a 2K2K ? possible. I use a fixed set of resolutions for Windowed mode (only 16:9 resolutions), but for fullscreen, I get the available modes directly from the system.
However, downloading the sources of Batik and importing it as an eclipse project would enable me to use the Fatjar addon that will crawl in the code, and create a single jar with all used classes. If batik uses Class.forName(), then I’m doomed. :o

Slick supports loading a subset of SVG with a custom loader.

Kev