I've been working on some new illustrations for my game programming pages. In the past I had created bitmap diagrams using Gimp or by writing custom code. This time I'm using Inkscape, which produces SVG, in the hopes that I can directly embed SVG onto the web page.

Unfortunately browser support for SVG stinks.

First, not all browsers support SVG. So you need a fallback. That's fine; I can produce PNGs with Inkscape.

Second, there's the question of whether to use <embed> or <object> tags. The answer seems to be that <object> is the “right” answer, but it crashes Safari 1.0. So I should use <embed>, right? I would, except <embed> doesn't support fallbacks.

This means that I to support browsers without SVG (by using PNG fallbacks), I have to crash the Safari browser. Ugh.

Even if that problem is solved, the next problem is that different SVG implementations support different features. Adobe's SVG plugin, Mozilla/Firefox SVG, and Opera SVG are all different. Even the very simple SVG I wrote does not work the same on all three. Opera does not seem to support text at all.

Browser vendors: it's worse to have limited SVG support than no support. With no support, the fallback will be used, and the reader will see something useful. With limited support, the reader will get a broken diagram.

Even if browsers supported SVG, the web server I use does not use the correct MIME type. It sends text/xml instead of image/svg+xml. I'm not sure how much this matters in practice though. (Side note: I find it interesting the change from text to image. This is going to generally be a confusing point with XML, since it's text underneath, but the rendering of it may not be.)

I have decided not to embed SVG on my pages (although I might link to it). I will turn SVG into PNG and embed PNG on my pages.

I played Black and White 2 for many hours yesterday. The computer player and I were in a stalemate. The computer kept sending armies against me and I kept defeating them. I had built my town with walls around it, and then put archers on top of the walls. I was building up my strength while defending myself, in preparation for a big attack. I felt pretty safe.

After around 40 attacks, I realized that they weren't all the same. The computer wasn't using the same attackers each time. It tried the creature, archers, swordsmen, and catapults. It tried combinations of them. Sometimes it would come through my main entrance, and sometimes it would come around the back entrance to the city. The computer player also destroyed major sections of the city using the “earthquake” power, but I recovered from these too. After a while the enemy creature figured out that he should kick my wall in. His archers and swordsmen stayed back, out of range, while the creature came up and destroyed my wall, including the archers on it. After it breached the wall, the army swarmed into my town and killed half my people.

I rebuilt my wall and started to recover, but the computer's newly discovered strategy worked well. It tried several variants but kept going back to the same approach: kick down the wall, then swarm the town. This forced me to try some new strategies. Although being on the wall has advantages, it leaves the archers vulnerable when the enemy creature attacks the wall. So I moved them behind the wall. I've also learned to open my gate, wait for the enemy army to get close, then close the gate and set their army on fire. I have no good strategy for the creature knocking down my wall though, and I'm constantly losing townspeople and then rebuilding.

After a long stalemate, the computer AI learned how to attack more effectively, and now I'm having trouble keeping my city safe. I'm very impressed by the AI. I'm not sure how it's programmed, but it tried out many different things and learned which ones work the best. From the game AI techniques I've learned (genetic algorithms, neural networks, fuzzy logic, state machines, etc.), the AI in Black and White 2 seems to match most closely with what I know about reinforcement learning. It's a technique that uses online learning (observing results as the game is played) instead of training (from examples constructed ahead of time), allows both exploration (trying new things in order to learn) and exploitation (taking advantage of what you've learned), and associates rewards (like whether the attack was successful) with actions (like kicking down the wall and keeping the army away from my archers). I recommend Sutton and Barto's book if you want to learn more. It's entirely possible though that the game uses something much simpler that just happens to look impressive, but my guess is that it's using reinforcement learning.

Labels:

My game programming page contains information about platform-independent game programming topics, but when I actually write a game I need to combine that with platform-specific code. These days I use either PyGame, Java2D, or OpenGL. My favorite OpenGL resources over the last six months have been:

  • CodeSampler, which contains lots of examples of OpenGL code to do various things like textures, shaders, transparency, and lighting.
  • NeHe's Tutorials, which covers similar topics.
  • Gamedev.net OpenGL Articles, which includes a few random topics. Unfortunately most of the Graphics articles on GameDev are old and obsolete; they teach you how to implement algorithms that are already implemented in hardware these days.
  • FlipCode's Featured Articles cover many graphics-related topics but do not focus too much on OpenGL.

In addition, I've been reading Dave Eberley's Game Physics and Van Verth's Essential Mathematics for Games & Interactive Applications. These books are not primarily about graphics; they are about representing objects in 3D, manipulating them, etc. I also took a look at Stahler's Beginning Math and Physics for Game Programmers but didn't like it as much.

Labels:

One of the most fun things about SimBlob is the water simulation. It isn't great though, and I keep looking for ways to make it better. Using the Navier-Stokes equations is the “right” way to simulate fluids, but they're complicated and expensive, so many people have come up with approximations or alternatives. Here are some resources:

None of their solutions directly works for me, since I'm using a hexagonal grid and have a dynamic landscape underneath the water.

[2005-07-11] Update: I tried some approaches based on the above, but they didn't work for me. It's quite possible that I'm missing an essential step in my simplification.

Labels: ,

I've added a Mac makefile to the download, but I haven't tested it myself. The main changes involved file paths. On Linux and Windows, OpenGL is #include <GL/gl.h>; on the Mac, it's #include <OpenGL/gl.h>. On Linux and Windows, GLUT is #include <GL/glut.h>; on Mac it's #include <GLUT/glut.h>. I admit that the Mac directory names make more sense, but it's annoying given that the include has been GL/gl.h for a decade on other systems. The other change involved the linker options; you have to specify a -framework. Thanks to my friend Richard T for figuring all of this out.

Labels:

When I started working on Simblob 2 back in 2002, I decided to use OpenGL and GLUT. Even though I was developing in Linux, I didn't want to end up in the situation I had with Simblob 1, which only works in OS/2. I finally took advantage of the portable libraries for SimBlob 2 and got it running on my new computer, which runs Windows XP.

I use Cygwin in Windows, so the Unix level libraries are fairly similar. The main difference was that the paths are different. In Linux, I used -lglut -lGLU -lGL, and the compiler was able to find all the headers and libraries. To make it run in Windows/Cygwin, I changed it to -I/usr/include/w32api -L/lib/w32api -lglut32 -lglu32 -lopengl32. Also, glext.h wasn't automatically included, so I had to insert #include <GL/glext.h>. In addition, the multitexturing functions (glActiveTextureARB, glClientActiveTextureARB, and glMultiTexCoord2fARB) don't seem to exist on my system, so I worked around that by using a single texture instead. I'll figure that one out later. I might need to use wglGetProcAddress to get those functions (unfortunately that function is Windows specific).

The one remaining problem I'm having is that when I quit the program by closing the window, GLUT's main loop doesn't exit. It instead starts eating up 100% of the CPU and never terminates. I'm not yet sure if this is a GLUT issue or a Cygwin issue. My workaround is to use Ctrl-C to exit instead of closing the window.

At the moment Simblob depends on Cygwin. You can't just run the Simblob executable; you have to have Cygwin installed. I'd like to try using the MingW option (gcc -mno-cygwin); I just need to remove some other dependencies on Unix libraries first.

I should probably spend some time learning autoconf or some other tools that help manage builds on multiple platforms.

I don't have a Mac handy, but it shouldn't be too hard to make Simblob 2 work on a Mac.

Labels:

A few weeks ago Google Maps got me thinking about writing simple games in Javascript. In particular, how much of The Silver Kingdoms could I implement in a browser? If I drop the terrain and make it a 2D overhead game (or possibly isometric, but that might be harder to implement), what I would need from the browser is (a) AJAX support (so the simulation can run on a server and send updates to the browser) and (b) transparent overlays for sprites. There are some nice advantages of writing in a browser. The basic graphics code is already there (image display, animation, positioning, layering) and the basic UI code is already there (mapping clicks to objects, overlapping windows, form controls). The real question is whether it's feasible—can the browser smoothly animate lots of sprites on the screen at once?

A few days later I read that someone had created a Star Wars hack on top of Google Maps. And then I saw someone had created an animated Microsoft campus invasion hack. There's now a wiki page with a list of Google Map hack game ideas.

There are only 9 sprites on the animated invasion hack, but it feels rather choppy. I'm not sure if this is a browser issue, an issue with the demo, or an issue with the Google Maps API. If it's a browser issue then it's unlikely that any nice games are going to be written on top of Google Maps. If it's a Maps issue, then a game using its own map might be feasible.

Some links I've collected while looking for ways to implement a simple game (SimCity-ish) in Javascript:

I hadn't been considering using Google Maps itself, because a SimCityish game where you can't actually modify the city would be boring. I think it might be feasible to build a war or transportation game on top of Google Maps, but the game would need some notion of what the objects on the map are, and that might take some image recognition heuristics. It's unlikely I'll actually implement a real game this way, but I might try a little demo game.

Update [2005-12-16]: Take a look at this game.

Labels:

There's something about Guild Wars that I don't see mentioned much: it has a very friendly interface that encourages casual play.

  • The CD doesn't have to be in the drive. When I'm thinking of playing, I don't need to take the previous CD out of the drive, put the Guild Wars CD in, and then start the game. I can just start the game right away. Since it's no hassle, I play a lot more.
  • When I start the game, it goes right to the login prompt. No publisher splash screen. No developer splash screen. No video card maker splash screen. No sound library splash screen. No introductory movie. No copyright screen. No disclaimer screen. No menu. No loading progress bar. It's really quick and easy to get into the game. This encourages me to play more.
  • While you're playing the game there are Minimize, Maximize, Close buttons at the top right corner. This lets you easily switch to another application or run the game in windowed mode or just stop playing. It acts much more like a standard application, and it's very smooth. I feel like I can play at any time, and then switch back to whatever I was doing.

All of these seem very minor but I think they add up to something big: I'm playing Guild Wars a lot (over 200 hours). I wish all games would be this way.

Labels: ,

After playing Neverwinter Nights for a few months, I got tired of it. I played the main campaigns and enjoyed them. The problem is that the mods are much harder to deal with than they should be. It takes a lot of effort to find mods that you can play (level restrictions, number of players, good ratings, etc.). It then takes more effort than it should to download and install them. They come in ZIP, EXE, and RAR formats. They come with multiple files, each of which may have to be put into a different folder. Bioware could have made mods easier by keeping all the mod files in a single folder and by standardizing on the distribution format. For example, if the game could read ZIP files, you could just download the file and put it in a particular folder and it would be ready, without unpacking it. In any case, the main problem I had was that it was hard for me to find and try out mods, so I didn't try many, and I didn't find many that I liked.

I've been playing Guild Wars this week (22 hours so far). This is an action RPG, much like Diablo, but it also has more quests. One thing that struck me was that Diablo 2 wasn't considered an MMORPG, but Guild Wars sometimes is, and the two games aren't substantially different in that respect.

Diablo 2 lets you play offline (one player) or online (one or multiple players). Guild Wars lets you play online only. This seems like a good idea. If you know that everyone's online, you can have a much quicker update cycle (those of you who waited over a year for the 1.09 Diablo 2 patch know why this matters). So far I've had 3 small updates in 4 days. Requiring online play also means you can learn how people play and make game balance adjustments frequently.

Diablo 2, in online mode, puts you in one of many chat rooms. The main purposes of this room are to chat, to find people to play with, and to trade. There are several chat rooms (presumably to avoid overcrowding), including some specifically for trading. When joining a game, you see a list of games that are at your level (Normal/Nightmare/Hell). People generally want to find a game that's not only at their level but in the same general areas. They sometimes do this by announcing their area (“Act III - Staff quest”) in the game name, but there's no easy way to filter or sort the games to find the areas you care about. Once you join a game, you don't see everyone anymore; you only see your party. Every time you join a game, the world resets—all the monsters are back, and the layout is randomized. When you leave a game, you abandon your party.

Guild Wars feels like an MMORPG because it puts you into the game right away. You're in a city, with lots of other people around, and you can see everyone walking around, talking, getting quests, etc. But these cities are essentially chat rooms. Their main purpose is for people to chat, find people to play with, and trade. Once you join a party and go out to play the game, you don't see everyone anymore; you only see your party. Every time you go out, the world resets—all the monsters are back (but the layout is not randomzied as it was in Diablo). When teleport into a city, you abandon your party.

There are of course other differences. In Diablo, you can only get quests once you go into the game. In Guild Wars, you can get quests in the chat area (cities). Since a party may want to go into a city to get quests, the party is not broken up if you walk into a city; it's only broken up if you teleport. In Diablo, if you want to trade with someone, you find them in the chat room and then you have to create a game to trade with them. In Guild Wars, if you want to trade with someone, you can trade with them in the city where you met them; there's no need to go anywhere. Also, Guild Wars has a special trading chat channel. You can tune in to both the regular and the trading channel; you don't have to go somewhere to find the traders. Guild Wars also makes it easier to find a party or to play PvP.

Why does Guild Wars keep the Diablo-style chat vs. game area distinction? I think it's for efficiency. Chat areas handle hundreds of people; game areas handle up to four. Chat areas are easier to make efficient because you don't need strict ordering of events. If you say something and I say something at roughly the same time, it doesn't matter so much which is heard first. And it doesn't matter so much if it takes 250 ms to show up. If you attack someone and I attack someone at the same time, it matters a great deal which one occurred first, and it needs to be decided and sent to all clients much quicker than 250 ms. By segregating the chat (lots of clients, loose ordering of events, high latency) and the game (few clients, strict ordering of events, low latency), you can make both efficient. If you tried to combine the two, you open up a new hard problem: what happens when you have lots of clients and you need low latency? Trying to tackle that rare but important case makes your life as a game developer more difficult. You're spending less time on other things that may have mattered more to the players.

Another thing that Guild Wars doesn't handle is massive persistence. You can only drop items in the game areas, not the chat areas. So if you drop an item, it only has to be seen by a few other clients, and it goes away as soon as you enter a city. That way you don't need to coordinate item locations among tens of thousands of clients. You can assign each city area and each game area to a separate server. Since city and game servers keep no state, you can add more servers transparently. You don't have to require players to choose a server ahead of time and then find that they can't play with their friends, who happen to live on a different server.

So far I've been really impressed with what I can infer of the design of Guild Wars. It's fast, has great graphics, and lots of fun. It's an incredibly addictive game.

Labels: