VERGER: ruminations on generation


When I started work on VERGER, the term "procgen" still mostly eluded me. I knew people made games like Dwarf Fortress and Caves of Qud (which I absolutely love), and that swaths of those worlds were rendered through algorithms rather than "by hand". My use of procedural code, however, had never gone beyond shuffling cards or similar "random" choice functions. I loved the idea of spawning terrain or creatures or narrative chunks according to more complex rule sets, but I had no sense of how to achieve it.

As such, my early implementation of these concepts in VERGER could best be described as "rocky", or even "a jagged field of debris upon which I ceaselessly impaled myself". Neck deep in tutorials on tile grids, item and obstacle distribution, and stat-based combat, I somehow managed to get a loop up and running, but the results were pretty bare-bones. My saving grace was being so unfamiliar with the genre that checking off even the most basic tasks gave me an inflated sense of accomplishment.

On the other hand, I discovered that a little aesthetic polish went a long way in "elevating" my prototype to something you could actually stand playing even after you realized how one dimensional it was. Simple animations and particles, punchy "analog" music & SFX, and, shortly after the jam, randomized "weather" added unexpected depth to the crude trappings of my tiny world.

The satisfaction of these small touches, more than anything else, kept me interested in the project. When I butted up against PICO-8's token limit, porting my code to LOVE allowed me to deepen gameplay without worrying about "memory" optimization. Here came bigger/more interesting monsters, better power-ups, an upgrade shop, etc. I also began experimenting with visual flair like CRT shaders and animated text.

After months of chipping away, I had a much more robust prototype in hand. My world-generation algorithm had been hardened by many small tweaks and constraints, and all of the core mechanics had undergone several passes to improve coherence and playability. There was still loads of room for improvement, of course, but the basics felt solid enough for public consumption.


All of which seemed well and good until last week, ten minutes after I uploaded my MAGFest demo submission. I'd been feeling great about my new tutorials, refined enemy behaviors, and clearer difficulty curve. Most of all, I was excited to keep adding stuff — aaand that's where the terror set in.

The problem was that, as a piece of code, VERGER had no underlying mechanisms to handle the kinds of interactions encouraged by procedural design. Every time I added an item, entity, or weapon class, I had to manually script how it would interact with other objects in the game. New terrain tile? How does it react to being struck by a player-class entity? How about a guardian-class entity? OK, but what if the guardian has an ice weapon?

The sum of these realizations was that I still didn't really understand procgen at all. Or, a little more generously, I had grasped it in a superficial way, only to immediately bumble off the cliff of my underlying ignorance. Not having any immediate community of folks I could hit up for advice, I returned to the tubes.

I knew I needed to make my object code more generic while still preserving the unique properties of items and tiles. To this end, I tried to break in-game objects into broad categories, settling on three overarching "types" -- stuff that could be picked up, stuff that served as a point of interaction with some other system (i.e. doors or mana pools), and terrain, which either served as an obstacle or could be destroyed to reveal one of the other two types.

In the midst of fumbling towards the above, I watched Brian Bucklew's 2015 IRDC talk on data-driven design , which basically blew my mind for a couple weeks while I tried to parse it. Bucklew's object management system is both a concise, scalable solution to the problems I was dimly grappling with, and a really helpful window into how people who understand software (i.e. not me) think about this stuff. I also felt validated that, at least in some small way, I seemed to be asking the right questions.

Since then, I've been wading through some of VERGER's oldest code — the garbage fire at the center of the universe — slowly refactoring the molten nuts and bolts. So far, I've successfully converted all existing objects/tiles into the types described above. I'm actually starting to wonder if there's really just one type — but I'm  not ready to take that plunge just yet. Now, instead of triggering ultra-specific conditions hard-coded into the game loop, objects are simple, JSON-like data structures with prepackaged "physics" values, function calls, etc. that are fed into a generic update engine.


^(do you understand this? i don't)

I've also rewritten my world generation code to handle multiple maps per season, each with variable sized "nodes" (screens). This opens up the possibility of dungeons and other interior spaces — each with their own entities, timers, goal states, whatever — that are dynamically generated as the player discovers them. The player's in-game "house" and current shop have, so far, proven out the viability of this approach, though I'm sure its shortcomings will rear their head sooner than later.


The funny thing about working through these challenges is that (for me, at least) it's so damn hard to tell when you're actually doing good work. As someone whose sense of things like "skill" and "progress" mostly emerged through process-oriented arts, evaluating the value of something as constrained as code often feels sort of impossible, especially because, in so many cases the changes are invisible in the end product.

If I was working on a team or under a more experienced engineer, my work would likely be subject to external evaluation. As it is, I just hack away until I get something resembling my expectations, then move on to other tasks until mistakes I don't know I've made start biting me in the ass. This is a deeply uneducated strategy at best, but I learn a lot as I bear headlong into brick wall after brick wall. Sometimes I solve cool problems above my pay grade! If nothing else, I emerge from each heap of rubble slightly more experienced than before.

Case in point: this post took way longer to write than the first two, largely because I wasn't sure what I was trying to say until I'd failed half a dozen times. Now it feels done, but I'm not sure I could explain how or why. More chipping away, I guess.

Fuck it. Thanks for bearing with me! More to come soon.

b

Comments

Log in with itch.io to leave a comment.

(+1)

This is looking good, I agree that working solo really makes it hard to know if you're making the "correct" decisions\progress when it come to adding features and knowing if A,B,C is fun\intuitive for others.