There hasn’t been anything huge since my last post, but quite a few small things. Most of it has focused around improving the herbivore behaviour through things like pathfinding improvements, some tweaks to how actions happen, and various bugfixes. I’ve also added a UI overlay to start showing some simple game stats – soon to be expanded upon – and implemented a few workflow improvements to help keep track of my ideas and progress.
Herbivore Behaviour
Last post I talked about how the herbivores were performing too efficiently, leading both to a lot of “swarming” behaviour as well as degrading performance. I’ve addressed this in two main ways: introduce more complexity to the decision making progress so that it’s less efficient and predictable, and by making pathfinding a bit less expensive.
Some of the adjustments I’ve made:
Actions now have a configurable “duration”; e.g. after eating, walking, etc., an entity will wait a number of cycles before doing another action.
Entities have an ideal number of children; after they reach that number they become far less likely to create any more.
If an entity’s pathfinding “fails” it will now idle for a short period; wandering in random directions, instead of immediately attempting to pathfind again.
If pathfinding fails, the entity is also supposed to “blacklist” the object it was walking to so it will pick a new target, but this might not be working.
Entities no longer route their path before every single movement; they’ll instead remember a previously routed path and follow it for a number of cycles before re-calculating.
On top of these specific adjustments, I’ve also made a bunch of tweaks to individual parameters for both the grass and herbivores to try to get to a state of equilibrium. I’m aiming for a scenario where both types of entities can survive for a long time while also not killing the frame rate. It’s getting close – the herbivores are much less explosive and the grass a lot more resilient, and the game tends to stay above 60FPS, but over a long enough period it’s inevitable that the herbivores will eat all grass and then die for lack of food.
UI Overlay
This is a pretty minor thing overall, but an important first step. So far I’ve just added some text that tells me some basic info about the game state – this can help me gauge how various factors impact the game’s performance. As well, now that I know how to create and update text on the screen, it gives me an avenue to start displaying properties of individual entities.
Workflow Improvements
To replace the Google doc I was previously tossing ideas into, I’ve started using Jira to track ideas/tasks/bugs/etc., though that’s pretty boring. I’ve also started uploading my work to github (https://github.com/dlouwe/tinyfeelingrobots) to A) keep myself a bit more structured/mindful in how I work on things, and B) maintain a working backup of my changes, and C) allow any errant soul the chance to check the thing out for themselves. I am 95% sure that this has all of the project files necessary to load the thing up in Unity with minimal/no configuration, but I also don’t entirely know what I’m doing!
A side effect of using these tools is I’ve had to somewhat formalize a name for this project: Tiny Feeling Robots. Because I’m not creative and I like iteration. 🙂
What’s next?
We’re inching ever so close to the actual purpose of the dang thing, which is to start allowing the properties of entities to change over time and observing what kind of shenanigans that causes. The only thing that I’m really waiting on for that is being able to view entity properties while the game is running. Technically I can do that using the Unity editor, but that’s not very practical. So, depending on how easy that is to set up, we could potentially see some shenanigans in the next blog post!
Well now, a lot has gone on since my last update. A lot of it has been behind-the-scenes stuff like refactoring and optimizations and more refactoring (which I’ll talk about a bit further below), but I have introduced something new to the artificial ecosystem. For the time being they’re called “herbivores”, and they eat grass!
New friends!
You might also notice the grass looking a bit different; I’ve been doing a bunch of tweaks to existing behaviour as I go, though nothing huge. I’ve mostly just been trying to make something that looks aesthetically pleasing at this point. The biggest change is letting the grass populate up to about 10 squares away; this makes it more possible for grass to return to areas rendered barren by voracious herbivores, as well as makes the overall shapes less homogenous.
Now, a significant issue with the herbivores at the moment – at least in terms of establishing some sort of equilibrium in the ecosystem – is that they are far too efficient. I essentially built them on top of grass with modified parameters – plus the ability to move and consume grass – so they are essentially always trying to either eat and reproduce if possible.
That’s a lot of friends
Reproduction currently is only limited by a percentage chance, which means that if a single herbivore is likely to reproduce at least once in its lifetime, then it’s at least possible that it could reproduce twice, and each additional herbivore increases the likelihood of more being born, leading to overpopulation inevitably consuming all available grass.
The horror
You can see near the end a small pocket of grass was able to re-establish due to the newly increased propagation range, however, it ends up being moot. I have some plans for how to improve this behaviour that mostly revolve around making the herbivores less efficient; such as making them get hungry less often, give them a diminishing likelihood to reproduce multiple times, etc. I would like the reproductive cycle to be more “generational” than “relentless swarm.”
You may also notice in the 3rd image that it’s starting to encounter some slowdown; these herbivores have been a really excellent exercise in pointing out poorly optimized portions of my code. This is also another big issue with how efficient the herbivores are; it was fine for grass to be very efficient because their operations are relatively low-cost. Herbivores, however, need to regularly search for meals as well as pathfind to reach those meals, which can become very expensive to do constantly – particularly when they start getting further away from meals and/or can’t find a valid path. The measures I talked about above should help with this as well, plus I also want to give them the ability to remember their paths for a period of time; currently each herbivore re-checks that the entire path to its next target is valid every time it wants to take a step. That’s good for accuracy, but very bad for performance.
My next main goals are, in order:
Add behaviours and tweak the herbivores until the ecosystem can find some sense of equilibrium without grinding the FPS to a halt. I want to be able to let this run for some time.
Allow the critters’ parameters to drift over time. When a creature reproduces, I want its descendant to have slightly different inclinations.
Build some sort of UI that lets me inspect the individual entities and see what sort of parameters they optimize towards as the “fitter” settings should produce more offspring.
And now I’m going to delve a bit into the more technical stuff that I’ve been up to. I’m putting this at the end in case up until this point has somehow been within your threshold for nerd shit, but no further.
Aside from lots and lots of incremental changes in order to get specific things to work, I’ve made two major changes in how the code is structured and operates.
Firstly, I consolidated all of my non-water entities into their own singular class. This was due to the fact that in Unity if I want a script attached to one game object to interact with the script of a different game object, I need to write the name of Script B into Script A. This isn’t an issue if I just want to allow the Herbivore object to trigger some interaction in the Grass script, but my end goal isn’t to hard-code specific interactions – rather to build the rules behind the interactions and let those operate in a more arbitrary way. So, in the interest of not coding myself into a corner, I moved all entity behaviour into a single script and allowed those to be controlled through parameters. E.g. a creature with 0 “speed” isn’t ambulatory, even though its script has the code required to move in it.
I had actually started on an early version of the Herbivore and sorted out a pathfinding script before deciding to make this change, so it required a lot of backtracking. But I’m feeling much better about my ability to scale this to additional entities; any work I put into building any given entity is also extended to any future or existing entities, which is the sort of efficiency I can get behind.
The other significant change was getting the controlling “brains” to split off when they reached an entity limit. This was something that I hit a roadblock on before condensing all entities into a single class. Each brain needs to know what kind of entities it controls, and the master list of brains also needs to know what kind of entities the brains it lists control, and the thought of creating a new list of brains for each entity was unacceptable. I made a few attempts to make this dynamic and work with multiple entity types, but it just ended up getting tied in knots that I didn’t know how to untangle, and I shelved it for a while. Moving everything into a single entity cleared that up, and let me finish the implementation. This was also necessary, because the behaviour of multiple herbivores under a single brain was quite poor (each herbivore under a brain would have a random chance to move towards its next meal each cycle), so this let me keep using the brain approach, but only allow each brain to control a single herbivore before spawning a new one.
Some technical goals that I have coming up at some point aside from the more functional ones above:
Allow for entity configuration to be stored to and read from physical files.
Figure out a good way to store entity parameters in a sort of balance; e.g. as one raises, one or more could lower. I’ll delve more into the functional reasons behind this when I get closer to doing it.
Hopefully it won’t be a full damn year before my next update, but, it might!
After a small hiatus to deal with life, I’m back at it! There’s a bunch of ground to cover in this post; I’ve made some significant performance optimizations, some behaviour changes to the grass, and have also added water generation!
Alas, I wasn’t thinking to take screenshots while anything was in progress, so be forewarned that this will be more of a text-heavy update, with just a couple images of the latest progress.
More speed!
First let’s talk about the performance improvements. This is probably the most boring bit as it’s almost entirely behind-the-scenes work, so I’ll try to keep it brief… ish.
The existing issue was that, in order to be aware of its surroundings, every piece of grass was checking for other game objects in a small square around it every single time it was updated by the program – roughly every frame. This caused the amount of computation to quickly ramp up as more and more grass was spawned, creating significant slowdown after running for even a minute or two. I tried experimenting with adding a delay to the grass calculations (pause for X frames before updating again), which did help to some degree, but ultimately didn’t solve the issue at scale.
I had a number of thoughts on how to deal with this (and suggestions from some friends I was bouncing ideas off of), but settled on creating a new script (I’ve called it a “brain”) that is in charge of controlling a collection of grass squares. When the program starts I spawn a number of brains with one grass square each, and every update cycle each brain script randomly chooses one of its grass squares to run its own updates, and the others remain idle. Each time a new square of grass is added, it’s placed under the control of an existing brain. This means that as the program runs, the number of grass updates stays consistent, rather than increasing with new grass growth.
This new approach creates some new issues that need solving – primarily that it artificially slows the growth of grass as time goes on – but the performance gains are very much worth it. As I write this post, I’ve had a simulation running for over 20 minutes with virtually no slowdown.
A blue addition to the family
As much fun as it has been tooling around with the grass (though as you’ll read later, I’m definitely still doing that), things won’t really get interesting until there’s more factors within the simulation. My next step here was to add bodies of water to give the grass a more meaningful way to gain energy.
My method for generating the water was to first place a small number of initial “seed” squares of water and then continue to add more water next to existing water semi-randomly. I limited the placement to the main cardinal directions (no diagonals) to keep the bodies of water contiguous. I’ll need to come up with something a bit more sophisticated eventually for things like rivers or streams that have more intentional shapes, but for now this does the job well enough.
When adding the water I ran into technical issue due to some code I had taken from the first game tutorial I built. Essentially, it placed random game objects by first creating a numbered list of all squares on the “board”, then picking from that list at random, placing the object there, and removing that position from the list. This is what I was using for initial grass placement.
It’s is a very clean and efficient method if we are only placing objects randomly from the list, but the water is now being placed in semi-specific positions. Since there was no efficient way to find a position in that list based on its coordinate, any alternate placement method (e.g. water next to water) would cause the list to no longer reflect the “board” state, making collisions possible.
The solution was relatively simple: I needed a placement method that could check whether or not a coordinate was “empty” before placing an object there. Luckily I had already created exactly that for the grass’s growth script, so I only had to make a more abstract version for the world generation to use. This let me scrap the “list” method entirely and streamline object placement overall. As with most things this isn’t without its drawbacks (e.g. since we don’t keep track of free squares, placing an object randomly on a very full screen becomes exceedingly difficult), but we’ll also toss this on the “good enough for now” pile.
Lastly, I visualized water “depth” by changing its colour based on how many water tiles surround it. This is purely cosmetic; if I ever want to do anything functional with water depth I’ll want something a bit more meaningful, but for the time being it’s much nicer looking than just flat blue.
Ta-da! Initial world generation, now with water!
Yes still more about grass
With some performance issues solved and water existing in the world, I was able to start making some significant updates to grass behaviour. The primary change being to how grass gathers energy.
Previously, grass would lose a fixed amount of energy each “update” and then gain back a semi-random amount based on how many grass and non-grass squares were surrounding it. Then if the energy reached a threshold it would try to grow, if it hit zero the grass would die. I manually tweaked these values so that the grass would live in some cases and die in others, but on the whole would generally live. While this successfully created something interesting to look at, it ultimately wasn’t very meaningful. There was enough variability to make it look vaguely organic, but grass that was in a “living” position would essentially never die, which was far from ideal.
Instead, grass now gains energy based on its proximity to water. This has some limits (that I’ll go into below), but is a big step towards the environment determining how the things in it behave. And going back to an old idea about crowding, the amount of energy grass loses is now increased when it is surrounded by more grass.
Another small change I made was to allow grass to grow up to 2 spaces away. This wasn’t in response to any particular challenge or goal, other than to give entities more behavioural options.
The result of the above changes was very satisfying. We see grass clustering around water sources, but not too aggressively. Growth now slows down when grass starts to fill up space, and we no longer see a trend towards large, uniformly dark green clumps. We also see grass start to die around the fringes when it tries to grow into spaces that are too far from water or that create too much competition.
Improved grass growth behavior
Unfortunately, as mentioned above, there’s some limits to the new behaviour. The biggest issue is the strict limit to how far grass can exist from water due to how distance is currently being calculated.
The “standard” way to calculate distance is to scan the game area (or a sufficiently large portion thereof) for every single object that exists on the correct layer, then iterate through each one and do some math to figure out which is closest. This works in a lot of cases when dealing with a limited number of objects, but it my case it scales poorly.
Since grass and water exist on the same layer, the distance calculation becomes less efficient as more grass squares are grown. The current band-aid for this is to limit how far grass will look for water, which limits the potential number of grass squares it will have to check. The downside is that this makes an artificial threshold for where grass can live.
This is an issue that, going forward, will effect anything that needs to make decisions based on what it knows about the world, so I’m going to have to find a better long-term solution. My ideas right now involve giving objects a “memory” for certain things that will update when the target in question changes, rather than every time the object needs to make a decision that involves the target.
What’s next?
Some upcoming priorities are:
Create an ambulatory animal entity that uses the grass for food.
Update the “brain” script to allow splitting off after it gets to a certain number of controlled objects.
Implement aging for living entities.
Upload the project to Github. This was a request from a friend to check out the source, and figure it wouldn’t hurt to share it here as well.
Create a proper to-do list. I may also make this public.
This time: less of a dissertation, more pictures! I’ve been working on getting the grass to, well, do things. As previously mentioned, I had thought to try to somewhat mimic Conway’s Game of Life, but departed from that relatively quickly. Instead, I came up with some initial assumptions about how grass should behave:
It doesn’t move, but it can grow to adjacent spaces.
It will grow when it has enough energy, and will die if it runs out of energy.
Growth reduces energy.
It doesn’t live well in isolation, but it also doesn’t thrive when crowded.
All behaviors should include some variance.
Gotta Start Somewhere
Before implementing any behaviors, I had to do some figuring-out how to get the grass to interpret the game state and make copies of itself, which is mostly boring. Instead, here are a few early failed tests:
This one also caused Unity to crash!
OH NO
The above made me realize that the square boundary I had drawn didn’t have any application yet in how the game understood itself, so I ended up just making the whole background brown and have delegated “game boundaries” to be a future problem to solve.
Also at some point between the above two tests I did manage to create a state of equilibrium; the grass was not yet growing, but it was dying in a relatively random – but ordered – way.
Like, Mold or Something?
The equilibrium test was nice because it was demonstrating some of the assumptions I had made. Since it dislikes crowding, the grass would die if there were too many other adjacent grass tiles. However, this was a bit much. Plants don’t tend to just fully die because there’s other plants around, plus in future tests it just looked very inorganic, so that behavior was greatly reduced.
Next I reached a stage where the grass actually appeared to grow:
This was good! I then thought it would be neat to visualize the “health” of the grass:
This is the first point where I thought “Oh, neat!” My main issues here are that A) grass in isolation was dying far too quickly, and B) the growth was very uniform and uninteresting. Groups of grass close enough together would simply amalgamate into a big blog and grow outward with little variation.
Something Not Entirely Unlike Grass
At this point, the internal workings of the grass had quite a lot of settings to fiddle with. And fiddle I did. For a couple days. Until it reached its current state, which I’m quite happy with:
The biggest differences between this version and the previous are that it is much more likely that grass in isolation would stagnate rather that die, and that a piece of grass would not always choose to grow to an adjacent square when it had enough energy to do so. This led to a great deal more variation in the patterns that grew. It still does trend in the direction of a solid blob, but that’s more of a function of there being nothing to curb its growth; there’s infinite energy for it to grow with, and nothing to eat it.
For fun, I also made a GIF with the same settings but double the size:
One thing you might notice near the end of that one is that the frame rate starts to noticeably drop. If I let it run much longer it absolutely crawls. So, I will definitely need to put in some work optimizing the current processes. Every individual grass square probably doesn’t need to be acting every frame, eh?
What’s next?
I still have a few things I’d like to do with the grass, such require growth to take time, and, as mentioned, I need to try to optimize the speed a bit. After that, though, the next two additions I want to make are some sort of herbivore creature and water. These will introduce something for the grass to consider food, and something to consume the grass.
Today, let’s talk a bit about what I actually want to make with this project, as well as some of my first steps into creating something in Unity.
So what’s all this then?
I’m about to deep dive into my motivations and thoughts behind the project, which may not be everyone’s cup of tea. So, I’ve put the concrete idea up at the top in plain language: I want to build a “life simulator/sandbox” with the primary purpose of producing emergent behavior. With that out of the way, feel free to skip ahead at your discretion.
Why would you do this?
As I mentioned in my last post, I’m taking a lot of inspiration from Dwarf Fortress. For the unfamiliar: it’s a deceptively complex 2D simulation game about an expedition of dwarves establishing a new settlement out in the wild. It’s best known for its steep learning curve, challenging UI, and the developer’s massive ambition in modeling realistic physical interactions in a 2D world. While the game simulates some high-level behaviours such as hunger and thirst, most of the specific details such as where to dig, what to build, and who takes on which jobs is left up to the player. After having played the game for a while, I had the thought: “What if the dwarves could order themselves?” Over the years I’ve abstracted from and built onto this thought, but ultimately this question is what formed the project I’m working on today.
From that question, I started thinking about how it could happen. How would they learn? Could they learn from each other? How would they know how to survive? How would they know what “survival” even is? This was before I had really heard of things like genetic algorithms, but I started dreaming up what was essentially an unsophisticated version of just that. I became enamored with the idea of creating a world with creatures that try to figure out the best way to make their way in it with as little direct input from me as possible.
I have something of a love for abstraction. One of the things that I enjoy most about my job is when I get to break down systems or procedures into their component parts so that they can be more easily reused. Sounds like so much fun, right? So, naturally, over time my ideas progressed roughly from “dwarves” to “humanoids” to “animals” to “living entities.” Gradually I realized that I cared very little about what the things in this world would be, and more about what they would do. And if I created a complex enough simulation, could they learn behaviors that I didn’t explicitly give them?
This train of thought doesn’t really have a terminus station; it just keeps driving on through the minutia of how I’d like to accomplish the above. I’ll probably get into it more in the future, as I’d like to write down more of these thoughts and perhaps be able to look back on this blog as something of a design document, but for now there’s just one more thing I want to touch on:
Where’d the “game” go?
Beyond my “shiny new idea” zeal, I realized that I’ve removed pretty much everything from my initial inspiration that could be considered a “game” or “playable” or “fun.” If the creatures in the world order themselves around, then what does the user do? Why would anyone care about any of this? Interactivity is something that I’ll have to flesh out over time, but I do have some preliminary ideas/principles to build on:
Expose interesting data. I want to build an interesting world, so it makes sense to let the user learn about it. As I’ve decided to make a 2D game (I’ll touch on this a bit more below), I’ll be limited in what I can demonstrate visually, so this will require some creative solutions. I’m going to do my best to avoid ripping off Dwarf Fortress wholesale, but in terms of representing complex systems in a 2D world, I’m sure it will have its influences.
Establish a sense of progression. This one is a bit harder to define, and probably even harder to pull off, given the game should be largely unscripted. But I do want the user to feel like time spent with the simulation is building to something. I’m currently tossing around thoughts on giving the user more tools and interactions as they reach certain milestones.
Let the user poke it. One of the more interesting aspects of simulations is being able to alter its parameters to see what happens. Users have a knack for finding the most unexpected ways of using software, and in this case, that’s something I want to foster. The extent to which the user can poke things could be gamified, and/or tied to some progression mechanic.
Is any of this tangible?
Welcome, at long last, to the game development portion of my game development blog series. As I have mentioned previously I’m very novice to the language and tools that I’m going to be using, so for the moment my goal is more about learning and experimentation. Today’s adventure is in outputting displaying graphics to the screen! [star wipe]
2D, or not 2D?
One of the first decisions I had to make about this game is what kind of graphics I wanted it to have. I’ve known I wanted it to be 2D for quite a while, for a number of reasons. A big one is simply that I have little talent for graphic design, and I want to be able to represent the info being generated by the system in a simple way. This does put some constraints on how the world can physically behave, but that’s not a big setback in my overall plans.
Unity is a 3D engine, but it does have a 2D mode that works just as well. This mode effectively “erases” the game world’s z-axis by fixing the camera perpendicular to the x-y plane, and eliminating visual perspective. Unity also has some 2D-specific components for things like physics which are simpler than their 3D counterparts.
Baby Steps
First things first, I need to be able to draw things to the screen. The 2D game tutorial I had already finished taught me how to output sprites (static 2D graphics) to a grid, so I had a bit of something to work with there. I decided to start with simple coloured squares. I’d use brown squares for ground, green squares for grass, and display them in a semi-random distribution. This was pretty simple to put together based on the tutorial code, but the visuals looked somewhat off. The squares weren’t all, well, square.
As it turns out, displaying a sprite in an exact number of pixels on a 2D representation of a 3D world isn’t as simple as it sounds. I don’t intend this to be a tutorial so I won’t get into the nitty gritty, but the short version is that – depending on a bunch of different factors (camera position, screen resolution, pixels displayed per game “world unit”) – sometimes a sprite’s calculated size includes fractions of pixels, which need to be rounded either up or down to be drawn to the screen, resulting in irregularly shaped squares. The even shorter version: math was trying to ruin my game.
So, I started tweaking settings. I laid out the ground and grass tiles in a checkerboard pattern to better see the changes, and got something like this:
Bad PPU! This is one of the worse looking versions.
I spent a few days trying to resolve this issue, and came close a few times to simply accepting the fact that I’d have funky shaped sprites forever. But with the help of some online tutorials and discussion threads and magic incantations, I found the configuration that I needed to get a “pixel perfect” 2D display. The final piece was setting a fixed resolution for the game display. Please don’t ask me to explain exactly why that’s necessary. But, it worked! And my checkerboard started looking like this:
Good PPU! Everyone is behaving nicely.
After that, I modified the ground/grass placement script to make things a bit more natural looking, and adjusted the camera position so that the squares would appear as 4×4 pixels, et voila:
Just like real grass!
I also made some adjustments so that grass tiles would be placed on top of ground tiles (rather than being placed instead of ground), but that’s uninteresting and visually irrelevant.
What’s next?
Next I make it do things! My idea is to create something similar to Conway’s Game of Life. This will require me to figure out how to get entities in the world to determine things about their own state, as well as the state of the world around them. Stay tuned! There might be a GIF.
I often flit between hobbies like a hummingbird between morsels of nectar, and my most recent pickup is video game development. I’ve actually been kicking around ideas for potential game projects for more than a decade, and after a few false starts over the years, I’m finally giving it a proper go.
I’ve been a professional web developer for almost 10 years now so I’m no stranger to programming, but this is a whole new beast. I’m learning a lot, and I thought it could be fun to document my progress. Partly as a way to keep up motivation, but I also just like to share.
Humble Beginnings
My previous attempts to get into game development started with attempts to learn C# and build something from the ground up, as is my natural impulse. However, this is a fairly tall order to undertake in one’s minimal spare time, so I never made much headway. This time I’m going to be using Unity, a free game development platform with a lot of utility baked in. And more importantly, it provides a much easier spot to “jump in” and start creating with less preamble.
I spent the first few weeks of this adventure following along with one of the packaged tutorial projects provided by Unity. In my hubris (and desire to just get on with it), I picked an intermediate tutorial (2D Roguelike tutorial). Additionally, it also more closely matched the style of game that I wanted to build, rather than the beginner 2D platformer tutorial. It however skipped over a bunch of the more basic functions of the program which I had to back myself into learning. But for better or worse, I did eventually find myself with a completed game!
Tutorials make it easy, right?
On top of getting up to speed with Unity, I’m also learning the particulars of C# (the programming language used by Unity to script game behaviors).
Both languages that I work with – PHP and JavaScript – are considered “dynamically typed” languages. This means that the program will attempt to convert data to the most appropriate type based on how it is used. (E.g.: using “10” as a number for arithmetic, or as text if I try to count how many characters it has).
On the other hand, C# is “strictly typed,” meaning that I need to explicitly tell the program what type of data is being used before using it. I also need to perform specific operations to convert data from one type to another. For the non-technical types: it’s like knowing how to drive an automatic transmission, and needing to learn standard. There’s also a bunch of other quirks that I will mercifully avoid covering in detail.
What’s next?
Next I start on the actual game! Or, an actual game. Or something. I don’t imagine I’ll nail it on my first try, so my first goal is to just play around and attempt to implement various ideas to get a feel for the tools available. Maybe I’ll make something fun along the way, but more likely than not I’ll have to toss everything out and start over at least once or twice.
I’ve already made a bit of progress on this next bit, so expect an update soon. I also promise to include some real details about what plans/ideas I have. (Spoiler: It’s a simulation with heavy influence from Dwarf Fortress).
Want to come on this journey with me? You can subscribe to email updates using the form in the left-hand bar!