You know the drill by this point. Here is the full presentation at Quakecon 2012. My comments with timestamps follow. Note that I’m just watching the video, pausing to comment at points that I think are interesting or could use some clarification for the masses.
I’ve said before that this era was pretty much a turning point in graphics technology. Doom 3, Half-Life 2, World of Warcraft, Thief: Deadly Shadows*, and Far Cry. We can argue a bit about the true high point. Maybe you want to move it back to 2002 so you can include NOLF 2. Maybe you want to move it forward a year or two to include the likes of Half Life 2: Episode One, or Quake 4, or whatever. But the point stands that right here we hit a magical spot on the visuals vs. cost trade-off. Games could still be produced in two-year intervals, and they had just enough graphics that characters could emote. But they hadn’t yet dropped into the uncanny valley of photorealism or become so expensive that nothing short of mega-blockbusters could hope to turn a profit.
The graphical gains since this time have been so modest, and we’ve given up so much to get them.
* I’m commenting on the graphics here, not the gameplay. Also, Thief Deadly Shadows gets a demerit for it’s not-ready-for-primetime ragdoll physics, which turned the town guards into hilarious contortionists upon death. Also the tiny levels were inexcusable given the genre. Maybe I’m undercutting my argument a bit here, but the point is: With regards to screenshots, the game holds up really well.
He’s talking about their ongoing project to re-release Doom 3 with some graphical updates, some new levels, and support for VR headsets. In the process of updating the 2004 Doom code, they found themselves pulling bits of id Tech 5 (the name of the engine that drives RAGE) code and using that. When he mentions interfaces, he’s talking about programming interfaces.
Let’s make a simplistic hypothetical example. Let’s say you’ve got a bit of code for working out hit detection. Say there’s a bit of code for checking to see if a given shot will hit another player. Perhaps your code for Shoot Guy III looks like this:
Entity* HitscanDetect (Vector origin, Vector direction, float range);
So when the player pulls the trigger, you call this function. You pass it three values: Where the shooter is standing, what direction they’re aiming, and the maximum range of the weapon. (It’s pretty common in old games to simulate bullets that travel in a perfectly flat trajectory until they hit some limit, at which point they poof out of existence.) This function will return the entity (fancy programmer lingo for “thing that exists in the game world”) that was hit, if any. You can then use that information to take whatever action is needed. (Deal damage, subtract ammo, kill somebody, etc.)
Maybe in a few years you’ll release Shoot Guy IV. During development, someone might re-write
HistscanDetect () to be better. Maybe it will use less CPU, or do more accurate detection. Maybe it uses less memory, or just has cleaner, more readable code. Whatever. It’s new.
So then you do a re-release of Shoot Guy III. You decide to take the new and better code and copy & paste that sucker into your older codebase. Easy, right?
If the interface is the same, then it’s easy. But what if the interface has changed?
EntityList* HitscanDetect (Player Shooter, Vector origin, Vector direction, class WeaponData);
See, in Shoot Guy IV, you added the railgun, which can pierce multiple targets. So the function now needs to return a list of everyone that was hit, not just one entity. Also, Shoot Guy IV had team-based gameplay, so you have to provide the identity of the shooter, so that it can check and handle friendly-fire issues. (The railgun can’t hit enemies hiding behind the shooter’s fellow teammates.) Shoot Guy IV also featured real bullet physics, which meant bullets traveled in a proper parabola. So now you have to pass the hit detection thing a little bundle of information describing the weapon being used and how it behaves, so that it can do the simulation.
The interfacehas been changed. The values you provide are different, and the results you get back are different. It’s similar, but not the same. Now you have to think about what you’re doing. Maybe you can plug in some dummy values for Shooter and WeaponData and call it a day. Maybe if you pull in the new code you’ll need to also bring along more code to deal with the WeaponData. Hang on, the WeaponData code is linked to this math stuff for calculating parabolas. And the math stuff ties in with the newer networking code for dealing with latency in an online game. And that code uses a couple of tiny bits of our newer, more secure networking stuff and the anti-cheat code that goes with it.
What you’ve done is tugged in a loose bit of Christmas lights and found yourself holding an immense knot of interconnected stuff. You’re not even sure where you should make the cuts between new and old. This was supposed to be a simple copy & paste job and you just dumped six hours into this and you’re still finding new knots. You’re not even sure how big the problem is at this point, much less how long it will take to untangle.
This probably adds quite a bit to the cost of making games, and becomes more exacerbated as the process of making games is handled by more specialists.
In the old days you had programmers and artists. (Or, in the super-old days, your programmers also made the art. This was probably not ideal, but that’s the way it had to be.) Your artists kind of made levels, textures, and character sprites. Maybe Alan was better at some tasks and Barb was better at others, but the stuff was simple enough that everyone could stay busy.
Now it’s all specialists. Two different artists will have entirely different jobs, using different tools, on types of machines, to produce art that is needed at different points in the development. Alan can’t just start making character animations and Barb isn’t in the loop enough to contribute to making texture maps. So what happens when you’re a month from going gold? You need lots more polish on your texture maps, but you’ve got all the character animations done and nobody wants to mess with them for fear of breaking something.
What do you do? Force Barb to take her vacation here in October? I’m sure she’ll love that. Fire her and re-hire for the job in a few months? (If your dev team is owned by EA or Activision, maybe yeah.) Jam her into a job she’s not trained for and let her make low-grade assets?
Building a game is like building a house. You don’t need the roofers until the end and you only need the bulldozer at the beginning. House-builders use contractors to manage this sort of thing, which isn’t nearly as applicable to game development.
Keeping everyone busy and doing meaningful work is a major challenge. It’s yet another reason that games have gotten so expensive.
It’s also part of the reason behind day-1 DLC. (Not that I’m super-happy about the practice, but I understand the appeal it has to the bean counters who are looking at the idle artists at the end of a project and wondering how they can be made useful.)
Carmack said this meaning, “We’re in media blackout mode”, but I couldn’t help hearing this as, “The game will be riddled with hilarious and crippling bugs at every turn.”
Still, this is part of the cost of giving up their independence. They no longer get to talk about their own games until the folks at Zenimax say so. Alas.
The Game That Ruined Me
Be careful what you learn with your muscle-memory, because it will be very hard to un-learn it.
Marvel's Civil War
Team Cap or Team Iron Man? More importantly, what basis would you use for making that decision?
The Strange Evolution of OpenGL
Sometimes software is engineered. Sometimes it grows organically. And sometimes it's thrown together seemingly at random over two decades.
Even allegedly smart people can make life-changing blunders that seem very, very obvious in retrospect.
The Best of 2013
My picks for what was important, awesome, or worth talking about in 2013.