Almost always when you’re up in the wilderness climbing a mountain the terrain changes with each passing trail marker, sometimes step by step, definitely hour by hour. You may start off on a wide trail with a gentle grade surrounded by rich forest, and that may break out into a rocky traverse along the dog legged trail through a centuries old rockslide, which around the next bend becomes a narrow clamber up and down through some root-laden single track all of it leading to a steep cliff where you need all four limbs coordinated and strong to reach the top.
If I ever needed an analogy to write about indie game design and development, I think one of the obvious options would be to compare it to climbing a mountain. It changes with every step, and you need to be prepared for what’s around the next corner—and that could be anything.
My life has been cluttered up with non-game work these past couple weeks so progress on development has been a bit of picnic stop at a scenic viewpoint. I’ve been swatting bugs, changing my socks, and enjoying the view from my efforts so far, but I’m not getting much closer to the top. Yet, this moment of pause and assessment is, as any seasoned mountain hiker would tell you, might be as important as any forward step up the trail.
All that said, as I write this I’m getting fueled up for the next few days of knuckling in and pushing on.
Sadly (for my forward effort in my education) my weekend round of lectures was postponed and rescheduled. This sets me back by about a month in my professional training, but—lemons made lemonade—frees up three solid days for some game coding.
What have I done since last checking in?
A lot, actually, but only a lot if—again to the mountain climbing analogy—if you consider squashing bugs, play-testing, cleaning up code, and poking around in my supplies an important part of the journey.
It had been over three weeks since I loaded a snapshot on my SteamDeck, and doing so with my bug-tracker sitting open next to me gave me a full day of work tuning controls, stabilizing code, and catching other little UI quality of life fixes.
I also dug into the back end of how I’d built things at the beginning and did some refinement. My understanding of Rust and Bevy both have grown exponentially since December and I look at the ways I built some of those original functions and see significant improvements to be made. And maybe this is a little disheartening to rewrite stuff that was already working, but then at the same time I’m tweaking stuff so that it can be expanded to to ten more things in addition to the thing it was originally written to do.
I’ve also made a lot of art.
Art is time consuming. Heck. I figure I need somewhere in the neighbourhood of 300-500 more art assets. I’m able to make about four or five an hour. So, mathy time, that is something like a hundred plus hours of work drawing little pixel sprite carrots and tomatoes and blue cheese. Fortunately I can multitask my art (unlike my code) by which I mean I can draw with the “distraction” of the TV on, so I’m simultaneously getting my fill of classic Simpsons episodes while I draw.
After I write this I’m going to do a couple things.
I’m going to record a video of the game-play and grab some more screenshots. If that goes well it should get dropped about here…
And I’m going to go into GitHub and reassess my issues. I’ve pushed and nudged and swept all the fiddly jobs into a pile and that pile is sitting in the middle of me finishing this latest milestone. So I need to reassess some of the things I said I was going to do and either say frak it and just do them today, or figure out where to shuttle them off to a future state again.
Either way, I’m closing out 0.4.8 today and moving onto 0.4.9–and bound and determined to move into 0.5 by the end of the weekend.
I don’t ever want to get ahead of myself here, posting half-baked successes as if they were all star performances. Yet, back nearly two months ago now when I sat down at the computer and worked myself up from a “Hello World!” introduction to Rust Language programming to a rudimentary game loop, it was a long road ahead of me to a day like today.
What’s special about today?
Well, besides the fact that it is the day of St. Valentine and I am yet again sitting in a cafe writing about code, there is the simple success that as of a few more minor tweaks this morning I am about to hit an interesting sort of milestone.
When I wrote that rudimentary code two months ago the thing that I wrote in a game loop was quite simple: a time-based cycle, looping through and counting off seconds passed, and at specific increments of time applying changes to data in a table. That is an abstraction, tho. What I was actually trying to model and represent in code was the aging of a bundle of carrots.
Yes, carrots.
You can put two and two together I assume. I’m building a game about a Science Fictional Supermarket and as such my game would obviously have something resembling a bundle of carrots and given that time passes in even most science fictional universes, said carrots must age.
Thus is the foundational premise of my game after all. You sell things in a store and the those things sell based on their quality and their quality is affected by what’s going on in the universe. So, things like aging are one of those obvious things.
Could I model an aging carrot? A carrot, getting stale and decreasing in quality and value is little more than a set of numbers representing those things, but the short answer was yes. Yes, I could. My little proof of concept code counted off the seconds and minutes and even an hour when I let it run, and after increments of time changes applied to those numbers representing my carrots changed to other numbers. Math. Imagination. Code.
Then I dug in.
If you’ve read any of these writings you already know that I’ve been plugging away and building rooms and doors and game clocks and npcs and art and sound checks and code efficiency debugging tools and piecing it all together.
I’ve built a store and a warehouse on my screen, I’ve given controls to the little character to run around that space as time passes around him. I’ve given him virtual money and a place to spend it. I’ve enabled him to pick things up and carry them around, and then to set them down again somewhere else. I’ve put little virtual customers in the store walking around and getting in the way. I’ve layered a story over top of that with discoverable beats and unlockable help tips and a world stuffed with books that detail interesting backstories. And then this week I added a sales loop that checks when the store is open and takes stuff that exists on the shelves and slowly sells it turning it all into profit.
And then today arrived.
I have one open ticket left in this milestone phase of my project tracking tool wherein I manage my efforts to make this silly game. I’ve worded it a bit different than this, but basically the ticket is: make the carrots age.
Yeah, yeah. My proof of concept two months ago started with that first. But then I went back and built it all right building up to this point and…
I need to make my carrots get old. And everything else, too, obviously. Age, go stale, decay, rot, et cetera. That is the one last underlying pretext of the game to complete the great big circle of my alpha-minimum-viable product game loop.
After today I don’t just have a part game. I have a game.
I mean, it may not be very good and it needs a lot of content and polish and tuning and tweaking, but the core of it will be there.
Everything that follows will be enhancing that loop. Everything that follows will be making the loop more challenging and interesting as a game, adding obstacles to slow progress or challenges to keep it interesting or story to give it context or art, art, art so much art to give it depth. Yes, there will be bugs. Yes, there will be inefficiencies that need to be tweaked. Yes, it will grow and shift and improve, but at the very core of my code there will be a game by the end of the day.
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.
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.
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.
As I reach and stretch for new features to add into Space Carrot, the 0.2.x phase of development focused around the goal of “creating a navigable world” I have opted to conclude this particular push and move into my next phase of work.
Space Carrot ends with a few notable features that are technically world navigation functions but really are starting to bleed over into the player management, action managment and UI realm, all work for later.
I added a light switch. That may not sound very impressive, but what it really means in code speak is that I added an action trigger that only functions during a very particular collision event to conditionally change the visibility of a “shadow” over the current room, simulating a lighting event. A lot of little systems (all of which will be useful later) had to be implemented to make this a reality.
I also added my first animation. This is a simple conditional animation of the player walking versus standing based on movement. This should have been really simple, but I had (again) shortcutted my design work and leaned into single use sprite pngs. Going forward as I bring the world to life in my next phase of design and development I have a bit more confidence about creating animated objects and more.
Paranormal Pickle is the next phase of work, and it begins today, less than two weeks after Space Carrot.
This phase is really very much me leaning into populating the world, filling it with colour and art and objects and life. I have dabbled in this a little as can be seen from the handful of decorative things like switches, doors, and pallets. But I have a whole store to design, and these then 33 other rooms to fill with shelves and furnishings and wall decorations and windows and more and more and more.
In other words, this is kind of a creative phase more than anything.
That doesn’t mean I’m stepping away from the codebase tho.
The other side of this is the other layers of the game like the menus and a welcome screen and even just a splash logo (because all games need a studio logo and title cards, right?) There is a lot of coding and button interaction and the like which I need to study up on and figure out.
To all that effect, what that means is that in the first subphase of Paranormal Pickle, 0.3.1 I’ll be focussing on three main enhancements to the game:
First, a title card, which will allow me to implement a mechanism to delay starting the game pending player interaction. Right now the program just jumps right into the game on load. Games don’t ever really work that way, do they?
Second, I want to fill the world with furniture and life. I’m going to start with the main room: the store front, filling it with shelves and decorations. In this effort, I also want to add something I’m calling (to avoid confusion for myself in the code) lively decorations, which are essentially background objects that have animation cycles. Think flashing neon signs or trees rustling in the breeze or steam blossoming off of something hot. All of this brings the space to life, and I think I actually know how to do this. It’s just rolling up my sleeves to make it happen.
Third, I want to add a basic popup menu system. This is pretty self explanatory, but it will need to be something that grows and adapts, so maybe I’ll narrow this down to two “tabs” of things I want the player to interact with.
So, there it goes. The game progresses.
It’s funny. I have started following (and being followed by) other developers on social media, and as proud as I am of the work I am making from scratch and this being my first attempt at a real game and all, I still look around and feel a bit out flanked by so many great game devs out there building amazing things. My game is going to be pretty 8-bit in style and play, so hold that up to a full 3D triple-A production and it all seems about thirty years too late. I have always had an interest in retro games, of course, having lived and played through that era, and now I’m finding that the retro vibe very much fits with my coding abilities. What I guess I’m trying to explain is that maybe this is all impressive to some and way less impressive to others. But I’m aiming for something simple and fun and achievable with Pleck’s Mart. And right now it feels like I’m aiming just about right.
I hunkered. It helped that it’s been twenty-five degrees below zero outside and I can’t do much besides sit in the warm house and look out through the frosty windows. No dog walks. No running adventures. No casual outdoor excursions. Instead, I’ve spent two full days coding.
I wrote just a couple days ago about my intention to work on this current phase of development (Space Carrot) and barely forty-eight hours later I’m posting again to say that I’m moving my efforts to a new sub-sub-version. I updated the milestone log with the results of 0.2.1 and I’m moving on to 0.2.2 as of my next coding session.
What goes into writing a game like this?
I’m not an expert, I’ll remind you. I’m winging this and hoping something comes out of it. I’ve been working on some game story lore, fleshing out the mapping system on (digital) paper (ie sketching out things on my tablet) and sitting down to think about the mechanics of creating a game space.
Sketching out version one of the storeroom.Sketching out version one of the store.
After all, the whole point of Space Carrot (I realize that some people might read that as the name of the game and not just a development phase) is to create a navigable world for the game-proper to exist in.
First, I worked through the nuances of creating a collision detection system that doesn’t weigh down the processor checking everything constantly. Now you can’t walk through walls. And since I have now forced every movement to happen inside the boundary of virtual walls, my player sprite can navigate around without falling out into the void. Testing will continue on this, but so far it works.
Second, I had to figure out the strangenes of door-to-door inter-room navigation. This, also a foundational aspect of the game, seems simple at first but in reality it’s a kind of interplay of a player “colliding” with door, waiting for an action to be triggered, and then figuring out what door she collided with is (specifically) and where it leads. Since this whole thing will exist as a series of virtual rooms, any given door maps to a corresponding door on a different room map, all of it encoded into a few lines of data and “match” statements in the little door collision detection function. In other words, a door collision is detected and if that happens a trigger action can be accepted and validated, and if that happens the player’s location can be updated, and if that happens the code goes uh-oh, I’m displaying the wrong room because the player isn’t here anymore and then the code despawns wrong room and then spawns the new room where the player is now located and also standing at the cooresponding door she just walked through. And all that happens in a fraction of a second so it seems to the player (maybe you) that your little dude just walked through a door into a new room. Sketch that out in a math equation, huh?
Finally, I wanted to add a bit of explanatory text to the scene. Specifically, this comes in the form of a little corner notice room label, when a new room was entered (it’s going to get confusing otherwise, believe me) and any other little notices that might help the player poke around the game. This was relatively the most simple part, but I did need to figure out Bevy’s new (0.15) Text system, which has not been updated in almost every 3rd party tutorial and code sample. Every explanation of how to use this leaned into the TextBundle constructor which has been deprecated in the latest version. Good thing this whole langauge is starting to make more sense to me with each new function I create.
So. That’s that. Two solid days in front of Visual Studio and a compiler—and countless times typing the run command and debugging my buggy code until I incrementally added all this stuff and it seems to work.
But then, this is just a few more basic building blocks of a much bigger plan.