We have all heard entirely too much about Java and Javascript.
Java is an "object-oriented, type-safe, dynamically loaded,
garbage collected, multithreaded programming language," loaded
with powerful features, suitable for the design of amazingly sophisticated
applications, currently mostly used to make silly games.
Javascript is an "object-oriented scripting language,"
suitable for double-checking what the user has typed into an
HTML form or generating a large HTML table using a simple loop,
currently mostly used for just that.
You may feel this is a point in Javascript's favor: Javascript does
what it is supposed to do, and does it reasonably well,
and does it today. But I don't see it that way. What
I see here is a silly games gap.
Javascript Deserves Silly Games
Until recently, it was widely believed that Javascript was
not suitable for writing silly games. Sure, there's the
occasional version of Hammurabi or Minesweeper out there,
but there are very few live action games written in Javascript.
I recently decided to take matters into my own hands
and correct this unfortunate oversight. After all,
writing silly games in a sooper-dooper amazing language
like Java is too easy. The really fun stuff happens when
you push a language beyond what it was intended to do.
Nifty Javascript Secrets
"Geek: Game of Champions" takes advantage of a few crucial
features of Javascript that make an action game just
barely possible. The first is the handy function
setTimeout, which can be used to
do something after a certain period of time. Here's
a simple example:
setTimeout(1000, "Confirm('One second has elapsed');");
This line of Javascript pops up a message dialog box, but it
doesn't do it right away; it does it one second (1000 milliseconds)
later. This feature is important because it allows the game
to move the "geek" and her opponents every so often. Javascript
code should never sit in a "tight loop" like this:
// Don't do this!
while (1) {
// La de da, ad nauseum, forever
}
Tight loops like this prevent the web browser from doing anything
else. The latest versions of Netscape will even invite the user
to shut off your script after a few seconds of this sort of abuse.
Use the setTimeout function instead to call
a certain function every so often and get some more work done.
Be sure to call setTimeout again at the
end if you want to keep your "loop" going.
The second nifty feature is the src property
of every Image object in an HTML page. (There
is an Image object corresponding to every
<img>
tag in an HTML page.) Javascript can change
the image displayed by a particular <img>
tag at any
time by assigning a new value to the src property.
Here's a simple example in which the image displayed rotates among
three different pictures, each time it is clicked on. Notice
that giving the <img>
tag a name
attribute allows the code to easily fetch the Image
object by name in the doSwitch function.
<html>
<head>
<script lang="javascript">
switchState = 0;
function doSwitch()
{
switchState++;
switchState %= 3;
if (switchState == 0) {
document.images["myimage"].src="/~boutell/images/volcano.gif";
} else if (switchState == 1) {
document.images["myimage"].src="/~boutell/images/dialog.gif";
} else if (switchState == 2) {
document.images["myimage"].src="/~boutell/images/troll.gif";
}
// Return false so no page will actually be loaded by this link
return false;
}
</script>
</head>
</body>
<a href="dummy" name="switcher" onClick="doSwitch();">
<img src=/~boutell/images/dialog.gif name="myimage">
</a>
</body>
</html>
Really Tight Tables
Geek displays its graphics by setting the src
properties of the <img>
tags in a table.
Each "cell" in the table is also a link with an
onClick handler, which allows the
game to know when the player has clicked on a particular
cell. The only trouble with this scheme is that most
web browsers are eager to add lots and lots of extra
whitespace around table cells, around images, around
imaginary black dots... well, basically everywhere. Anyone
who has tried to do design work with HTML can attest to this.
I eventually solved this problem for Geek using the following
combination of attributes for the <table> and <img> tags:
<table cellpadding=0 cellspacing=0 border=0>
<tr><td><img src=geek.gif hspace=0 vspace=0 border=0></td></tr>
</table>
It takes quite a few zeroes to keep Netscape at bay.
The Complete Game
Feel free to
try out the game on my server. Complete source code is
available as well. Since the game is written entirely
in Javascript, it doesn't create much load on my machine. A simple
CGI program written in Perl displays the welcome page and a list
of high scores; Geek submits new high scores back to the
CGI program when the game is over. (The separate "game over"
window is not closed automatically for the simple reason that
closing it crashes Mac Netscape the great majority of the time.
Closing it manually doesn't seem to be a problem.)
Conclusions
Javascript is perfectly capable of supporting silly games.
No doubt there are practical applications for all this as well,
but let's not think of such unpleasant things. Have another
cup of coffee and play another round of Geek: Game of Champions.