Postmortem: Tony Hawk's Pro Skater (Dreamcast)
As cutting-edge as Draconus is, we knew it wouldn't sell as well as a blockbuster like Tony Hawk. Since Draconus was supposedly nearing the end of its development cycle, we decided to move two of the Draconus coders (Wade Brainerd and myself) over to the new project. We also selected Draconus artist Christian Busic to lead the project and enlisted producer Gregory John, who was busy finishing up Triple Play 2001, to manage us part-time. (He spent a lot of time in the office.)
In addition to the two artists we added to the project, we also hired two programmers: Srini Lakshmanan, who had worked on the Playstation titles Tommorow Never Dies and March Madness, and Sean Palmer, who had worked on Demise for the PC and the Oddworld port from the Playstation to Windows. My criteria for new programming hires were that they must have finished at least one title, write correct and readable code, and have some Playstation experience. Although Treyarch had plenty of Playstation programmers, Wade and I had no Playstation experience, so we needed to address that gap.
Unfortunately, it takes time to find new staff. It looks good on paper to say, "We can do all this with four programmers, no problem." But you have to remember that those programmers aren't going to join you right away, and even when they do finally come aboard, some ramp-up time is always necessary. Our schedules took that into account to some extent, but not enough. The new programmers and artists weren't there when we scheduled them -- yet more padding lost.
The Issue of Internet Play
Originally, Tony Hawk for Dreamcast was envisioned as an Internet game. We planned on a staff of five or six programmers, two for the Internet end and the rest for the port itself. To get an Internet game completed in five months, we wanted to begin the networking support right away on the Playstation before the game was even up and running on the Dreamcast. The Playstation development systems had a serial port that we could send messages through, and that was all we thought we would need to take our first steps toward an Internet game.
Coincidentally, Sega held its first network game conference during the first couple weeks of our project. Wade went and discovered that their tools and lobbying network were not going to be up and running until after our ship date. Needless to say, we scratched the plan for network play.
Even without the network play it looked like Tony Hawk's Pro Skater for Dreamcast could still be relatively painless: apart from the renderer there wasn't a lot of Assembly in the existing code base, the Dreamcast is a much more powerful machine than the Playstation so there were no worries about space or speed, and we had a reasonable amount of staff and a comfortable five months to finish the project.
The first step in porting Neversoft's code base was to get it building on a Playstation development system. (Michael Montague, who was on the Triple Play team, did this for us because he couldn't wait to see what their code looked like.) Their code base was a hybrid of C and C++ code, originally written for Apocalypse, with a lot of Assembly for the renderer and some Assembly for the physics. Apocalypse was a Playstation game featuring Bruce Willis, which, we learned, is why in Tony Hawk the code for the classes of skaters is called "CBruce."
After that, Wade started building it with our Dreamcast tools. For Draconus we used the Metrowerks compiler so he tried that one first but then immediately abandoned it. Because Neversoft used GNU for the Playstation version, it made sense for us to use GNU for the Dreamcast as well. Still, he had to go through the tedious process of finding lines that didn't compile because they referred to Playstation library calls; for every one of these he created a dummy function that did nothing but print out a debug message saying that it had been called. After a couple of days he had a program that compiled, linked, and ran -- and did nothing but print out messages.
This is the scary part of the project because there's no real way to measure how far out you are from having a running game with a character actually animating in a level. During Treyarch's Triple Play Baseball port from the Playstation to the N64 it took two months to get the game up and running, but that time we didn't have a Playstation system on hand and we weren't that familiar with the N64. We figured that since for this project we had three programmers (Sean hadn't come on board yet), a Playstation dev system, and a lot of DC familiarity, we have it running in just one month.
While Wade got the file system working, Srini and I started filling in the empty Playstation calls, trying to write only the ones used by the renderer and the physics first. Early on we decided we weren't going to use the Dreamcast's wonderful floating-point math because we didn't want to introduce errors into the code before we even had it up and running. (And besides, as slow as the Dreamcast's integer math is, it's still faster than the Playstation's.) We actually had two options when it came to the math; the Edge of Reality guys had already done floating-point math for the N64 port of the game and we were given their code. By this time (see below on our problems communicating with Neversoft), we had already implemented a lot of the functionality in integer, but we had come up against a bug and were thinking of switching to Edge of Reality's floating-point system.
Ultimately we didn't switch, and the decision seemed to pay off: our game behaved almost exactly like the Playstation version, right down to the same quirks and weird little bugs: players can ollie through a chain link fence in a couple of places, occasionally bounce off half-pipes in interesting ways, and even get stuck on the lip of a half-pipe, able to do tricks but unable to move, trapped there until the end of the game. All of these bugs shipped on the Playstation side and we only fixed the ones were players got stuck.
There was one place where the integer math's lack of precision hurt: the animations looked a little jerky. (The worst was when you were grinding a rail you could actually see your trucks shift around on your board.) Sean rewrote that in floating-point and we were fine. We would make little test beds in the first few lines of main() that would evaluate different values of these different math functions in order to test that our version of the Playstation function behaved the same way on the Dreamcast. While we got all the needed functions done, Wade got the file leader going and was displaying the opening title screen.
We then needed to write a renderer so Wade and I pair-programmed on the first draft (more on pair programming is under "What Went Right"). Writing a renderer for the Dreamcast using their libraries is trivial, it's as easy as programming the Voodoo API and even easier than programming DirectX. Soon we had the level drawing flat-shaded, followed by a box for the skater and textures. Finally, we had animations and the game was up and running. All told, this took a total of three weeks. We managed to get our first milestone burn a few days early, and there was much rejoicing.
We had five Sega "Set 5" development systems. We bought them ourselves rather than borrowing them from Crave, though they did lend us the Playstation dev board. We got one for each programmer and one for the lead artist so he could see the art in the game without interrupting any coders. It would have been nice to have one more for our producer so he could do the build and smoke tests and burn the deliverables for Crave, but since Greg was busy with Triple Play it was better for me to do it.
Things got scary because Tony Hawk had movies streaming into textures that played while you skated and the current version of the Sega libraries (we were using Release 9) did not support that functionality. Release 10 promised to include it, but didn't beta until we were supposed to be feature-complete, and the final release didn't arrive until after our beta. When asked, Sega said it was confident in its ship dates so we waited for the new libraries and worried. We managed to get an alpha of the movie-playing stuff early, and worked with a hybrid library that was actually quite solid. Unfortunately, the movie library was barely documented, so it us took more than a week to get the thing actually working. We ended up missing our feature-complete milestone because of this one lacking feature. Still, because it was the only missing feature, the game could still be tested without it and we still shipped on time. We shipped using a hybrid version of Releases 9 and 10 which Sega didn't really approve of, but they tested the game thoroughly and passed it anyway.
The artists used Lightwave 5.6 for modeling both characters and exported them with Neversoft's El Pluggo Max plug-in, modified slightly to ease the production path and incorporate high-resolution Dreamcast textures.
Instead of buying top-of-the-line single-processor machines for the coders, we spent the same amount of money getting dual-processor machines with weaker processors. It took some doing to get the makefile that Sega provided for doing builds working with the dual-processor machines, but once we had that going it was fantastic -- a complete build took three minutes. Unfortunately, we had to upgrade the library to get movies working, and for some reason we couldn't get the new makefile working with the dual-processor support without introducing strange bugs into the code. We never understood why, but for the rest of the project we were back to six-minute builds and wishing we had the fast single-processor machines instead. Three minutes doesn't sound like much but for some coders it meant the difference between doing the right change in your code -- even if it means touching an .H file -- versus implementing a cheesy workaround.
The code for Tony Hawk for Playstation rendered shadows by rendering black ellipses, one for each segment of the character model, onto the ground. We appropriated that code, made it work on the Dreamcast, but discovered that it looked terrible due to Z-buffer poke-through. We then switched to rendering to a texture and then projecting that texture into the world. We tried to find a good way to render that texture dynamically using light sources and projecting it on the nearest surfaces. And after a lot of passable results Wade and Sean came up with the idea of rendering everything near the skater in two passes: one for the geometry, and another to project the shadow texture on the geometry. This resulted in near-perfect shadows, as they would conform to steps, slopes, and walls. It took Sean some elbow grease to get them clipping correctly so they wouldn't show up on the backside of walls or on both sides of the skater, but the end result was well worth the extra time spent on it.