|
To frame this, I actually worked at Sony as a software engineer on the Playstation when Wipeout came out, so I have some firsthand insight into developing games around this time. When it comes to older games like this, there were a bunch of compromises that we had to make that introduced additionally complexity, that are entirely overlooked here. You're looking at this from the perspective of how a computer/processor works now, and what it is like to develop software without having to take into actual account the limitations of the hardware and processor itself, as a part of your code design. For example, the Playstation 1 had a MIPS R3000 CPU, and a single instruction pipeline, so it's basically doing only doing 1 thing at a time. Multithreading doesn't exist. Our only parallel processing was that we could do all the game logic + all the math to transform all the triangles into screen space, and simultaneously the GPU would be drawing the last frame we drew. We had 4MB of memory total, so when we were were working on games then, we would have actual discussions about whether it was worth the overhead of including a malloc/free, or just hard-coding all your memory addresses because of the space you'd save. We would compile out our abstracted, "nice" versions of functions, count the instructions, and compare sizes to see where we could optimize the code to reduce the compiled output size. In return, we might be able to draw an extra triangle or two. The instruction and datacache were tiny, and loaded based on address, so sometimes we would add code or instructions that didn't do anything just to make a loop not cross a cache boundary. So we were working on under strict time pressure, with unknown hardware and badly translated japanese print manuals (and sometimes not even translated), in small teams without any real ability to communicate with anyone else in the industry about it (since we are all under NDA). I'm not saying that we didn't write bad code, we did write plenty of it, but a number of the decisions on HOW to write the code itself that we were considering then aren't even visible to people reading the code now and making judgements on it. I knew I was writing spaghetti code some of the time, because I didn't have the memory budget to load it as data. Is there a cleaner way to do their UX and in a data-driven fashion? Sure. But for me to get that data, I would have to write a function to load a/multiple blocks of data from a 1x CD that a super low transfer rate, and an appallingly long seek times. Making a data-driven UI is possible, but not practical when someone hits the start button, they want the menu to come up immediately. In many cases, we knew that we were writing bad code, but didn't have the capacity to write anything better. It literally didn't fit our budget for memory or CPU. Then you have to make decisions about where you CAN afford an abstraction, and those decisions can be quite painful. I haven't violently disagreed with anyone in any of these threads, but did want to offer a bit of my first hand perspective on things that are often overlooked. |
When you have more resources, you can write things prettier, not rely on side-effects, not 'abuse' features to do things normally considered BadTM, not "cross the streams". Or perhaps I should say when you fit easily within available resources, you have luxuries.
Don't feel bad about what you built, when you're aware of the constraints you were under and that the tradeoffs you were making were the best available choices at the time.
[1] http://www.catb.org/jargon/html/story-of-mel.html