Magnetic Transports: Progress

< All, 1, 2 >

Magnetic Transports: v1.0

I thought a bit about it, and I couldn't find anything left to do with Magnetic Transports after this update. Hence I have decided to elevate it to version 1.0 and call it finished.

So what has been done to finish the project?

  • Replaced the directions in the launch dialog with arrows.
  • Event animations have been introduced.
  • Transports crashing now have an event animation.
  • The options dialog has been tabbed as the previous version bombarded the user with choices and didn't look too good.
  • The thread issue with the win32 version of the game has been resolved, it should work fine now.
  • Users can now remove unwanted magnets with the new bulldozer button in the button tray.
  • A readme has been written.

I'm not going to comment too much on the changes. I will just say that the crash animation doesn't look like a crash, blame my lack of graphical interest.

Time to sum up the project. It took about a month, although I was a bit lazy in the beginning. The project did give me some experience with JOGL and did brush up my OpenGL. I must say that JOGL is a good OpenGL library and enables a lot of interesting OpenGL powered java possibilities. It would be interesting to make an OpenGL powered 3D game in java, just to show that it works, although someone has probably already done that.

The other big new part of the project was JRE 1.5 (or 5.0 to make marketing happy). All in all it was great to see that Java can still evolve and become even better, it has become increasingly hard to produce runtime errors by mistake. My favorite changes are generics and typesafe enums, the rest just feel like ways to save a couple of lines.

I guess it's time to come up with a new project again (suggestions are welcome).

Version 0.7: Precompiled binaries

The new things in Magnetic Transports version 0.7:

  • Native precompiled binaries released.
  • Games can now be saved (and loaded).
  • Gliders can now be launched in eight directions from the landing pads instead of just one.
  • The Configuration class has taken over the responsibility for a lot of fields that were previously hard coded static final.
  • User can now define all configurable values held by Configuration.

The native precompiled binaries are available in the download section, just keep in mind that the project is still very much in the development stage. The different versions basically consist of the same jar files but with different native JOGL bindings. The reason that I split them up is that each of the bindings take up about one MB and I opted for making three native 1.5 MB packages instead of one universal 3.5 MB release. As a result one would think that if one package worked then all would work (as one can assume JOGL is fairly well tested), but surprisingly that is not the case. The Linux version should work well as it is the one that has been tested during development. I have no possibility to test the MacOSX package as I don't have access to such a platform. The surprising thing (or maybe not) is that the win32 package does some very strange things when I tested it, the game window opens up and all but no listeners are ever notified of anything (hence nothing happens). This would suggest that there is some thread issue or something even stranger going on in the win32 version, I will look into it when I get the time. However making a precompiled version that works on windows is not a huge priority for me until the game is fully developed.

One thing that I found annoyingly hard though was to set things up so that users would just have to run the jar file to run the game. Therefor I'm going to share how I did it in case someone wants to know:

How to package JOGL so it doesn't have to be installed by the user.

This is how I set up the releases: I have the game's jar file (only containing the game) in the main dir, then I have a dir named lib in which I put the jogl.jar and the native bindings (libjogl.so, libjogl_cg.so in linux). There are two problems that have to be dealt with in order to get the game to launch (assuming that the user does not have JOGL installed in the JRE), a simple one: put jogl.jar in the classpath, and a harder one: put the lib dir in the library path (and then load the libraries).

The solution to the first one should be well known, just put "Class-Path: lib/jogl.jar" in the manifest. As far as I know there is no simple manifest solution to the second problem, so one has to modify the library path via System's java.library.path. But the value is basically read only while running a program so one has to use a trick.

private static final String LIB_DIR_NAME = "lib";
[...]
//Set the library path and load the jogl library.
try {
	//Reset the "sys_paths" field of the ClassLoader to null.
	Class clazz = ClassLoader.class;
	Field field = clazz.getDeclaredField("sys_paths");
	boolean accessable = field.isAccessible();
	if(!accessable) {
		field.setAccessible(true);
	}
	Object original = field.get(clazz);
	try {
		//Reset it to null so that whenever "System.loadLibrary" is 
		//called, it will be reconstructed with the changed value.
		field.set(clazz, null);
		
		//Get the base dir of the program.
		String basePath = System.getProperty("user.dir");
		//get the system dependent file separator.
		String fileSeparator = System.getProperty("file.separator");
		//Get the system dependant path separator.
		String pathSeperator = System.getProperty("path.separator");
		//Get the current library paths.
		String libPaths = System.getProperty("java.library.path");
		//Create the path to our library dir.
		String libDir = basePath + fileSeparator + LIB_DIR_NAME;

		//Append our library dir to the existing library path.
		System.setProperty("java.library.path", libPaths + pathSeperator + libDir);
		//Load the libraries.
		System.loadLibrary("jawt");
		System.loadLibrary("jogl");
	} finally {
		//Revert back to the original.
		field.set(clazz, original);
		field.setAccessible(accessable);
	}
} catch(Exception e) {
	e.printStackTrace();
}

Yes, it is dirty and probably shouldn't be used it if there was another way. However I'm yet to find a better way to do it. I might replace it with something other in the future, but it's not on the top of my priority list as the project is still in development.

The side effect of this is that the jar has to be launched from the directory it resides in. I.e. the libraries will not be loaded if the user does something like "java -jar magnetic-gliders/magnetic.gliders.jar", double clicking and so on does execute from the correct directory.

So that is it, those two things should enable users to run the jar file directly without any webstart or installation of native bindings.

Back to the new features:

magtransports_news12.jpg

This is the new launch dialog. North is up on the screen and so on, so the transports launch in the physical direction of the button. This should remove the luck that was involved in map generation, the game used to become a whole lot harder if all transports were stuck on the east side of the map.

magtransports_news11.jpg

All static final fields that should be user configurable were moved to a new enumeration in the Configuration class. Then all those enumerations were projected onto the configuration dialog. This of course enables the user to make the game trivial, or excruciatingly hard, the choice is meant to be free.

magtransports_classes9.gif

The class diagram has also been updated, there were hardly any structural changes in the code to talk about (which is to be expected at this stage). The new changes are mostly reflected in the javadoc, which is quite large too.

I'm almost out of new things to do now *cough* event animation *cough*. So I will mostly focus on improving things from here on.

The barrage continues: version 0.6

Magnetic transports is now good enough for me to start building some real versions that function fairly well. The new version (0.6) doesn't bring a lot of changes to the game, rather it extends and improves the user interface.

Some of the changes:

  • The game window can now be resized during play.
  • A button tray has been introduced to the game's viewport. The button tray contains buttons that enable the user to place magnets.
  • A config file has been introduced, it currently holds basic information like preferred game field size, but I have more planned for it.
  • A game menu has been added.
  • The source is now too large to be handled as one package, it has been split into five packages instead.
  • The color code of the map grid power overlay has been changed.
  • A lot of various bug fixes, most associated with the map grids and the view of the game field.

One other thing that I wanted to have done for this release was compiled binaries, sadly the complications which distributing code that relies on native binding brings will delay it. JOGL requires native libraries containing the OpenGL bindings to run, that is not much of a problem though since Ant is more than happy to give me three native distributions instead of one. However I have not been able to successfully load the distributed native bindings yet. I'm sure it is quite easy and that I will have it solved as soon as I get some time to take a look at it, but not for this release I'm afraid.

magtransports_classes8.gif

The class diagram has been changed to reflect the division into packages. It is quite large now.

Time for some various screenshots.

magtransports_news8.jpg

This is the new menu. It is very simple at the moment, but it works. I plan on adding some graphics to it in the future, I might also add some more options.

magtransports_news9.jpg

The new button tray is in the top left of the game field. I decided to use the canvas to draw the buttons (rather than making separate buttons) as it fitted nicely into the existing code.

An image of the color changes to the map grids can be found in the project's image section.

The game is starting to take shape now, although there's still a whole lot of work to do. I'm at the point where I feel that I wont bring much new into the project, rather the future work will focus on improving the current contents. I do however have one new thing that I will have to include at some point: the event animation. I'm probably going to ignore it for a while though as it requires making a lot of new graphics, which I don't enjoy.

Prototype 5 accomplished

The title might not be a good one but I had a hard time thinking of a fifth synonym. The fifth and last prototype includes three additions.

  • A scrollable game field.
  • Win conditions.
  • A generator capable of randomly generating play fields of specified sizes.

The scrollable game field took the most time. I must have tried at least five different approaches until I finally found one that worked (although not as elegant as some of the things I tried). I first thought that there were some elegant way to do it in OpenGL, and there is probably, but I couldn't find it (or at least couldn't make it work properly). Instead I had to make a new Camera class to handle the scrolling and translations between screen coordinates and field coordinates. The game field is scrolled by dragging the mouse while holding the right mouse button pressed.

magtransports_classes7.gif

You can see the new Camera class above the MagneticSource interface. It is the only major change so nothing too exciting.

The win conditions part was very simple. Basically one wins by having a single transport manage to dock with each landing pad, hence proving that one has created a communication net through which a transport can glide from each pad to all other. The result is that every transport records where it has been.

Building the game field generator was fairly easy but still quite fun. Here is an example of a part of a generated play field.

magtransports_news7.jpg

I scrapped the initial idea of randomly trying to place landing pads one by one while checking that they are far enough apart. The reason was that it would take a lot of trials to get the last pads placed if the initial placements were unlucky (or rather very spread out). Instead I opted for a recursive depth first random placement algorithm. It basically works by starting of by placing a pad at a random sport, then the recursion starts. It select a random angle from the parent and then tries to place a child at the minimum distance from the parent in that direction. If it succeeds then the recursion continues until there are no longer any valid places to place a child. The process is then backed one step to the parent of the child that tried the recursion, that parent tries to place a second child and continue recursing through it. And so it goes on until there are no places left in the game field where a pad can be placed (as the recursion has backed up all the way to the root, trying to place more children along the way without success). That type of recursion is commonly called depth first, hence the name of the algorithm.

magtransports_gen_algo.gif

This image is an attempt to graphically show the algorithm. The blue dots are landing pads and the black circle around them represents the minimum distance that each landing pad has to have to all other pads. The circles are above all circles that were placed after them, hence the circle in the middle above all other circles was the first that was placed. Then you can see a kind of backbone of circles emanating from that circle, and then shorter branches emerge from the backbone. In the end everything has been covered and no more landing pads can be placed.

I did not try something as elaborate for the mountains, I just randomly placed them as they do not have any restrictions of minimum distance to other mountains (just a short minimum distance to other entities).

The next step will be to start building the actual game. I have a few things on my todo list, but more things will probably pop up.

  • Allow resizing of the game window during play (without causing size problems).
  • Implement some kind of event animation, an complex animation that only loops once until it hands over to some other sprite. These would be used when a transport crashes or docks with a landing pad.
  • A way to place magnets is needed (i.e. a tool bar or maybe a key command).
  • A config file of some sort for configurable values (I will probably use the classes I made for Multipurpose Log Filter).
  • Some kind of game menu so a player can access it.

Prototype 4 finished

The new features:

  • Mountains (or maybe big boulders is a better description) have been introduced.
  • Transports can now crash with for instance other transports, mountains and magnets.
  • Transports can now dock with landing pads.
  • Landing pads can now launch docked transports.
  • A way to visually see the map sectors' powers has been introduced.

magtransports_news4.jpg

Here is an example of a big boulder. The big boulders have the same polarity as the ground, hence it acts as a low power repellent versus transports. Unfortunately a fully powered attracting magnet has been placed next to the boulder, so transports are sucked in anyway.

magtransports_news5.jpg

Here we got a couple of examples of crashed transports. The crashed transports will just lie there for the rest of the game. The bad part about crashing transports is that the crashed transports are still active magnets (repelling other transports), they are also obstacles that other transports can crash into. A new dialog is also displayed, it is brought up by double clicking one of the big metal landing pads. The dialog allows the player to launch docked transports from the landing pad. There will be an limited amount of transports in the game so it's better to think first and launch later.

magtransports_news6.jpg

The grid pattern displayed is the new visual overlay describing the map sectors' different power levels. The power levels fluctuate and gradually change over time, hence it's important to take a look at the overlay every now and then by pressing the tab key. The lighter the zone the higher power level. The power level decides the amount of acceleration force provided by the sector to the transport, so a flight path that once worked might not work five minutes later (although it should only take a couple of tweaks to guiding magnets to make it work again). The visual overlay was not originally part of prototype 4 but the rest went too fast so I added some more to it.

magtransports_classes6.gif

The class diagram is about the same as last time, a few classes have grown a bit and some minor classes have been added. The only notable change is that I decided to change the way the interface Configurable works. The interface, which is now named DialogDisplayer, provides a complete dialog instead of the building blocks to make one. It gives the class implementing DialogDisplayer a bit more control and enables them to make higher customized dialogs at a low cost of a bit more (but less confusing) code.

I'm not really sure how hard the next (and last) prototype will be. The win condition part is obviously, with docked transports, a piece of cake but the map generation is something I have never done before. I guess it all depends on how good I want the generator to be. The main thing that I have in mind is to basically let it place things out at random with X landing platforms at minimum distance from each other. Then it will have to make sure that there are no trivial paths. I'm not sure how good maps that will create, but I suspect that I will have to rethink the concept once or twice. I will also add some kind of scrolling functionality to prototype 5 as it will be needed in the game.

< All, 1, 2 >