## Monday, August 13, 2007

### Still Trucking

It sometimes seems like I've been working on the same programs all my life.

I first started writing a game about a truck driving across a 2D landscape when I was a child, in BASIC. There is a separate track-editing program. The game uses 40x25 text mode; the truck consists of two Os, an equal sign, and some underscores. The only control is to press Space to jump. Nevertheless, my brothers and I had a little bit of fun playing it.

Thanks to DOSBox I was able to actually run the program and get a screenshot:

Here's the code:

``5 INPUT "TRACK NUMBER? (NOTHING IF 1)"; T\$6 T\$ = "TRACK" + T\$10 OPEN T\$ FOR INPUT AS #1: DIM TRACK(300)20 FOR X = 1 TO 30030 INPUT #1, TRACK(X)40 NEXT X50 TRKPOS = 23: KEY OFF: SCREEN 0: WIDTH 40: COLOR 2, 1, 1: CLS : CLOSE #160 R = 1: FOR X = TRKPOS - 20 TO TRKPOS + 1970 FOR H = 23 TO TRACK(X) STEP -180 LOCATE H, R: PRINT CHR\$(219);90 NEXT H100 R = R + 1: NEXT X110 TRKHT = TRACK(TRKPOS) - 1120 COLOR 12130 LOCATE TRKHT - 1, 19: PRINT "___"140 LOCATE TRKHT, 19: PRINT "O=O"150 GOTO 440160 A\$ = INKEY\$170 IF COUNT > 0 THEN GOSUB 470180 IF TRACK(TRKPOS + 1) <= TRKHT GOTO 380190 IF COUNT = 0 THEN IF TRACK(TRKPOS) > TRKHT + 1 GOTO 380200 TRKPOS = TRKPOS + 1: R = 1: COLOR 2210 FOR X = TRKPOS - 20 TO TRKPOS + 19220 IF TRACK(X - 1) = TRACK(X) GOTO 310230 IF TRACK(X - 1) < TRACK(X) GOTO 280240 FOR H = TRACK(X - 1) - 1 TO TRACK(X) STEP -1250 LOCATE H, R: PRINT CHR\$(219);260 NEXT H270 GOTO 310280 FOR H = TRACK(X) - 1 TO TRACK(X - 1) STEP -1290 LOCATE H, R: PRINT " ";300 NEXT H310 R = R + 1320 NEXT X325 FOR SLOW = 1 TO 4000: NEXT SLOW330 IF TRKPOS = 280 GOTO 710340 IF A\$ = "" GOTO 160350 IF A\$ = "G" GOTO 440360 IF A\$ = " " THEN IF COUNT = 0 GOTO 550370 GOTO 160380 COLOR 7: LOCATE 1, 1: PRINT "YOU CRASHED!"390 PRINT "PLAY AGAIN?"400 A\$ = INPUT\$(1)410 IF A\$ = "N" THEN END420 IF A\$ = "Y" GOTO 50430 GOTO 400440 A\$ = INPUT\$(1)450 IF A\$ <> "G" GOTO 440460 GOTO 160470 COUNT = COUNT + 1480 IF COUNT = 2 GOTO 590490 IF COUNT = 3 THEN 590500 IF COUNT = 4 THEN RETURN510 IF COUNT = 5 THEN RETURN520 IF COUNT = 6 GOTO 560530 IF COUNT = 7 GOTO 560540 IF COUNT > 7 GOTO 560550 COUNT = 1: GOTO 160560 IF TRACK(TRKPOS) > TRKHT + 1 THEN IF TRACK(TRKPOS - 1) > TRKHT + 1 THEN IF TRACK(TRKPOS - 2) > TRKHT + 1 GOTO 650570 IF TRACK(TRKPOS) = TRKHT + 1 THEN IF TRACK(TRKPOS - 1) = TRKHT + 1 THEN IF TRACK(TRKPOS - 2) = TRKHT + 1 THEN COUNT = 0: RETURN580 GOTO 380590 LOCATE TRKHT - 1, 19: PRINT "   "600 LOCATE TRKHT, 19: PRINT "   "610 COLOR 12: TRKHT = TRKHT - 1620 LOCATE TRKHT - 1, 19: PRINT "___"630 LOCATE TRKHT, 19: PRINT "O=O"640 RETURN650 LOCATE TRKHT - 1, 19: PRINT "   "660 LOCATE TRKHT, 19: PRINT "   "670 COLOR 12: TRKHT = TRKHT + 1680 LOCATE TRKHT - 1, 19: PRINT "___"690 LOCATE TRKHT, 19: PRINT "O=O"700 RETURN710 TRKPOS = 21720 GOTO 50``

The thing that strikes me about the code, looking at it now, is how short it is. The physical act of typing is a challenge for children; it behooves language designers to create concise languages that can do a lot in few characters.

In college I had another try at it in C, using a sprite animation library I'd written. I borrowed the image of a Nissan Pathfinder from a clip-art package, and wrote a script in Photoshop to rotate it to generate a bunch of orientations. My rigid-body dynamics skills were not up to the task then so I never got around to using all the additional orientations. The gameplay stayed pretty much the same as the old BASIC version, so it was fairly lame:

Thanks again to DOSBox for the screenshot; it's great to have emulators.

This week I have managed to get my old rigid-body dynamics code all moved over to my Direct3D-based game framework. There's a simple truck although it's not participating in the rigid-body simulation yet. I drew the mesh for it in Inkscape and then typed in the info by hand. Pretty tedious! I really should come up with a better solution for authoring meshes. In this case they're 2D, but they probably won't stay that way. Perhaps something like Blender would work. I'll have to look into that before I ramp up art production.

The truck and beginnings of a terrain just kind of sit there at the moment. I've got the old system of boxes and discs which are simulated overlaid on top:

There's a mostly-straight line along the bottom of the screenshot; that's my frame-time graph. I spent a bit of time trying to figure out if there is any way to get completely glass-smooth animation, without occasional hitches. On my current laptop (a very recent vintage, Core 2 Duo Thinkpad) I get a noticeable hitch every few seconds. My program is not stressing the CPU or GPU at all so it seems like I should not have to put up with this. Unfortunately I have not found any way to do it, yet. I tried cranking my thread priority up to maximum; it made no difference.

Tim Sweeney of Epic Games has mentioned that he'd like to have something more flexible than object inheritance, and I ran into the type of situation that he was trying to deal with. I'll attempt to explain.

As I move my physics code I am thinking about how to modularize it so that it is distinct from the rendering code. Thus, objects will have physical and visual representations.

There is already a class hierarchy for the physical representations. Body holds all of the information common to all rigid bodies: position, velocity, angle, angular velocity, mass, and rotational inertia. Box and Disc derive from Body and supply a small amount of additional information each (width and height for Box, and radius for Disc), as well as the distinct intersection-testing behavior for their respective geometries.

On the visual side it is natural to want to have a class hierarchy as well. There would be a base class declaring a draw method, with derived classes for boxes and discs which would each implement draw in their own way.

It might be nice to be able to say that a RenderBody “is-a” Body because then it would contain all the properties of position and angle which are needed to draw in the right spot. However, if RenderBox derives from RenderBody, then it won't have the width and height defined in Box. If RenderBox is derived from Box then it won't be able to inherit the draw method from RenderBody.

The usual solution in C++ is to change “is-a” relationships to “has-a” relationships, but I think I'm going to end up having to write a lot of glue code. So for instance, one way to do things is to put a Body member in RenderBody. It would need to be a pointer so it can point to instances of Box or Disc. RenderBody would then implement methods for returning position and angle out of its Body member.

RenderBox and RenderDisc would create the appropriate Box or Disc instances and install them in the RenderBody class's Body pointer at construction time. Then, at render time RenderBox and RenderDisc would need to down-cast the Body pointer (which they can safely do since they know the type of object they constructed) in order to get at the width, height, and radius parameters.

There isn't generally any way to sort of “clone” an object hierarchy, adding members and methods at the top level (the draw method in this example) that are inherited down the tree.

Open classes (supported in some languages, e.g. Scala, I think) might be able to solve part of the problem. The basic idea is that you don't have to declare a class's entire interface in one place; you can add dynamically-dispatched functions elsewhere in the code. In this case I'd declare a standalone draw function that takes a Body, then supply definitions of that function for the Box and Disc subclasses.

I don't know whether open classes would allow you to attach additional data members to the original classes, though. If the draw methods require members that store mesh information, for instance, or colors for the objects, you'd have to find a different solution.

Inheritance in C++ serves two purposes: it defines a subtyping relationship, whereby an object of one type can be used as if it were of another type; and it supports reuse of implementations, so that an object of one type can automatically acquire all the members of an object of another type. These two purposes are linked (although you can separate them to some extent using abstract base classes and private inheritance).

Finally, here's a list of 50 Really Good Indie Games. I can vouch for Cave Story (pictured above), which tops the list and is a free game.