what if we don't need to write flexible game code?
lately i've been thinking about code architecture in game development. I decided I'm not going to just use Godot as my all-purpose solution, and that I'd rather code in a less bulky framework environment, of the likes of love2d (my current pick), FNA, raylib, Haxe, pico-8, etc. and so architecture and code organization has become more of an active question for me. I began watching various talks and reading this book that, if you're into this stuff, there's a pretty good chance you've heard of before! it's really good.
as I began to read it, I felt critical of the core assumption it proposed about why we concern ourselves with making useful game architecture. according to the book, we do so in order to make code easier to change, or more specifically, to make it easier on ourselves to expand the game. I wasn't disagreeing with the book's definition of code architecture, but rather my thoughts went to a deeper level, that perhaps the way we approach game programming is flawed.
I'll start with the theoretical, then come back around to practice.
when making games, we tend to think of the game as existing somewhere in ideaspace before it's made. our imaginations are so powerful that it is easy to grant the things we envision tangibility before they even exist, to the point where they feel real without yet being so. what we have are imagined sensory impressions of something we would like to exist, rather than a thing-in-itself yet to be borne from our minds. this discrepancy comes up near ubiquitously in the realm of art creation, and is a classic source of angst for beginner and intermediate artists who can picture what they want but can't yet create things to the level they envision.
what I am suggesting is that this process is the same in game programming, to an even higher degree of discrepancy due to just how complicated and divorced from basic sensory experience games and computers are.
we imagine ourselves to be david besting goliath, taming the wild binary beast to inject our vision into silicon flesh, effortless and triumphant. this is a common unspoken "dream" of how programmers ought to approach computers and think about using them that I propose we reexamine.
embracing the material 'computer'
what if instead of computers being an intermediary we haggle and negotiate our visions through, we thought of our computers as the instruments they rightfully are? you don't play a trombone to get the sound of a drum, you play a trombone to make the most of the trombone as the thing it is. what if our game ideas were just ideas, and we must accept that, as they are created, their confinement to the material limits of what our computers and the code on them do? coding fills us with a broad sense of possibility, but it is bound by limitations based on both the computer and the nature of how we interface with it as large text documents.
rather than searching for the holy grail of flexibility and extensibility, I propose embracing limitations thoughtfully.
limitations and creativity
it's pretty well understood that limitations tend to enhance creativity. the topic is well covered, but I'll highlight one aspect of it: when we accept the limitations we're working under, our ideas focus on what the possibilities are in front of us and what we can do with them. our creativity becomes tempered with pragmatism, with material considerations, that helps us spend more time putting tangible things to page.
in the 8bit through 32bit eras, these limitations were immediately tangible just by setting out to make a game. especially when you're writing in machine code, working directly with the computer as the thing-it-is is already baked in. additionally, today we have this sense computers can do "anything," yet what computers could do was much more strictly defined 30+ years ago. one of the reasons games from this era were so unique and creative is exactly this, their built-in limitations pushed creators to be thoughtful, intentional and practical with what they were making, to interface closely with the capabilities of their hardware.
a similar dynamic exists with modern purpose-built game engines, such as RPG Maker and Ren'Py. rather than promising an ocean of possibility like all-purpose game engines do, they give you a specific set of tools that help make a specific genre of game. the tool doesn't have to be about being able to do everything, when what it does offer is enough to make compelling creative works in a usable package.
in computer applications, ease of use is widely understood to be in opposition to functionality. it's not a direct relationship, as things like good UI can do a lot to improve the functionality-to-friction ratio, yet overall this is how it is. I propose that the same goes for game code architecture, as all the same principles are at play. we can make good programmatic interfaces that compress the value-to-cost of the convolution we're adding, but fundamentally we're always adding convolution.
purpose-built engines like RPG Maker and Ren'Py operate on notions of "just enough" in finding where to draw the line in functionality. when you pick up a purpose-built engine, you're incorporating its limits into your creative process from the outset. this turns limitations from something to be fought against to an ally in your creative process. it might empower us to do the same in how we go about programming games
what if, when going to code our games, we decided the limitations first, and then worked within them from there? doing so greatly streamlines the process of architecting your game, as every system you build is going to fit your needs from the start: no more, no less! and then, those systems you do build can be maximally optimized for usability within the given limitations, giving you a toolset to work within that might vaguely resemble a purpose-built engine of sorts.
I suspect this might be a challenging mentality to adapt to, especially as it requires more upfront planning and scoping, but for any of us who are production-oriented it can do a whole lot to keep us on track. there's always the siren's song calling us to add more features, to implement an idea that requires adding a little more extensibility to our code, but it quickly becomes a slippery slope. ideas can either be workshopped into a version that better fits your engine's current capabilities, or they can be saved for a later project that can incorporate their needs from the start. this begins to get us into a wider conversation about treating our projects a-little-too-preciously, or try to make each thing we touch into an opus, but I'll taper off there.
if there's anything I want to emphasize, it's that the ways we make things should be serving us, and it's something we all need to check in with ourselves about now and then. in my recent research I heard no shortage of horror stories of indie games that went through multiple engine rewrites over the course of their 5-15 year development cycles, and I have to think there's a better way for us to do this stuff--if Capcom could pump out 1-2 beloved Megaman games every year with a development team of six on NES hardware and computers we'd typically declare "unusable" now, I'm sure we're far from the best we can do. not just for productivity's sake, but for the wellbeing of our own creative spirit, as drawn out projects tend to wear on even the most disciplined creator. we want to make things we enjoy making, are excited for and proud of, yet much of the common practice on how we do so can lead to anguish rather than empowerment.
ultimately, each person has their own interests and needs that serve their process. I haven't personally encountered this point much yet, and I hope it may serve you somehow. these words as for you as much as they are for me, as I continue refining how I approach my own practice.