Georg Simmel (German sociologist, 1858-1918)
A game jam can be a wonderful experience. At its best, it energizes you, gets you in contact with new people, allows you to celebrate gaming culture, and lets you reconnect with your skills and your toolset. This year's Global Game Jam, in which I participated in the absurdly beautiful city of Aix-en-Provence, ticked off all these boxes, making it one of the best I've experienced. The local team of organizers was incredible (freshly made sandwiches - need I say more?).
Now, two days later, I find myself constantly thinking about a key mechanic which I (sole programmer on a team of tremendously talented environment artists) developed for our entry, which we called East German Space Prison Break. The idea of the game was simple: you are inside a large cube made up of corridors and intersections. The structure can be moved and shifted like Rubik's cube. Just like the famous toy, you have to 'solve' this prison in order to pass through corridors and find the exit. Since you're also inside the structure, this isn't easy. Here is a Vine of a single rotation.
Implementing the rotation mechanic wasn't difficult, but it wasn't trivial either. The way I did it, however, was very much at odds with the way I would normally have done it. My solution was a hack in every way imaginable, yet I usually pride myself on being an engineer. This tension has led me to think more about the distinction between hacking and engineering, how it is usually (and IMO falsly) regarded, and how it relates to game jams and game development in general.
Hackers vs. engineers
Hackers, hacking and hackathons have been 'cool' for a number of years now - as illustrated by movies like The Social Network or TV series like Silicon Valley. By comparison, 'engineering' still seems to evoke connotations of boredom and creativity-stifling solidity. Engineers may garner respect, but you'll probably never see one on the front page of GQ.
If you do a search for "hacker vs. engineer", you will find an astonishing number of pages proclaiming that hackers are actually a deficient kind of engineer, rough stones waiting to be cut by the exertions of a style of thinking that emphasizes correctness and generalizability. Hackers may be creative, edgy and fun, we are told, but they lack the deep systemic knowledge and self-discipline that leads to true technological mastery. Unsurprisingly, an equally large number of pages, sites and books tries to highlight the advantages of 'hacker culture' over traditional engineering.
After last weekend's Global Game Jam, I disagree with both views. Hacking and engineering are two styles of problem solving that are quite distinct, but they both have value. The trick is to know when to apply which style. By way of illustration, allow me to show you the hack I developed for solving the problem of the cube rotations, and compare this to how a more engineering-oriented solution would have looked like.
Making the cube rotate
It is Friday evening, the clock shows 23:30, everybody on your team is working on their first set of tasks. The artists are happily - and loudly - scrolling through page after page of reference material, arguing which kind of ageing metal effect might look good in Unity's new PBR shader. Those lucky bastards. You, the lonely programmer, are already in the grip of the anticipatory anxiety that comes from thinking about a problem whose solvability is obvious, but whose actual solution eludes you. Google, otherwise such a generous mentor, has been unwilling to solve the problem for you. You must figure it out for yourself. Your brain is foggy, thinking hurts ((c) Simmel), but you have to make the godforsaken cube rotate along its 3 principal axes.
In this groggy state of mind, I tried make an effort to at least understand the problem more clearly. Wasn't that already supposed to be half the solution? A space prison-slash-cube is made up of N*N*N little cubelets which can be created as individual GameObjects in Unity (or Unreal, or...).
Saving the cubelets in a multidimensional array wouldn't help when rotating sides, so I decided to store them flatly instead. Calculating array indices from a given set of coordinate indices (x, y z) is simple:
newIndex = N*N*x + N*y + z. The operation of visuallly rotating slice A on axis X, Y or Z turned out to be equally trivial. Just calculate the center of the entire cube and let Unity's
Transform.RotateAround() do the rest for each cubelet. However, this messes up the logical position of the cubelets in the array, which therefore needs to be reconsolidated. For that, you first need to extract coordinate indices from array indices, recalculate the two indices that are not aligned with the rotation axis, and then retransform the coordinate indices into the new array index.
Well, you would need to do that if you were still able to think like an engineer, which I wasn't anymore at that point. Thinking hurts even more when you're tired. I was ready to quit. But then it hit me: I don't have to do the math myself after all. Here's why. As the team programmer, I could decide that the cube would always be aligned to the global axes. This meant that the new 3D-coordinates of the cubelets (the ones resulting from the rotation) already contained the new coordinate indices! For instance, a cubelet that was at
transform.position = (0f, 100f, 0f) might end up at (0f, 0f, -100f). I only had to account for the difference in scale between the (huge, walkable!) cubelets and Unity's game units, plus take care of numerical errors (after all,
RotateAround() isn't numerically robust).
Problem solved! I was almost surprised to see that this approach worked right away and didn't have to be revised anymore during the jam. But part of me was also ashamed. Writing such code just wasn't me. It obviously depends on several assumptions - e.g., other than aligning the cube with the principal axes, the position errors generated by
RotateAround() must never be greater than .5f, otherwise
Mathf.Round() will return a false index.
However, none of these assumptions are really risky in the game's context. What's more, after a few tests I realized I would have to mimimize numerical errors generated by repeated uses of RotateAround() manually so that the entire cube structure wouldn't start to disentangle after a few turns. In other words, cubelet positions along the global coordinates had to be aligned to coordinate indices anway, so I might as well recycle them like in the code above!
What I learned
For me, as someone who tends to identify as an engineer, the lesson was that sometimes a hack really is the best way of approaching a problem. If you've ever looked at the famous Jargon File, one of the origins of modern hacker culture, you realize that hacking has always been about making efficient use of scarce resources, especially the developer's time, money, and processing power. When two solutions both work reliably and efficiently, it makes sense to prefer the one that takes fewer resources to build.
The issue of hackers vs. engineers is often framed as a question of identities, as a clash of cultures. I don't think that's healthy. In the future, I would like to be better at deciding when to develop a solidly engineered solution, and when to put together a hack that works. Neither is intrinsically better, and deciding between the two isn't always easy. But I can't think of any field in which mastery of this meta-skill might be more useful than game development. Some problems in game dev are so recurrent, so standardized that they have led to the emergence of a heavily commoditized tools industry in which prices are already racing to the bottom. Other problems are so absurdly context-specific that we devs can't even be bothered to write unit tests - "This will only be called once anyway" etc. Sometimes we mistake a general problem for a context-specific one, or vice-versa. But I at least would like to be more aware of the opportunities of both hacking and engineering in the future, and be more conscious in my choice of either.