My carefree days of hours-long coding sessions are on hiatus, it seems.
Well, at least are coming in more sproadic than in the throes of mid-winter.
I still am managing to find good blocks of free time to work through tickets, adding small enhancements, squashing bugs, and tweaking algorithms. The game creeps towards some kind of state of playability.
And that’s the first key here, I think.
I spent two months working and committing code almost every single day, and all of that culminated in a thing that looked and played like an alpha-state game. Which is a big deal.
Getting that same game to beta? That’s going to be the work of a few more months of work, lots of art, lots of writing, lots of hunting bugs. I mean, I now have an entire category of tickets that is called “playtesting” by which I sort things that I’m pretty sure I have fixed but until they crop up naturally in the middle of play—or I play long enough to feel confident that I fixed them—there isn’t much to do (besides maybe writing some tests) to ensure that they are working.
And that’s the second key here, I think.
This game thing I made is big and complex and—hell—its a simulation and it rolls along simulating and doing stuff behind the scenes that are the result of compound effects of algorithms that I wrote. Calculate this, math that, compute these. And it is deeply fascinating to see that at work—but it is anything but simple to untangle in my own head to know if it is actually working.
I did the most dad-gamer thing the other day. I ordered a copy of Civilization VII (which recently released) for my PS5, but I ordered it using airline points. Yeah, I had enough spare points to buy a ninety-dollar new release game and yet I still have bank. But I have been watching the reviews of the new game (and I have played all six previous versions when they were new plus the spin offs) and people are pickyAF about the mechanics. This game that is so complex it is almost an organic lifeform in an of itself, doesn’t behave exactly how people expect and they rant and scream online about how terrible it is.
And that’s the third key here, I think.
Players can be particular. They want complex things but they also seem to hate complexity. Pleck’s Mart is no Civ 7 on the complexity scale, but I wrote about complexity previously when I compared this creation to Dwarf Fortress and the complexity of Pleck’s Mart has definiely increased since that post. Yet, with complexity comes unpredictability, and simultaneously the inability to game out ever combination of that complexity.
How do you trust it other than to play it and have many other people play it and then be ready to nudge it back into balance if the balance is not as tuned as one might think?
I have recently been accused of writing things that no one understands.
“I don’t even know what half those words mean.” A friend remarked. “All that stuff you post about your game.”
The effort of trying to bring a glimpse of a guy trying to do some simple game design to the masses is as difficult as the coding, it seems.
The problem is that coding and technical stuff is jargony. It is tough to describe complex things, after all, without falling into the easy rhythm of just using the complex words.
And, it turns out, if that isn’t a metaphor to describe the challenges I encountered in my code this week, I don’t know what is.
Falling back on the easy, I mean.
It wasn’t so much that I shortcutted or made bad decisions, per se, but rather that in my effort to do something complex I described it to the compiler—I wrote code—in a way that, um, confused it a little bit.
My code got just complex enough that I ran into one of those juicy jargony words that begrudge programmers all over the world: race conditions.
Let’s back up a bit. What the hell is coding anyways?
You probably know or have heard that computers speak binary. Zeros and ones. Right? And that is true. Virtually every computer program every built for every consumer product relies on binary computation. (I could go on about quantum computers or analog computers or whatever, but let’s keep this simple, shall we?) Digital computers speak binary.
I’d love to be able to spit out a string of zeros and ones long enough to fill a library and not make any mistakes and do so well enough that it results in the computer making a game called Pleck’s Mart that you all want to eventually play. But I will never be able to do that.
I can, on the other hand, write down all those complex ideas in a text editor in a language called Rust (which I have been learning quite well) and then ask this little bit of software on my computer to turn it into that string of zeros and ones so that it becomes said game.
That’s coding. Writing out complex instructions for a compiler to turn your plan into binary numbers.
And knowing this, you should also know that this can fail in two basic ways: Either you can write code so bad and wrong that the compiler tells you it kinda sucks and you should fix this or fix that and go back and try again because it doesn’t understand—or, you can write code that makes enough sense to get translated but results in something unintended happening when the computer starts mathing and computing all those resulting zeros and ones. We call the first bad code and the second, usually, a bug.
The first fail, bad code, happens to me a hundred times per day, and I go back and fix stuff. I mistyped a variable or forgot to make something mutable (flexable and changable in the system) or missed a semi-colon at the end of a statement or—the list goes on.
The second fail happens alot too, but is occasionally more subtle in as much as you don’t notice that the results are wonky until you really do. Easy to spot bugs are incorrect coordinates on sprites or calling a valid but incorrect variable or switching the signs on a math calculation. The hard ones are things like the thing that bit me in the butt this week: race conditions.
To understand this you have to also understand something that is probably pretty basic but important to my point: computers are fast. Freaking fast, these days in particular, but they have always been way faster than we realize.
You can look at this little video of my game that I recorded yesterday of things on the screen and realize that there are about five hundred individual images on the screen, each a file that needs to be loaded into memory, and simultaneously the computer is reading information from the screen, the mouse, the keyboard, my gampad controller, playing music, loading up individual click sounds for the little interactions, checking the math to see if anything I do causes any two of those little image files in the pretend space of the screen to crash into each other, and about a hundred other things I can’t even keep track of—and it is doing all of that on repeat over a hundred times per second.
Per second!
And I, the invisible conductor of this crazy digital symphony, need to to have staged all of that down to the millisecond.
And when things are simple, nothing really deeply goes wrong. At least not wrong enough to matter.
But then things get complex and—well, let’s go back to that symphony analogy: I play in an orchestra so believe me when I say it is easy for things to get out of sync. The timpani is pounding out a steady beat but then the clarinet comes in half a second late and the violas sitting next to the clarinets try to pace them, but the violins are watching the conductor and timing themselves to the baton, and then the trumpets who can’t hear anyone but themselves way at the back decide to wing it and jump in too. The result might be music, but it more likely will just become noise.
One thing got ahead of the next thing and the thing that was supposed to be following in a planned order happened out of sync and—that’s kinda a race condition.
In coding, as I understand it, a race condition is when the code is not exactly wrong, but you as the coder have not put in the right set of rules to stop things from getting out of sync.
On a small program you might not even notice.
On a growing and complex program? Chaos ensues. If things don’t crash outright, then you suddenly have eighteen soundtracks playing because they are not properly being removed and replaced, or all the objects in your room spawn a mere half a second before the rest of the room making it look like ten cases of tomatoes just blipped and appeared in empty space for a moment, or else your player flashes brightly because the lighting effects took effect a beat too late to maintain the illusion of that shadow you had meticulously coded. But then, mostly, yeah, mostly it just crashes. Or bogs down to a crawl as eighty-seven thousand copies of your player sprite spawn into the program and the computer (as fast as it is) just throws in the towel because even it isn’t that fast. And then it crashes anyways.
These things are not laziness in coding, but they are me making assumptions about that long string of zeros and ones and assuming that the computer can make sense of them as much as I think it can without tripping over its digital shoelaces.
They are adding a dozen more musicians to the orchestra and just hoping they will all keep perfect time.
Thankfully Bevy, the game engine I am using, has mitigations for this. I have spent a few hours restructing my code to give it a little bit more of a compartmentalized order and some timing conditions. That, for people who thing I am being to jargony, just means that I can specifically tell the computer to wait for one thing to happen before starting something that is supposed to happen after it, and I can also tell something else to count to ten and hold its breath before doing something else. Like cues and an enforced script, mostly. Sheet music and each musician with their eyes glued to the conductor and noise cancelling headphones so that they can only hear themselves. No more winging it and hoping for the best.
All of these challenges are themselves spawning out of something good, tho: progress. Real progress. The game is moving forward. As much as my code is occasionally tripping over itself, that can be managed and fixed, and the result still is that the game does something this week that it didn’t do last week. It’s progressing.
In this phase I have dug into objects: stuff on shelves, mostly. I built the core functionality that allows the little guy (who up until now was just walking around exploring) to order objects from the shop, carry them around in an inventory and put them onto shelves, pick them up again, and put them somewhere else.
And it is weirdly satisfying to organize cases of vegetables in the store or the warehouse. So long as the game isn’t racing and crashing that is.
I’ve been thinking a lot this week about Dwarf Fortress.
Have you played Dwarf Fortress?
Have you even heard of Dwarf Fortress? It’s a bit of a #iykyk kind of game, but one that some gamers have #k about for almost as long as the game has been in active development, which is well over 20 years.
Two guys. One dream. One insanely complex game engine that fools you into thinking it is simplistic because its graphic design is, bluntly, outwardly visually rudimentary and (until recently) completely composed of colourful ASCII text characters.
I’ve been thinking about this game, Dwarf Fortress, because as I develop my own little game project I’ve come to realize that many games, at their core, are essentially just pretty user interfaces for databases of varying complexity. I mean, I knew this. It’s always been my core understanding that to be a good games designer that at among many things you need a solid awareness of database design in your toolkit.
My game is a database at its core.
I’ve mentioned this in a past post, but in creating my game I’m essentially designing a fancy UI for a really complex accounting ledger spreadsheet. THAT doesn’t sound nearly as much fun as a Science Fictional Supermarket, so you can see why I don’t lean into the former description in my marketing copy. That said, I am friends with more than a few accountants who might be into that, so—
But I digress.
Dwarf Fortress has been in active development for more than twenty years, because as the (perhaps apocryphal) story goes, the developers can’t seem to stop adding more rows and columns and macros to that game-as-spreadsheet metaphor. The game is insanely complex. It is like the Matrix of database queries but with the cascading text representing dwarves and sheep and weapons and logs and, heck, I can’t even begin to name a fraction of a fraction of the elements here. I sure there is complexity layers in the game that are games in and of themselves that barely a handful of players have even discovered. It’s complex. Have I mentioned it is complex?
This complexity is on purpose, of course. (I assume.)
I know many gamers who are (you know who you are) into wildly complex games with rules spanning many dozens or hundreds of pages, and in some cases, rule systems. DnD is essentially a giant rule system, that has depth and a bit of complexity but tries to keep it simple enough for our human brains to keep up. But Dwarf Fortress seems to embrace the complexity in the other direction and has both depth and complexity. Thousands of variables tangled in around themselves.
Pleck’s Mart has from nearly the beginning had a database. But until yesterday that database was almost entirely about saving states and progressively loading game data. Yesterday, tho, I added objects. And objects, see, are more than just a picture of something that appears in the game. Objects are the start of data complexity in the game. Objects are containers with variable states and value and properties that affect how they ultimately matter in the game. Objects are rows in that spreadsheet whose values react to conditions of the game, the passage of time, and the interaction by the player.
It’s that start of my own game complexity that begins on one end of the spectrum with merely a virtual caselot of imaginary potatoes and ends all the way at the other scale with Dwarf Fortress.
I’ve been thinking a lot about Dwarf Fortress this week not because Pleck’s Mart will ever be that complex but because it will always now, going forward, be some fraction as complex as Dwarf Fortress.
You might even call that a Dwarf Fortress Complexity Quotient, like as in Pleck’s Mart DFCQ equals about 0.01 as of right now. I’m striving for maybe about a 0.2, subjectively speaking of course.
I have a long way to go, but the journey into a wildly entertaining spreadsheet ledger user interface adventure has begun. But let’s keep calling a game, ok.
It was just a couple days ago, wasn’t it, that I was lamenting the slog of working through the spit-polishing of code at the end of a development phase, and yet now here I am letting you know that Paranormal Pickle, my v0.3.x phase of design and development, is complete.
For firsts, huzzah! Onto shinier things again.
For seconds, it has been over a month since I made my first commit to the code repository and just a few days shy of a month since I formally kicked whole thing off as a project from the curious proof of concepts that I had cobbled together over the holiday season.
What has been accomplished in 0.3.x?
A lot. Really.
From back in those early days (a whole nineteen days ago!) of marching a little sprite image of a character around a grid on the screen I have incrementally coded a whole world populated with multidimensional spaces, nearly fifty distinct game areas, autonomous npcs that walk through those rooms following paths, a clock that marches forward the passage of time, and a smal but mighty database that keeps track of everything from the game state to a progressing story full of lore, dialog, and supplementary help. All the while, I have been fine-tuning my art and locking in a quasi-8-bit style with a colour-scheme that supports the user interface and the game experience.
Really, what else could I have to do?
Oh, right. There is still the whole gameplay part.
In my next phase of design and development, which as per the title of this post I am calling Subatomic Tomato, it is time to go a little deeper into the details and start creating this all important thing called an “object” …
What is an object?
Well, an object is pretty much anything that it needs to be. There already are a handful of background objects, things like shelves and doors, and all those passive world-filling things that helps to start bringing the game to life in the last phase, but what I’m talking about here are objects that are much more interactive and much more important to the game itself. Objects, simply, are things that the player can pick up. The player can pick objects up and keep them in an inventory, pick them up and put them on a shelf, pick them up and give them to another character. A player can buy objects, sell objects, or discard objects. Objects have value, but they also exist throughout the game as, in many ways, are the whole point of the game. The whole point, in that general hand-wavy sense, is to get objects and put them somewhere in the game where they will have an effect or do something that changes the state of the game itself. That, after all, is what game is: strategically organizing things in a way that progresses one towards victory. In the case of Pleck’s Mart, this is strategically placing the right objects in the right place in any of those nearly fifty game rooms with the hope that doing so advances your progress.
I’m writing very abstractly here on purpose.
Side note? I have been thinking about my candidness here and even though I know that any copycat game dev could never really replicate exactly what I’m trying to accomplish, letting you in on everything not only spoils some of the story and game itself, but makes it that much easier for some oversees gamer sweatshop to crank out a low-budget faux clone of my game before I can. This, my friends, is about playing a few of my cards closer to my chest.
Still.
I can write about my progress in building things like complex collision systems that enable npcs to follow paths and yet avoid walking through each other like ghosts. I did that.
I can write about adding a complex invisible grid layer to every game space that tracks its own occupancy so that no two objects, people, animals, or walls can break these laws of physics one assumes should exist. I did that.
I can write about the complicated nature of this thing we call time and an effort to impose not just a day/night cycle into a pixel dance on my screen, but to enforce a player to go to bed at a reasonable time. I did that, too.
I am moving into a new phase of creating interesting and awesome virtual things now and I will be equally vague about their nature while telling you as much as I can about their design and development.
Like, what does this classic thing called a “player inventory” actually look like in code? One isn’t really creating pockets on the little sprite on the screen now are they? Rather, I have been thinking about it like a virtual “container” —basically an invisible slip of digital paper in the game that essentially holds a list of those aforementioned objects. Things can be in one place at any given time, so the can be in the world list or they can be in a player’s inventory list or they can can even be in an npc’s inventory list. Need to add more objects into the game? The in-game “buy more stuff” system is just another inventory with an invisible digital pencil dangling from it that creates objects from air and adds them to that same list, and from which those newly created objects can be moved into the player’s inventory list and then from there out into the world list onward an around and over and over.
I am sitting here writing about it because, as you may have noticed reading this blog, as much as the code is important I truly, deeply believe that thinking about, reflecting on, and writing through one’s process is a close second. So here I sit. Not coding. But planning, plodding, and preparing to slice into a Subatomic Tomato.
If you have been reading any of my posts on this project you may have noticed me writing a lot about version numbers.
To many, versions are obvious from the outside but the nuances of how each project numbers their versions can differ. I assume there is some level of standardization at big companies, maybe even between companies, but generally this is a simple way for me to track progress.
For starters, it’s not a numeric decimal system. That is to say, while it uses numbers and decimals, it is not math. So Version 0.1 is different from Version 0.10, for example, it’s not an issue of significant digits. Rather, it’s a sub-versioning number, so:
Version 0 Subversion 1 is different from Version 0 Subversion 10.
As I write this I am in 0.3.6, which means I am in:
Version 0 (pre-release)
Subversion 3 (what I am calling my world-populating phase)
Sub-subversion 6 (or cleanup on aisle 3)
I could also suffix all that with the term alpha, meaning (and what I really am in is) that my current formal version should be called 0.3.6a. But then, I haven’t actually released any code, so its a bit pointless telling you something that you can’t see or download may not work well on your personal machine because I haven’t tested it that far yet.
I have noticed with my versioning system that a small trend is starting to emerge, tho. That is to say, the bigger the third number (ie the higher the sub-subversion) the more tedious the work.
x.x.0 is a new phase.
x.x.1 is me mucking around with big new systems and fun and trying out interesting new things.
x.x.2 through 3 or 4 is more of the same but also fixing bugs and tweaking.
I am now in a x.x.6 phase which is almost all bug-fixing, adjusting pixels left or right, recalculating math checks that I thought were working but could use fine tuning, that kind of thing. It’s sweeping up before we get to the next big feature push.
I want to move into that next big feature push. Those are fun. Bug squashing can be satisfying, but progress is sooo incremental in the higher number sub-subversions that it’s almost toooo incremental. Progress is in the form of “I thought this worked but… uh oh… okay, now it seems to work but… uh oh…”
Tweak. Squash. Nudge. Clean up.
In version 0.3.x I have accomplished an incredible amount to bring the game to life as a world. The population of the space that I built in 0.2.x has left me with added dimensionality for the game, moving from a simple two-dimensional navigable grid to not just a grid with a third z-axis layer of depth orders and stacking logic for the sprites, but also a temporal dimension in the form of a game clock with days, months, seasons and year, a sleep cycle, and the mechanisms for ambiant lighting to change when the time of day changes. And all of that doesn’t even mention the fact that game now acutely takes place in that science-fictiony five-dimensional space of parallel dimensions.
Still, polishing code in this late sub-subversion, zero point three point six, has me itching to move onto zero point four point one where I will get to dive into a stage that is all about building player complexity through adding functions, fleshing out the sprites designs, adding an inventory and a wallet, and a short list of other big things that will start to make it feel less like the little dude is just a ghost walking about and more like he has a point in the world. All of this is big, juicy, code for which I have big, juicy ideas filling my brain…
But I gotta polish, tweak, squash, nudge and all that stuff first.
In building this game world as it is, filled with floors and walls and shelves and light swtiches and everything else, I knew I was eventually going to run headlong into what I perceived as my biggest challenge: the NPC.
What is an NPC? For all you non-gaming folks out there, the term NPC stands for Non Player Character, or anything in your game world that is for all intents and purposes “alive” and mobile. Mostly though, the term NPC refers to the people, animals and (in some games but so far not mine) monsters or enemies.
The thing is, it is all fine and simple to build a wall or a shelf, but it’s a whole other undertaking to build in code something that has behaviours—behaviours like walking around the room and interacting with objects and having conversations with the player, et cetera, et cetera.
I mean, think about it this way: to move the player around the screen I have (of course) lots of hard rules built into the system about boundary collisions and input directions and all of that can be negotiated in real time by a human being playing the game with a brain inside their head poking at a keyboard.
But on the other hand, an NPC needs to be literally programmed to do things in the game. These are not magic or automatic. They are code, and carefully plotted tangles of logic loops. Like, simply to appear to move, an NPC needs to have a route to follow around the room, a kind of connect the dots map, and then of course to follow that map completely independently of whatever the player (with the aforementioned brain) is doing in the foreground and too, while everything else is going on. In every frame of game time, a hundred times per second, I need to have coded in a “what do I do now” kind of command that also tracks a “what have I already done” and a “what do I need to do next” and “where the heck am I in this multi-dimensional universe anyways” state of existence.
Sounds pretty straightforward, huh?
To be fair, it is only just mathematics around geometry and timers and coordinate planes and incremental counters, joined together in an elaborate choreography upon an invisible stage that needs to itself be tracked and moved in perfect synchronization with the player movement and the more little factors that are considered the more lifelike it all appears until the player (and sometimes event the programmer) forgets that the little pixel art moving around the screen isn’t really a person or an animal and is instead a picture being projected in perfect and elaborate lockstep to everything else already going on.
The game kinda resembles a digital layer cake of geometric planes. For our purposes in discussing the NPC challenge, there are three key layers:
the player layer on top which is little more than a picture (that never actually moves anywhere) of a little dude moving his legs or whatever,
the room plane on the bottom, which is a grid map to which every square of a matrix of about thirty by thirty is bolted an image of a single floor tiles or a single wall, maybe a single decoration or a single object, or aything else that doesn’t move, essentially a thousand times over to form a literal gridded map that comes together to make the picture of what looks like a furnished room, and
an NPC plane upon which the in-game life-forms persist through time and are continually moved from square to square like upon an invisible chess board, revealed when they are in the same room as the player or hidden when not.
When the player moves anywhere—around the geometry of a room or through a door to another room—both the room plane and the NPC plane shift around on the screen. It’s as if—to go back to the chess analogy—you were holding your player piece still in your hand just barely above the board and someone was shifting the board around under your piece. And then you held your piece in the air while they swapped everything out for a new board from another game, over and over, every time you made your move in one game, swapping to the next board, for thirty five different boards.
Convoluted, huh?
It really kinda is, and so you see the challenge I faced.
how does this all work, really tho?
Like everything, though, I worked through this incrementally.:
Can I spawn that middle layer? Yup.
Now, can I spawn an NPC sprite onto that middle layer independent of the other two layers? Ok, that works, but it doesn’t move relative to the player.
Okay, so can I make my NPC sprite seem to stand in one spot in the room? Yes. I lock the coordinate geometry of the NPC plane to the plane of the room.
Next I need to make it move around realistically relative to the room, so can I do that? Well, I add a coordinate path vector and loop through that moving the NPC around on its own plane while tracking its progress along the track.
Okay, can I do that with more than one NPC in different rooms? Sure. Add a conditional loop to spawn a second NPC linked to a different room id.
Oops, now both NPCs appear in both rooms, each following their own path, can I fix that? Of course. I trigger a check and change in visiblity when whenever the player moves rooms.
Great, but now how do I interact with my new NPCs? Um. One more system to check if the player and the NPC “collide” geometrically in game plane maths and then pass that state along to the rest of the game to await further instruction.
Yikes. It works.
The result of all this is a complex—but actually robustly elegant-ish—tool that lets me spawn as many NPCs as I may need in the game simply by adding new “data” to a file with some simple starting and trigger variables. I even tested having 250 spiders walking around one room just to check and it seemed pretty solid.
The whole process of building this game has been something like this.
Ask a question, then increment through the solution until something works, then refine until it works well. Then move onto the next question.
Some of the people reading this know me, and know me well enough to know that I have been recently pursuing some education and certification in the field of Business Analysis.
At the other end of this road for me lays a certificate that says that I can think big picture thoughts about systems and people and processes and technology and organizations and then write those down into neat and tidy documents—and then hopefully get paid for that.
*wink wink if you’re reading this.
In the meantime, I am writing an indie game in Rust and Bevy and blogging those big picture (and often small picture) thoughts about the systems and people and processes and technology and organizations involved in turning thousands of lines of cryptic computer instruction into a toy in the form of a virtual science fictional supermarket.
We’ve all got our quirks, huh?
The overlap between my two efforts is probably not coincidental.
I have been doing all sorts of real work over the last couple decades that, while not strictly capital-BA Business Analysis, has been in the realm of doing the things that business analysts do to accomplish the things that business analysts accomplish with the goal of creating projects, supporting volunteer gigs, or (as it turns out out) scoping out my own learning and side projects.
As I sat in the most recent of my courses with a room full of people talking about business analysis-kinda things, my mind started drifting back to the effort I had made leading into and throughout this very Pleck’s Mart game project.
I mean, just for starts, I’ve been running it like a project. I have a capital-P project set up in GitHub, for example, with actual Milestones and Issues and Timelines and a Board on which to view it all. (But then, that’s all more of the project management stuff and you clicked over here for the business analysis stuff.)
Thus, this all leads to the question: how did I get from dabbling in some code in my basement on a chilly December morning to sitting in Starbucks legitimately considering a plan that brings me up to and beyond releasing a game on Steam in the next year.
Business analysis, as it turns out and broadly speaking of course is a lot about understanding a problem in the current state and doing a lot of work to make a plan to bring you to a future state.
My current state (back in December):
I suddenly had some spare time on my hands.
I had been working on some scattered ideas for a game on paper for a while, but had no vision for how to turn that idea into real pixels on a screen.
I didn’t know any game-coding-type computer languages or libraries well enough to try this big idea, did I?
In the broad sense of things, me as a creatively-inclined guy had the problem of having a big idea with few details or sufficient skills to achieve the fruition of said idea, but adequate time to address some of those deficiencies if I was focused and directed at the right things.
My future state was simpler, if challenging to achieve: having learned a computer language to a level of proficiency to design, build and support an indie game, I will have a game available to download from the internet for the public to enjoy.
So. What next?
Here there are a lot of things that a Business Analyst might do to assess those challenges. When one is working with multiple people or an organization this involves meetings and documents and surveys and digging into org charts to understand where the right people are to get the information squeezed into something resembling a plan. For just little ole me, tho? This started out as basically some reflective writing and starting to plot things out.
Maybe a BA would dig into a SWOT analysis or do some functional decomposition on the current state to try and understand how things work. For me, I sat in Starbucks and legitimately wrote about this. Reflective writing. Introspection. Personal brainstorming. Whatever you want to call it. You can probably read some of the early stuff that I posted in the archives of my blog. A lot of it was at a high level working to understand what tools I had in my belt (my strengths) or the things I still needed to figure out (my weaknesses) while putting it into the context of some of the resources and time I’d recently stumbled into (my opportunities) and the contrarian facts of tackling a dauntingly huge project on my own for which I had no real prior experience (my threats.)
Maybe, a BA might plod into the territory of looking for gaps. In my own context, I have skills in multi-modal art and a bit of experience coding. I also have two hundred thousands words of contextual lore that I’ve written over the last year and that I can definitely use to support the world building I had imagined accompanied my future state game. On the other hand, games need, for example, music and I’m no composer (gap) and games require extensive testing on multiple platforms and I have just one aging desktop computer that has never even heard of 4K resolution (another gap.)
So, at my Starbucks table with a GitHub project open and my writing tools at the ready, I did some informal requirements gathering with myself.
I needed a proof of concept. Could I code anything at all, let alone a relatively complex game? I’ve been scripting web code, but those legit-coding courses I took in University were a little dusty in my brain.
I needed a small budget. I was likely going to need to pay for a few things along the way, from collaborators to technology to even (way down the road) a listing fee for hosting the game in a storefront.
I needed a marketing plan. Indie games win or lose in the real world on word of mouth. Building something in isolation and posting just hoping for people to play it is pretty much a recipe for failure. (Ahem, follow me on Substack or Bluesky!)
I needed a schedule. I’m in the awesome position at the moment to treat this like a job. (I mean, if someone wants to chaaaaaange that, I’m cool with a conversation about it but…) I can’t just poke at this thing part time and expect to have a product inside of even a decade, let alone a year.
Simple enough, right?
All of this penultimately led to lots of words and a few contemplative walks in the woods and at the end of the day I was staring at that capital-P Project in GitHub that I mentioned earlier. I mean, I could have written all this up and formalized it, you know, put together a lovely slide deck to try and convince the guy at the top but by then I was already on board and was too busy sitting in my pajamas at the keyboard trying to animate some sprites or something to need another meeting about this.
Does this mean the Business Analyst hat has come off?
Of course not. I mean, it is a bit of conceptualized silly fun to think about it all this way (particularly in the context of my educational and certification pursuits running parallel to all this) but there is a lesson buried inside, too. Just over one month into this effort I may still be a long way away from a finished project, but simultaneously I have a plan. I did the work. I put the pre-work into this thing of sitting down and plotting out not just what I was trying to accomplish, but how I would get there, what might get in my way, and some ideas to overcome the obstacles along the way.
I have a bright orange textbook sitting on my desk right now that outlines a vast collection itemizing and explaining all the tools and techniques that a business analyst needs to pry open something bigger and more complex (and more expensive) than a simple indie game project by some guy in his basement, and I could probably open that book to any random page and find something useful to enhance my efforts—and maybe I will. But my point, and the lesson here, is that as much as the code is important and interesting and a big part of what I’m doing, there is more going on than a man in his basement dabbling in being a keyboard cowboy.
And in as much, I think that has brought me as far as I have come thus far, and hopefully keeps me going forward.
Analysis and planning for the win. Achievement Unlocked!
The pursuit of phase Paranormal Pickle continues as I round off another development milestone this evening and creep closer to something that is actually, really, starting to look like a game.
I will preface all of this with a bit of an anecdote on digital frugality.
In this era of the robust availability of processing capacity it is easy to find people discussing frame rates and generous graphical outputs derived from access to huge quantities of processing power. The advantage to using a game engine is that I can work under the assumption that the people who built both Rust and Bevy have considered things like memory management and processing pipelines so that I don’t need to think too much about either.
I mean, a little bit. I need to think about it some.
But I was overthinking it and as I develop this game which has a very retro architecture and two-dimensional 8-bit vibe, I may have been leaning into those thoughts a little too agressively.
I found myself doing some back-of-a-napkin calculations about what a very conservative number of simultaneous processes and active game systems might be. Then I searched for something similar, looking for confirmation of my math maybe. And then I outright asked an AI bot what a modest number of live processes and spawned objects and active systems might be for a game written in Bevy and Rust.
See, I had opened up my inspector tool and having spawned these generous tile-based rooms and layered those rooms with decorative objects and then animated those objects and then added collision to a bunch of those objects and then added a bunch more UI objects on top of that and all that was just to show the world and not actually calculate the game mechanics itself, I had come up with a number that to me looked daunting. At any given time, it turns out, I had somewhere between 1500 and 2000 spawned objects and systems.
To be clear each of those systems might be very, very small. Displaying a 64×64 pixel sprite at position X,Y on the screen. Doing a simple geometric calculation. Incrementing a number in a counter. Saving something to the database. All small, but add them all up and you have (a) a game and (b) a lot of systems that run in a continual loop about a couple hundred times per second each.
So how many are too many? I mean, I keep adding stuff and hoping that the game doesn’t suddenly drop to three frames per second because I’ve hit some limit.
Well, the answer I got back from my back-of the napkin calculations suggested that I could probably run the game at 120 fps if I kept that spawned number under 25,000.
If I got up to 100,000 I was going to start noticing it eating up the processor, and if I happened to hit a million I may want to consider doing some optimization.
The internet, AI, and everything else vaguely confirmed this.
So, to be clear, even at my biggest, sprite-filled, action-packed room state, I was running at about 8% of my most conservative everything-is-humming-along estimate. I mean, the proof is in the pudding, but the moral of this story is that I can probably stop being so digitally frugal and add a bit more life to the game.
Which is exactly what I’ve been doing.
I wrote a whole post on building my menu system (which to run compared to the game-proper processing power requirements is like comparing a pedal bike to a Harley motorcycle) so I won’t go into detail on that here.
But I have also been doing a lot of design work. This phase was about furnishing and decorating and I’ve added a whole couple of categories for Things That Appear on the Screen (TM) like simple A/B state decorative objects and this thing I’ve called lively decorations which are actively animated as part of the universe (slurping up some of that spare processing power, of course.)
In the background and to facilitate all these things I’ve had to implement and polish up a bunch of actual game systems, too. I mean, I wrote already about the game state stuff which facilitates the switching around between menus and the game, but I also added a clock to the game. The clock, of course, has a game built in, but it doesn’t specifically track anything besides a kind of this-app-has-been-running-for-this-long seconds counter. I added a clock in the sense that the game now tracks a 24-hour game cycle of days, hours and minutes. And not only does that time clock save routinely as part of the game state database save file, but it now makes the game feel like time is actually passing. You can open the menu and it now says something like “it’s 8:43 on day 2” of the game—which having a time clock might be important to things like having a store with open hours. My kid asked me if I was going to make it so you need to sleep (a’la Stardew Valley, which I admit is a bit of a back-of-mind influence on a few of my design choices) and this is starting to make more and more sense, particularly if I will need to have a bunch of “nightly” calculations happen to my grocery inventory.
So as you can see, things are taking some real shape here and chugging along a game is almost, kinda, sorta appearing. That feels real nice.
I’ve veered lightly away from building my virtual grocery store this week in favour of an equally important aspect of this game project: the menu system.
Yikes! Yeah, I know, me too. I’d rather be painting sprites and building an interesting world, but oh that user interface is going to be important.
As with almost everything I’ve approached this particular problem—that is, how to build a menu over top of a game world—incrementally. And as I’ve been lightly glazing over the coding progress in most posts on this blog, I wanted to do something a little different and deep dive into how I approached this particular problem, if only because it took me two solid days to work through and get it functioning in the barest-of-bare minimums (that is, as of another three hour coding session this morning.)
So, here goes.
You may have picked up on the vibe that story is very important to what I’m building here. I am a novelist in my other crazy project life, so having a coherent story with lore is key to this whole deal. To that effect one of the earlier things that I built (a week or so back in phase 0.2.3) was a kind of simple story engine that runs through the whole game.
Stories in Pleck’s Mart are comprised of a few simple database tables: One keeps track of all the words, and one keeps track of all the statuses. Just to complicate things, a story can be comprised of multiple “beats” or pages. This is for both flow and because my font choice at the moment really only allows for about 250 characters on the screen at any given time, so that’s like 20 words. Any substantial story needs to graced with a bit more expositional text than a tweet, you know? In other words, pagination.
(There was a deliberate choice not to use bools for some of these status flags as I’ve got some ideas about non-binary status states and using the system for books, notes, etc, but more on that in a future post.)
The story engine works pretty well, if I’m being honest. I’m happy with it so far and I haven’t run into any big flaws short of it could use a nicer UI design.
All the chapters indexes are loaded into the status database on a new game initiation, and if a story has an unread status then a collision trigger coded into the game map can fling it’s unique code into the story queue which is constantly checking for active stories in the queue and bobs-yer-uncle it reads it all (text from the data file) into the database, spawns a story UI up on the screen and you can either NEXT your way through each beat or EXIT out and move along to just play the game. Meanwhile things churn in the background to change the status to read so that particular part of story never spawns again—
—which leads to a little sad face from Brad as I’m building this game.
See, unless you play the game over you can’t (couldn’t) go back and read the story chapters that you already triggered. They were complete=1 and would never spawn again on any given save file. Thus, one of my first “this needs to be in the menu” features was the addition of a story history so a player could revisit and review and reread—and thinking about how to accomplish this was where I was sitting two-plus days ago, staring blankly into a computer screen full of five thousand lines of game code that barely even had a menu system, let alone something useful for a story history navigator.
I started to address this problem by tucking in and refactoring the whole menu scheme that I’d started to build last phase. (It was okay, but it had some limitations.)
First, I divided the in-game menu into three distinct, heirarchecal panels: there is now a TOP menu which is a kind of icon-based ribbon of menu categories. Next there is the LEFT menu which is a scrollable list of sub-categories. And finally there is the RIGHT menu which is for now a kind of panel that displays the results of whatever you selected in the left menu.
To break that down with an example, when the STORY icon is selected in the TOP menu, then a scrollable list of STORY CHAPTERS appears in the LEFT menu which subsequently results in the selected story chapter’s TEXT BODY to display in the RIGHT panel.
Like so:
If all this sounds fairly straightforward, well, it is—but it took me a couple days of debugging and coding effort to not only get to that architecture straight in my head and in place, but also to make it actually work.
how does it work?
For starters it’s all based on a collection of menu state components that are tracked and manipulated by player input. This is the root and core of how this all functions.
That is to say, when a player moves into the GAME MENU App() state by pressing the M key while in-game, the App() moves out of the GAME state and into the overall GAME MENU state. (And vice versa on closing.)
This action spawns all three menu panels:
TOP menu has a GameMenuState of 0;
LEFT menu has a ScrollMenuState of 0 with a bundled Length value;
RIGHT menu is a blank canvas;
A player now looking at the menu on the screen can either move Left or Right which cycles the GameMenuState from 0 to 1 to 2 to 3 and back to 0.
Or, a player can move up and down which cycles the left menus’ ScrollMenuState from 0 to 1 all the way up to a variable length value stored in that state. (Because of the variable length this also does some fancy math in there to adjust the scroll_y value so that the active item is within the view area of the left menu’s draw area. Math, math, always lots of math. And my daughter writing her Math final in her last year of high school in just two days from me penning these words wonders when she’ll ever need math again! Bah!
If all this seems pretty basic, it is. The tricks all come when we need to the GAME MENU systems in the App() to react to all these variables.
For starters the contents of the LeftMenu are uniform in design but simultaneously conditional on the GameMenuState. That is to say, it’s always a scrolling list with an icon and a piece of text, but what icons and what text depends on the number in that GameMenuState.
For example, right now my STORY menu is the fourth icon on the top menu ribbon. This means that the App() listens for a GameMenuState of 3. If that happens to become true a lot of things then are conditionally allowed to happen:
the fourth icon sprite in the TOP menu “remaps” to the “highlighted” version of itself on a texture map so that it appears in colour instead of in greyscale. In other words, it highlights itself and de-highlights all the others.
a query extracts all the “complete” story codes (things the player has seen) from the database as a vector of data and iterates through them to build out an n=rows number of icon and story title pairs inside the LEFT menu canvas. In the case of a player who has just started the game and played into the first room, this means the function will spawn two item pairs in the list: (1) an icon an a piece of text with the title of chapter 1 (the introductory story text) and (2) an icon an a title of chapter 2 (the story that activates when the player first enters the store). Later, as more story beats are unlocked this list will grow longer.
the LeftMenuStatus resets to 0. (Top item in the scrollable list.)
the first item in the list of things in the left menu goes into it’s highlighted state in the same fashion as the top menu does when it is highlighted (ie. the sprite shifts its texture map and de-highlights everything else)
the right panel function checks for valid content based on a hierarchical check though GameMenuStatus of 3 and a LeftMenuStatus of 0, which in this case populates the canvas with the first story block’s text.
the right panel (still checking through this conditional mode) waits for a keypress and if the player clicks the NEXT key it does some more mathy-texty-database stuff to pull the next beat from the story chapter and then replaces the content of the right panel if that all happens.
Of course, there are some extra conditionals and “something happened” checks tucked in there somewhere to balance things out and prevent these conditionals just going into processor eating loops of infinity, but those are details that don’t materially impact the overall deal here.
The net result of all this is that if, while playing the game, the player presses the M key a menu appears.
If the player then Arrow Key Left/Right’s over to the story menu, a list of her story history items will appear in the left panel.
And as they player Arrow Key Up/Down’s through that list of story history, the first beat of each story will appear in the right panel.
And if more than one beat exists for a story, the player can press the N key to cycle endlessly through the various beats that exist in that chapter:
let new_text: &str = this_story_text.as_str();
for mut this_text in rightcontentpanel.iter_mut() {
this_text.0.clear();
this_text.0.push_str(&new_text.clone()); }
Voila. A menu with story history.
Check.
side note: If enough people are interested in such a thing, I could pull this menu code out of my main project, clean it up for general use, and release it as a Git repository.
Comment if that’s of interest.
looking back
My biggest hangups after all this got working as I expected were making sure that the canvas contents were responsive to the conditional changes: mutable text fields, scrollable nodes, etc, etc — which you would think in retrospect should be pretty obvious but designing this all in raw code with overlapping coordinate systems across three spawned objects just seemed to be keeping track of things and naming stuff in meaningful ways.
And having built it this way, I think—right now, I think—all this work lays the foundations for most every other menu in the game:
The items in any the left menu can be dynamically defined by the contents of a database or hand coded to be very specific items.
The contents of the right panel can be adapted to display just about anything, text, images, or inputs.
And, not that I have much to fill them at the moment but I left room for up to eight menu categories, which is very probably overkill.
Now, back to building that virtual grocery store, huh?
I reached an interesting point in the development cycle that necessitated that I learn more about the root of the application.
If that sounds a little sketchy for a programmer to, you know, not fully grasp the intracacies of the main() loop of the software, keep in mind that for most every simple program the main loop is simple, too. And even for a Bevy application, most every simple app you can build in that game library (or importantly for this anecdote, every online code sample) follows the same basic and simple structure: add a system to initiate, then start up, then update and run.
And while up until now I have been building a pretty complex little game, the system upon which it runs has been very simple: Launch the game and the game launches.
Except, that’s not how games usually work.
You usually launch the game and at the very least a title card appears, and then often a main menu. The main menu is, of course, the important part. And in game design speak, the main menu isn’t part of the game-proper, but a kind of pre-launch state.
And similarly, another task I had set for this milestone was building an in-game menu. Both of these things are part of the capital-G Game, but they are not part of the game, if you follow.
In other words, I had to learn about game states, and the whole complexity in my main.rs file of conditionally running bits of the application depending on a game state.
And all this started off okay, too. I found some code samples, and dug through the API docs, and started building. And then? Then, well, I added a function to trigger the game state to switch to the menu state and put it into my game loop. That’s to say, there are a bunch of little functions that are run over and over and over again, updating the graphics, checking the keyboard for input, monitoring the location of the character on the screen, etc, etc, and I needed to add another one that would check to see if the key that opens the menu had been pressed (and if so switch that game state over to the menu mode).
After everything I’d built it was a simple little keyboard check, except when I ran the application I got a strange error:
trait bounds were not satisfied
rust error E0599
Okay.
I searched online. I dug through the API for the input commands I was using. I even asked ChatGPT for some ideas about why I might get that error from the very simple code snippet that I showed it.
No help anywhere.
Now to be clear, this little game I have been making is starting to get very complex. Lots of moving parts. Lots of systems that run sequentially or simultaenously or (now) conditionally. And the game loop consists of a long list of check_this, animate_that, move_littledudearoundthescreen-type systems.
I spent two hours digging and prodding and simplifying my new function.
No use.
Then I tried putting in some code that I knew worked from another function, I mean, not just adding but completely replacing that new fn call temporarily with a different function’s guts.
Nothing.
And then I did something that any good debugger worth his salt should probably do: I started methodically flipping switches until the problem disappeared. And—well, that’s the odd part. The first switch I flipped, that is to say, the first thing I turned off—which happened to be an animation function—fixed the whole damn thing.
It just suddenly worked—well, except for that animation function.
Was something wrong with the animation function?
I tried flipping the animation back on and then flipping something else off in it’s place, just to see.
Now? Now the animation was working but the picker highlights were off and yet it still all (minus the picker highlights) worked without that error.
So, naturally, I turned everything back on and—Error.
Look. I had a hunch. There had been something I was suspicious about and yet no matter where I looked (or what AI bots I asked) I always got the same answer:
How many systems can I add to an Update’s parameters. —I would ask or search or troll through message boards seeking a clue about.
“There is theoretically no limit.” —was always the answer.
Except. And here is the suspicious thing—remember how I mentioned that my app was (up until now) pretty simplistic? Yeah. So, when I say simplistic what I’m really saying is that I had neither organized nor really done any management of my function groupings. In fact, prior to adding that function that broke everything, my .add_system(Update… parameters for my game loop had exactly twenty functions being called from it.
My menucheck was number 21.
I spent a solid forty-five minutes breaking things up into categories and smaller chunks. Add the room systems. Add the animation systems. Add the input monitoring systems. Five systems in one, eight in another, and so on, and so on, until there were those same twenty one orignal systems that had broken my original scheme but now organized into four separate Update calls.
And?
Well, I wouldn’t be writing a blog post about it if it hadn’t worked, now would I? I don’t know for sure if there is a function limit specifically or maybe if there is a character limit for the parameters, or if I tripped over some other invisible fence but whatever it was I seemingly had breached it and caused an error.
If you have come here to read a programming anecdote, that’s it. That’s how this works. That’s how a guy can bang his head on his desk for four hours on a Sunday afternoon trying to puzzle out something simple and yet completely unobvious, something that no one thought to document because programmers with more experience, maybe, would naturally organize things a bit more meticulously.
Or, if you have come here because you are searching for a solution to that same problem and because I have helpfully copied the error messages and codes verbatim into the text to assist you with you own struggles, then cool. I hope this helps. And then drop a little love and check out my game.