Advanced Java Game Development: Introduction
The Joy of Debugging
We ended up writing our own focus controller thread and calling it explicitly anytime the player moved to a new window or clicked a new component.
With sound, for example, we found that anytime the system produced a tone at the same time as one of our games, the entire Virtual Machine would crash. If you got an e-mail beep while wasting time with Backgammon, your system went up in smoke. We fixed this by basically hijacking the Java sound system and playing a continuous, empty sound loop. The sound of silence, if you will. This made it impossible for other applications to get their audio foot in our door. A regrettable thing to do, but desperate times... .
Java also did highly annoying things with images. A simple GIF image, for example, should only take up 8-bits of color information per pixel. But Java sapped a full 32-bits, keeping a copy of the image cached and keeping enough room for colors that couldn't exist. Also, images bigger than 16 Megs couldn't be created if you were using a large color depth. Most business applications would never care about this boundary, but our real-time strategy game's background map certainly did. And so we had to break large images into multiple files and piece them together programmatically. We also had a stock of problems with animated GIFs. GIF89a images would often starve other threads, display garbled, or crash the system entirely. It took a few generations of Java before these suckers worked adequately.
Other big bugs involved focus. The default focus behavior changed from Java version to Java version. We ended up writing our own focus controller thread and calling it explicitly anytime the player moved to a new window or clicked a new component.
Java classes, all in all, are difficult to debug. Better and better profiling, optimization, and debugging tools are constantly being introduced. But back in the old days, it was pretty much impossible to tell how much memory our games were taking up, whether there was a memory leak, or where leaks originated. Only by using brute force and careful observation were we able to track some obstinate offenders.
At times, exceptions would appear somewhere deep in the Java libraries. These were totally out of our control. We would then be forced to trace the origin of the problem and code a way around the chasm. This called for lots of strange kluges and non-obvious solutions. But it was good fun, in any case.
We developed our Java games on Windows NT. Our earliest arcade applets worked pretty well when tested in the latest browsers on Macintosh, Windows 95, and Solaris.
We faced the law of bug interdependency: Fix a bug on one system, create a bug on another.
But as the games became more complex, with more-hungry threads, teetering data structures, and raging sockets, big problems cropped up. As it turns out, threads are handled differently from machine to machine. Getting focus means different things to different operating systems. Microsoft's Java would constantly wage small battles of code semantics against Sun's Java. Not to mention a Macintosh JVM versus Linux.
We faced the law of bug interdependency: Fix a bug on one system, create a bug on another. To bypass this law, we would isolate problems to a specific patch of code and then sniff the platform or JVM vendor using
. We'd then run a simple switch-case series and treat components, threads, or images in different ways depending on where they were running.
Deployment EaseSince PlayLink was originally developed in Java 1.0, there was no way to sign applets. This meant that a user would have to download the entire game every time she returned to our site. Since our main lobby classes and graphics were about 3 Megs, this was an unpleasant proposition. We were also trapped in by applet security. We needed to access system properties and read from and write to the user's hard drive.
So we chose to distribute PlayLink as an application. This meant users had to download our files only once. But they also had to download a Java Runtime Environment. Unfortunately, Sun's JRE 1.1.7 distribution installer is 2.6 Megs. Microsoft's version of Java they call it JView is an even bulkier package. It was a bit of a heavy toll to pay for a simple game of checkers. Then we realized that most of our users were on Windows 98 or had Internet Explorer 5.0 installed. This meant they already had JView on their systems. So we had our installer detect for JView and utilize it if a high enough version was found.
The other big advantage to making PlayLink an application was much tighter control. As difficult as it was to code for different platforms, it was a piece of apple strudel compared to testing our games on every version of browser and JVM configuration. This helped us guarantee that the user's experience would be as fun as our own.
And so?All in all, we are glad we used Java for our games. We believe all the up-front hassles and work were worth it and that we now have a stable, easily expandable system. In future articles in this series, we'll talk about using Java for client/server game networking, ways of enacting smooth high-performance animation using Java, and we'll analyze PlayLink's Citizen 01, which I believe is one of the most advanced games ever programmed using Java technologies. Until then....
Part II of this series: Advanced Java Game Development: State Data
About the AuthorDavid Fox is vice president of Games at PlayLink, Inc. He's also the author of numerous books and articles about cyberculture and technology.
Page 2 of 2