Where to start... A business acquaintance told me about his uncle who ran some kind of video game company in Hong Kong and was looking for game programmers, and I was interested. It was kind of strange, because I don't play video games, but I had written a few TinyBasic (text-based) games for that market. So I went down to the local video game arcade; I never spent a nickel there, I just watched people play so I could get a feel for how they play.
Anyway, my friend brought over the development hardware and a big Sony TV to play it on (I don't watch TV either ;-) and a competitor's tennis game (I think it might have been Coleco, but I cannot remember). I played with it some and decided it was a bit hokey. The vendor wanted something "3-D" with a shadow to follow the ball around. I guessed I could do that.
Problem #1: I don't play games, not even live games like tennis. I knew nothing about the game. So I went to the library or a bookstore (I can't remember which) and got a book on tennis rules. The scoring is bizarre -- certainly far more complex than the simple +1 scoring of the competition -- but not too complicated to program the computer to do it.
Problem #2: In the competitor's product (and in most video games, many even today 22 years later) the characters sort of slide around on the screen to follow the joystick, and their feet move, but their feet don't stick to the ground. It's like they are skating on ice, a consequence of sprite graphics (see Problem #3). I resolved that MY game would be physically correct. In the competitor's game, the player just flipped from racket on the left to racket on the right, mirror image; that was the only swinging action. Again, I thought that real tennis players had a little more animation than that. So I went down to the local video rental store and rented a VCR and a tape of Billy Jean King teaching tennis. There was some lecturing, but mostly a lot of video action BJK serving the ball, or BJK running across the court to catch a ball with her forehand, or running the other way to catch it with her backhand, stuff like that. I set my 35mm camera up on a tripod in front of the TV and paused the tape a lot and took a lot of stop-action sequence snapshots off the screen -- maybe three or four rolls in all. Then I lined up the snapshots in sequences all over the kitchen counter and picked out the most representative running and swinging and serving sequences. Then I copied the posture and motion of BJK's moves onto graph paper. Well, not exactly, which brings me to ...
Problem #3: Hardware limitations. The game console was eventually sold as Emerson Arcadia 2001, with a Signetics 2650 8-bit CPU and some kind of video chip that had 8 colors on maybe 256x256 pixels -- the pixels were not even square. And there were eight 8x8 single-color sprites. A sprite in computer graphics is a small picture that you can separately program not only what it looks like, but also where it will be displayed on the screen. That's how you get the skating effect: you run through a short animation of the character's legs running, and then independently you set the X/Y coordinates of where to show the character, and swish! It slides right over. Even in video hardware where you don't have hardware sprites, it's so much easier to program sprites for animation and motion independently, that the game software tools do sprites in software. 256x256 is not a lot of pixels, and 8 colors is pretty limiting. The sprites were a challenge in themselves: 8 pixels tall is too small for the players. I finally settled on one sprite for the legs, one for the head and shoulders, and one for the tennis racket. Each on-screen player was three sprites, leaving two for the ball and its shadow. Having only one of the 8 colors for a sprite was also a limitation, so I chose generic solid colors for the players, and white for the rackets and ball (and black for the shadow). Everything else, had to be programmed pixel by pixel. Worse than that, each block of (I think it was 8 pixels square) could only have one foreground color, and then a single background color for the whole screen. It was like the old character graphics from the days of the character-generator TV typewriters. It maybe had your choice of text-only at the bottom, or some kind of text over the whole screen. Now that I look at some of the other screen shots, I see that their character generator was one of those done by a computer programmer, with slashes through the zeros so they are hard to read. I consider that stupid, and you won't find any slashes through MY zeros (I'll use the letter "O" first).
Problem #4: Sound. The video chip did sound by giving it a frequency of tone, or else a white noise generator (or both, I think), plus a few bits of volume control. When a real tennis racket hits the ball, you get a smushy-sharp "plock" as the ball compresses and rebounds, plus a little bit of a twang when the strings in the racket oscilate like a guitar string (but much shorter, because the cross-weave damps it quickly). I played around with the sound for a long time before I settled on a burst of white noise overlaid with a rapidly decaying high-frequency tone, and then little bursts of white noise at minimum audible volume for the footsetps. I considered more white noise at varying levels to be applause at the end of the game, but I don't think I ever did it. My program was already becoming too big. It had to fit in a 4K ROM.
Problem #5: Animation. I did not want my characters skating over the grass, so I spent a lot of time carefully lining up the backward motion of the foot animation in the leg sprites to be synchronized with the forward motion speed I was moving the sprites, all on graph paper. In this game you cannot just zoom your player over to the other side of the court, you have to walk or run him over. I think I allowed for two speeds, walk and run, with an appropriate number of frames per pixel rate of motion -- and of course foot motions to match. As in the video, walking picks up one foot and sets it down before picking up the other foot. The foot that's on the ground must be moving backwards through its sprite at exactly the same speed the sprite is moving forward. When running there is a part of the cycle where both feet are off the ground, and the whole character is bouncing up and down with the leaps. That means the torso sprite must track the vertical motion of the legs sprite. I vaguely remember that the sprites weren't quite big enough to move them smoothly when running, so I had to adjust the sprite progress backwards (or forwards, I can't remember) one pixel in that part of the cycle to keep the foot animation continuous. It was pretty complicated. I never tried any diagonal running -- or maybe I tried and gave it quickly up as too hard -- but I did do both side-to-side and front/back walking and running. The front/back motion was somewhat simpler, and I maybe had a single animation for both walking and running. I wanted the winning character to jump over the net at the end of the set, but I was out of ROM space; they run around it.
Because of the color limitations, you cannot tell which leg is in front of the other in the side-to-side walking and running. This made things a little simpler, because I could reuse the same leg sequence for both the left foot passing the right and the right foot passing the left, and in both directions. I think I did a pixel reverse subroutine to flip the image over and save pixel space in ROM. However, the racket was a different color, so (assuming the players are right-handed), when the player runs left-to-right on the screen, the racket sprite is in front of the person sprites, whereas when the player runs right-to-left the racket goes behind and partially disappears from view. I cannot remember whether I did this by switching sprites (I think there was a strict hardware-enforced z-order on the sprites), or by knocking out some of the racket pixels in its sprite. Notice that the running animations had matching arm swings synchronized with the legs, the way real people run. I did, after all, have all those video shots of BJK running to look at. And of course, the racket was in the player's hand, so it had to track the arm motion. Also, as the hand came down in the swing, the racket rotated on its own axis (and partially obscure, if running to the left). I wished I could have scaled the distant player to be smaller than the near one, but I simply did not have enough resolution to play with -- nor enough ROM space for the code to do it. None of these are problems today. So the guy in back looks too big. Oh well.
Problems #6, and #7: Game physics. Today you can buy a whole book on game physics, and there are frequent articles in the computer game programming journals; 20 years ago the topic did not exist. I won't say mine was the first game to consider the physics, but it's probably in the first ten. Getting the parabolic curve in the trajectory of the ball in free-fall is not hard, it just takes a couple adds, the first to add the current ball velocity to the vertical position of the ball every frame, the second to add a constant negative acceleration to the velocity. This had to be done double-precision (16-bit integer), with the lower byte representing a fractional pixel to get smooth motion. All motion was done in fractional pixels, in full 3 dimensions; it required three 16-bit adds to each position vector, then dropping the integer part of the sum into the sprite coordinates. Oh yes, because this was a perspective view, I had to add half (?) the Y-axis position to the Z-axis to get the screen vertical, and run the character in the back at half the speed of the guy in front. Maybe I scaled them proportionally for the middle court, but I can't remember. I know I thought about it. I also thought about wind resistance, making the horizontal velocity of the ball slow down proportional to the square of its speed, but I think I decided not to. ROM space.
Much trickier was getting the new trajectory of the ball correct after
it's been hit by the tennis racket. I spent a long time working out the
math (trigonometry) based on the racket angle and velocity, plus the incident
ball velocity, to find a new reflected velocity. I was quite surprised
that all the trig functions cancelled out leaving me with two multiplies
and four adds. In a CPU without even a hardware multiply, that was a major
plus. The physics was perfect.
The game was unplayable.
Think about it for a minute: real tennis players have spent five and ten years -- essentially all their childhood and early adult years swinging hard objects held in their hand at a flying round object, making the connection, and learning how to control where that ball flies off to. Even newbie tennis learners have had some experience with hand-arm-eye coordination, and yet they take weeks to learn how to get that tennis ball over the net and not out of the court. A video game, on the other hand, the prospective customer (probably an adolescent boy) expects to walk into the store, pick up the game paddle for the game on display, press the buttons and move the joystick -- all operations radically different from swinging their arm while holding a large wooden handle -- and score within 15 seconds, or they won't buy the game. With my original physics, you could have learned the coordination, but it would have taken weeks, just like learning how to hit a real tennis ball. That's a non-starter in the game market.
So I threw out all the math and physics. Well, not ALL of it, I kept the trajectory physics, but I made the racket effectively four feet wide (about six pixels, as I recall), and reverse-calculated how hard and what angle the swing had to be to hit the ball and get it over the net. So if you are anywhere near the ball, and you push the button anywhere near the right time, you got it over. You can still control how hard you hit it (don't try a lob from right close to the net, it will go outside the opponent's court; a gentle hit from the back line will similarly not clear the net), and I think I left a little of the timing in (which controls the left/right angle, depending on whether it's a backhand or forehand), but it's relatively easy not to miss.
Problem #8: ROM size. Did I say the program was getting too big? It WAS too big, twice too big. It was supposed to fit in 4K, but when I put it all together, it barely fit in 8K. The vendor was pretty nice about it, he accepted it and even paid me twice the agreed price (which I didn't ask for -- but I didn't refuse it either :-)
He liked it so much, he even sent over a couple of his own programmers for me to tutor in game programming. Maybe that was part of the deal in paying me double. That was an experience in itself. One of them barely spoke a broken English, and the other knew only his native Chinese. I don't recall what-all I told them, nor how much they actually understood, but they seemed pleased with the process, and treated me to a huge Chinese dinner (ordered off-menu in Chinese at a local Chinese restaurant). OK, so Funky Fish isn't the most exciting game in the Arcadia catalog, but it was what the guy could handle (I can't remember what the other guy did). Whatever.
Maybe some day I'll write another video game. The bar is a lot higher today, involving 5-10 programmers, plus graphic artists, sound people (composers, etc), animation, way more than any one person can do. But it's a meritocracy: people are honored for what they (can) do, not who they are. I can still write pretty good code.
2003 October 9