Reusable game systems + Iterating on a "base"

The other day a friend linked this twitter thread: https://twitter.com/RustedMoss/status/1678809365975793664

I thought it was fairly neat that just starting with one system, (hair physics), by throwing it into a bunch of proof-of-concept demos it started to become clear what it was actually useful for (grappling hook mechanic). It kind of reminded me of another short talk I had seen some time ago where a developer over 20 minutes ran through about a dozen different scrapped projects. They were all platformers and it was pretty clear by the end they were basically all stemming from a single “base project”.

In theory putting together a base for a platformer is pretty straightforward if you make some assumptions about the types of things all of the theoretical platformers you’d ever like to make need. For instance:

  • Movement + Collision system
  • Player controller (ideally pre-tweaked for good gamefeel)
  • Animation state machine
  • Loading/Moving between maps or levels

With some other optional nice-to-haves

  • Health, game over screen
  • A basic “enemy” entity (kills/damages you on contact)
  • Combat system (hitboxes, animation frametimes, “hitstun”/gamefeel)
  • Depending on the engine, you may need some integration with third-party tools like level editors and such too.

Obviously all of these things are pretty well documented and solved features for most game engines. That being said, implementing them in a way that your future self could reuse and iterate on is not always that well explained. I don’t think what I’m saying here is that revolutionary or anything, but I don’t think I’ve ever put something together that really functions well as a “base” like this. I think there are some architectural concerns that you have to work around that you wouldn’t necessarily think about if you had a singular vision for a game and tried to just quickly make THAT idea specifically. You might want to engineer as much as you can as “modules” - things you can plug in and out depending on what you actually need. No need for a combat system if your game is just insta-kill spikes you have to jump over, for example.

I’m sure a lot of devs already work in a way like this, but it’s totally a skill in it of itself to write code that is easy to recycle throughout the future. Part of why I think I have avoided this kind of development is that I do tend to stress on implementing things super “broadly” and delve into just refactoring every couple months, when the truth is you just aren’t able to write code that adapts to every single situation or requirement you might have.

It does sound really useful to have something like this where if I do get some spark for a game concept, I could spend a week just playing around making the singular feature I have an idea for, and trust the rest of the boilerplate mechanics already work to my liking. You could start up and completely scrap something new every week until you find something that feels cool enough to turn into a larger project. And as you build and release smaller games, your “base project” over time gets more and more refined with features, and players can track over time the way your concepts improve.

Platformers are pretty straightforward but I’d be pretty interested to see what an architecture like this looks like across other genres, too, like RPGs, zeldalikes, and such. It could also be neat to build out some sort of “general use” base for people, and do a kind of challenge where different groups try to expand on it in different directions, gamejam-style. I’d be interested to hear if you know any devs who have work well in this way, or if you have any thoughts on how you approach this kind of modularity?

Coincidentally enough, Melos Han-Tani, who has worked on the anodyne games just wrote something about modular code with a lot of real examples of systems that are shared between multiple of their studio’s projects.

Really neat read! cohost! - "Tiers of Modularity in Unity 3D Programming for Single-Player Adventure Games"

I think the most interesting tidbit from this is that the event/cut scene scripting and editing is considered pretty modular. For reference most of the games they have made are pretty different in format, zeldalike, 2d platformer, 3d platformer, or sometimes switching between all those things in one game. So cutscene events need very different things for all those formats. In retrospect it makes a lot of sense that you could do this in a pretty modular way, because all an “event runtime” is is just something that steps through a list of actions, or maybe does some conditional logic or loops around that action list.

To that effect, a modular “base” for something like that would need a few basic event commands for starting and terminating cutscenes, a few for checking branching, and such. Then on a per-game basis you’d create a way to register individual commands unique to that game, for example showing your textboxes, or moving players and objects from point A to point B, loading different maps etc. The event runtime doesn’t actually perform any of that, it just delegates the work to whatever functions you wrote to “handle” those events. You’d have some sort of ObjectMover thing listening in for movement events broadcasting from the event runtime. It’s a good way to think about it! Basically a combination of these concepts: observers and commands.

Kinda makes me want to write a bit on cutscene/event scripting and the work that goes into those.

This is something I’ve thought about a bit and I think it is not only a really useful technique, but also vital for any independent developers who do not have the resources or manpower to reproduce major systems, especially basic ones, on a project-by-project basis. Recycling these elements should probably be in every indie’s toolset. I’m sure there are probably too many indies hardcoding values and siloing resources; I know I’m guilty of it too…

At the same time, I do worry that issues like grandfathering in issues if taken too far. For me, a key question is also what not to reuse. For example, a jump, while generally pretty easy to create has a lot of minor variable that can be tweaked and edited, and reusing that resource may limit you. Perhaps not literally, but as a developer, it may be easy not to rethink such a system when it may benefit from it. Now, of course, as you’ve mentioned, it’s important to create systems that are designed to be reusable and reworkable. And a jump is sort of an extreme example. But I think it is a key part of this, too.

I want to read that Han-Tani post soon, because just based on the title, I think this probably gets at this issue: recognizing and having a framework to understand not just how reusable a given system is, but also how to build it and when to reuse it.

yes this is a super good point! I think it’s also one of the pitfalls that come from worrying too much about perfectionism. Platformer jumps are something that gets a ton of attention from “games design” people, partly because it’s so ubiquitous in games. Like for example a ton of people reference this twitter thread on jumping physics and game feel from celeste: https://twitter.com/MaddyThorson/status/1238338574220546049?lang=en - and yeah there is a lot of good stuff here that serves the game well. But I also get the impression that we may be a bit eager to take these things as “canonical” to platformers, for instance later on this comes from those same concepts: Can you fix this platformer? - YouTube . though this is also part of (newish) phenomena of more sensationalized game design, which probably deserves its own discussion lol

These features have a number of considerations: some are accesibility, helping players who don’t have the same reaction time, some are design, like making sure/enabling certain types of jumps/platforming, but they are all mostly game feel choices. All these features are well thought out and serve a specific purpose for Celeste. But if you aren’t making Celeste they might not actually have the same effects on your game. So treating all these things as your baseline kind of leaves out projects that may be better suited feeling some other way (even “worse” gamefeel-wise, which can be good sometimes!), either by ignoring these rules or introducing features antithetical to them.

I don’t think any of this counteracts the importance of building out reusable things though - because often enough you simply won’t know what key change/feature makes your game stand out until you are actually putting it into test and iterating on it. So removing as many “well first I have to make…” situations as possible helps you actually reach the point that you can figure out what would be cool to tweak or design around.

Before I started doing game jams, I was working on a project in a different engine that ended up being much too big to finish. I tried hard to modularize the code for reusability, and I spent a lot of time drafting, architecting, and refactoring to keep things separated and avoid circular dependencies. Unfortunately, since I ultimately abandoned that engine entirely, it all ended up being wasted effort.

What worked out a lot better, though, was using a game jam as a springboard to a bigger project. I used the jam time to throw together a very basic RPG with only the most needed features, and I finished it. Afterwards, I was able to build on that successful base to create something much bigger and more complex (my current project). Whereas with my old abandoned project I had bitten off way too much, now I was able to get results by starting small and stepping up. My next RPG in turn can build on this one.

On the other hand, though, most of the actual code is not very portable or modularized, aside from some pretty generic stuff like object pooling that is easy to pull out. Part of this is because, since it originated in a jam, it was written quickly and not really architected for modularity; part of it is because Unity’s workflow isn’t designed around namespaces, so it’s easy to form sloppy habits and just leave everything in the default space.

Right now I am pretty much in the mindset of just trying to finish things by any means necessary. Getting things working and shipped is the priority. Honestly, I don’t really have a clear picture of what major functionality I would even want or need to reuse later. It will probably become more apparent as I make more games, and then I can make the effort as needed to extract and modularize what I need.

Definitely true that thinking about this sort of modularity is one of those ‘best laid plans’ situations. I probably can’t count the number of times I’ve told myself “I’ll make the definitive version of this system, then I’ll never have to code it again!” to then simply never even use it again. I think particularly when you are exploring things and jumping around engines a lot, that kind of workflow isn’t really attainable.

I think the truth is, for at least what I was thinking of when I first wrote this - you have to have a really specific frame in mind for your games, and know that it is more or less the area you want to explore for a long time. When it comes to game engines, most examples I can think of are usually people who are using their own custom framework they’ve been tinkering on for years. So maybe it’s being locked down to a toolset that is purpose-built for one type of game that encourages that rapid iteration time.
To me it’s really cool and unique to see developers who work in that way though. One name that comes to mind is sylvie - https://sylvie.itch.io/ - though i’m not sure what these games are made with from initial impressions. The web loader looks like construct2/3?
While not specifically one developer something that feels pretty similar is puzzlescript. I think there are some who do this kind of thing with tools like bitsy too, but it doesn’t feel quite the same without some level of experimenting with mechanics between individual games, which bitsy doesn’t give you a ton of space for.

So maybe there’s just a very specific type of developer who this method suits best - hopefully there’s still something to learn from that :s

This probably is the approach that suits most people! It sort of gets to the crux of the age-old “make games, not engines” approach, one that argues your time is better spent just achieving the goals for your game, instead of creating some grand framework and trying to fit your game into it (you already have to do this if you learn a big game engine!). Once you have a really solid idea and plan in mind, the best thing to do is probably just work on that, and not worry about the sustainability.
This probably rings especially true for RPGs - where unless you make a direct sequel, you’re just going to have so much mechanics-specific code you can’t really hope to build out anything modular in the first place. Maybe the one thing I could think of, is if you put a lot of time into building out a system for storing and reading stats (plus modifiers like status effects, equipment passives, what have you) and pair it with a general system that reads stats and produces a turn order, maybe capable of emitting events - you could possibly reuse that with some tweaking for the ‘backend’ elements of an RPG, but nothing hooked up to UI or even to combat formulas…

I think it’s kind of hard to say whether it’s better to stick to some rigid formula and just make the smallest of tweaks rapidly, or to just as rapidly make a ton of things different ways until you find something that clicks. I think what’s good about both those methods is that they are very focused on just experimenting without a ton of forethought - and a lot of the trouble comes from trying to make something so all-encapsulating that you end up just doing nothing but unrellated chores that are supposed to “build to” the thing you actually WANT to make.

That being said, that sort of thing isn’t bad on it’s own… I do it way too much, though most the time I justify it as just trying to learn lower level concepts and try not to feel like I’m committing to getting value out of it other than just better understanding of things. Maybe that’s just I lie I tell myself to feel better about working on those things instead of actual games hahaha

Using CPP and SDL2, I have some functions and classes that I recycled, recoded, and extended over the years. I tend to avoid doing them from scratch, since setting new naming conventions or mechanics for these very basal functions/classes usually only confuses me without any positive effect.

Note that I talk 'bout most rudimentary stuff (calculating distances in 2D-Rooms; parabolas; drawing Sprites and animate them, drawing buttons, etc). Things like movement/ctrl/interfaces/etc should be remade to match the game.