MicroRogue DevDiary #1 – Introduction
This is infinite promise. This is an (almost) empty Unity3D project. Yikes!
I am making a small 2D-ish action roguelite for PCs.
 I plan to finish the game within 2-3 months, plus publishing. As deadlines go, I’m being optimistic. We’ll see.
 The game is sort of pseudo-3D — it looks 2D and all sprites are flat and billboarded, but the camera uses depth and perspective
 The game is real-time, not turn-based: all actions and fighting happen live
 It has most of the roguelike features: you traverse random dungeons and fight hordes of baddies, collect loot, die horribly and restart, etc., but at the same time it’s -lite: more forgiving, free movement, real-time, less deep, etc.
I plan to publish the game on Steam, likely without early access first. This isn’t my “dream project” and I don’t expect major sales or reception. This is more of a “just get it done” sort of thing.
I will be working on this alone. Yes, that includes art. My current plan to go for super-simplicity, close to abstract style. Minimal lines, minimal colors, majority of visuals procedural. Art is not my strength and I will not feature creep this part. I will ruthlessly chop features if they demand artwork.
I will keep these dev entries fairly short and add screenshots. These entries are primarily for myself to think out loud and see if things make sense when articulated. They are also frequent checkpoint deadlines so I can keep on top of my schedule.
Now that I’ve “officially” committed myself to this, time to get to work.
MicroRogue DevDiary #2 – Framework
I have a lot, A LOT of half-baked prototypes and unfinished games. I’ve gotten really good at making frameworks for them. In fact, I literally copy-pasted the core code from one of my previous projects and used that as the foundation for MicroRogue. To put it in perspective: it took an hour to set up the project.
So now I have this in my scene by default:
Basically, this is a full game loop and all the primary game systems I would use. Plus I can easily add, remove and extend these. In the long run, this gives me the best control over–to put it simply–what happens when and how.
I want to jump into talking about mechanics and all the technical bits I’m doing, but I think it is important to establish the foundation that I am working from. This is years of experience, experiments and well-tested approaches that are condensed into a small, practical bundle. I can go into each one in detail and I might do that in future entries when talking about related features.
In addition to that, I have a bunch of truly independent plugins or modules. For example, the ones I have now (left over from the previous project):
So whenever I say in future posts that “I’m just using my input system/manager/thing”, I am likely referring to a previously-created system that I am adjusting to my current needs.
I swear, the next post will get into actual game-specific stuff. I just felt I need to get the whole “framework thing” off my chest.
MicroRogue DevDiary #3 – Tiles
One of the first features I’m working on is tiles (and maps and rooms) and how it all ties with the dungeon generation as a whole. To begin with, I’m starting very simple with just a bunch of tiles in a grid:
Note the slightly angled camera for that pseudo-2D look. I’m sure I will be tweaking it further a lot, but it gives the basic idea of what I am going for.
From there I can set up a basic dungeon generation pipeline and put tiles in some sort of order:
(There are also player and dummy enemy objects, but I’ll talk about that later.)
The way I plan to do the level layout is to have a grid of rooms (sort of like Binding of Isaac, but with more variable room shapes and camera is not fixed). Each room is a self-contained collection of tiles. The rooms then connect to each other, forming a dungeon.
So, to start it all off, I need a room editor:
In fact, let’s skip right down to having made an editor for this:
Now I can just select the type of tile I want and click/drag the map to update it. Instant preview. This is one of those editor tools that should save massive amounts of time versus trying to use dropdowns and such. (Plus, in the future I will need additional information, like loot, enemy spawn points, etc.)
My tiles are also just prefabs that know how to take a tile definition and apply its properties, currently the sprite it uses:
This means the tiles in the world are actually the ones I want them to be under the current “tileset”.
Each room is an asset. And a bunch of similar rooms form a collection of rooms. These collections can be referenced by a level (asset). So, for example, I could have a bunch of variations of generic library room and the current level might be a library. This saves some redundancy of trying to drag&drop dozens of assets that are shared between levels.
In short, all this results in the dungeon generator picking the right rooms for its (yet to be actually coded) generation:
The above is a start room, a few regular room and a goal room.
The above is lots of framework and details to set it all up for later content creation. It also happens to be very screenshotable, so this post is already long by itself and it only talks about the basics of tiles. There are so many features and mechanics that I will still need on top of this. Not to mention an actual dungeon generator. I’ve worked in parallel on player movement, but I will cover that separately. You can see dummy red mobs on the tiles and the green player.
MicroRogue DevDiary #4 – Movement
While my map is an obvious grid and my tiles are an obvious grid, the actual movement is not restricted to grid squares and both the player and enemies can move freely. What this means is that I need a movement and collision system that can “run into” and get blocked by certain tiles, namely walls.
Making the player move is relatively simple. Read (keyboard) input, decide on direction, tell player entity to move, adjust coordinates. Of course, it’s a bit more involved with accelerations, friction and walk speeds from definitions, but the basic extendable concept is simple enough. (Plus the camera to follow the player, which will get expanded later.)
Now we just have to make sure they can’t simply walk out a room through a wall:
In simplest terms, my problem is: how do I stop the player from moving into walls. I really don’t want to overcomplicate this with colliders and physics and fancy logic with ellipsis and rounded corners. So the player is a square and the wall tile is a square. When the player attempts to move in a direction, it checks if there is a wall there. And if there is, it can only move the distance that snaps it to the wall. And this works 98% of the time just fine.
The only real problem is how to handle this:
What happens here is that the player is not actually entering a tile with a wall, but rather a tile with a door — that’s where its center coordinate is. And I’m not doing collisions with “everything”, just the immediate tile.
So what I ended up doing is also checking the neighbouring tiles of the tile that could block the player. That is, checking if the player happens to run into a corner of a neighbouring tile. Why am I not doing fixed grid again?
And as far as tiles and the player is concerned, this works perfect:
The final thing is to get the movement “smooth”. (Note that I’m implementing “smooth” movement after collisions, so I can debug collisions stuff with constant movement changes.) This involved 2 parts: acceleration when walking is requested by the player and deceleration when there is no walking happening. Essentially, I’m keeping a current speed of the entity and either accelerating it to the walking speed to decelerating back to 0. I’ve done this sort of logic before, so I’m skipping a lot of maths and details, but the result is as follows:
Even without smooth camera controls (it tracks the player exactly), it looks really nice. Here the GIF is super-exaggerated for demonstration purposes. The actual acceleration is quick, while deceleration is almost instant. The best controls are responsive controls, and the whole smooth speed logic is supposed to be subtle for that nice game feel. Mechanic-wise it makes little difference, but it is very noticeable when playing.
The final touch is that running into a wall zeroes the speed in that direction. It may sound obvious in hindsight, but it’s really hard to notice the “glitch” when playing unless you know to look for it.
There are other things that movement needs to handle. Firstly, effects that can slow the mob. That is, the input requests movement, but should not expect it necessarily. The game may slow the player down or speed them up. And, more importantly, there can be multiple things affecting the movement, for example, an explosion knockback or wind or slippery ice. I don’t have these “other” things yet, so I will mention them when I work on them, but I am potentially anticipating them and thus creating the movement with those features in mind. And I still need mob collisions, but that may involve damage and AI avoidance and such, so I will discuss this later.
It’s time to work on one of the main features of the game — the dungeon generator. I’m sure there will be many posts on this alone. I already made the very basic framework and have a plan of expansion.
Now, I cannot spend weeks and months on the dungeon generation algorithms (even if I want to). So the generator is a mix of hard-coded rules, presets and certain procedural randomness. As I mentioned before, a level is a collection of rooms in a grid. Each room has a grid of tiles. This means rooms are all the same size. Rooms are just templates/presets of tiles. So the generator builds a map of rooms and then places tiles for each room. The resulting “dungeon” is all tiles, but it’s quite obvious it was made from pieces (at this point, anyway; I will likely touch on this later). Another reason is that I want a simple minimap, so a grid is great, but I will talk about that later.
Here’s the first “real” version of the dungeon generation (if you can call it that already):
The generator would run in steps. A single step is what I call a “branch”. A branch is not necessarily an actual branch of corridors or anything, but more of an algorithm to generate a certain pattern of rooms. For example, the above is a “straight” branch, which just places rooms in a line. Could be circular, could be area, could be a single room, etc.
This approach is top-down design, more or less. The plan is that I decide on the layout in broad strokes, then append smaller strokes, then fill out details and polish it up. So may be I build 3 main corridors, then offshoot 10 small ones, then add 15 side rooms, then sneak in a couple secret treasure rooms.
Further expanding on this concept, here’s a “snake” branch:
This is basically a multi-branch branch, which is a branch that is internally several other branches. So a snake branch is several straight branches in alternating directions; here 3 segments of length 4.
At this point, I’m anticipating some serious debugging and testing of algorithms, so I’m getting ready early by having all the outputs nicely (to me, anyway) presented:
Moving forward, I need to start assigning room designations correctly. I can already specify regular, goal, and start rooms, so I am expanding that to primary, secondary and tertiary rooms as well as primary and secondary hubs — these are just nomenclature for building branching paths.
So here is a “dungeon” with correctly specified and selected rooms — start to hub, to another hub, to end goal:
And more debugs with better specific branch knowledge and room selections:
I guess I have flashbacks to my early programming days where I spent more time stepping through code than actually coding. So now I really respect good debug tools and the ability to quickly follow through a certain algorithm/process.
At this point I worked on room layouts (covered in the next blog post) that I needed to adjust to continue with dungeon generation.
Now to add more steps to the dungeon generation. For this particular layout, I would keep track of hubs and then spawn extra branches from there:
I am able to add branches like this, because the step that generates the dungeon layout is more or less abstract — it creates a node grid map and these nodes are mutable. Not until the whole layout is generated, do I start selecting rooms to match. This nicely separates and encapsulates the generation. (The nodes could be even more abstract, basically a node graph, but I want to avoid algorithms that need many iterations and are “noisy”.)
Extending the above to keep track of directions and choose random directions (the rooms with dots are secondary):
So let’s add some secondary branches and a some tertiary offshoots (the rooms with even bigger dots are tertiary):
Now we’re looking more like a dungeon! At this point, I can go wild with creating branches with just the few tools I already have. The top level code for this is very straight-forward. Of course, this needs a whole lot more tweaking and de-randoming to allow more organic layouts. I am not quite sure how to achieve the sort of results I’m looking for, but I’m confident I can get at least part way there with certain generation rules and options. For example, keeping scores for each room — how many connections it has, how many further rooms, how far it’s from the start or goal, etc. That way I can “randomly” choose dungeon areas in need of additional branching and features.
I know I’m reinventing the wheel with some of this. But at the same time, I doubt a complete dungeon generation solution will fit my needs and will likely take longer to learn and integrate.
MicroRogue DevDiary #6 – Room layout
Time to work a bit on the room definitions/templates, so that I can create dungeons with proper room layouts. One of the “issues” with rooms is how to connect them correctly. If two rooms currently “connect”, it looks like this:
Firstly, rooms point in every which direction and the doors lead to nothing when there isn’t a neighboring room. This is, of course, because all my rooms have doors in all four directions. For my first attempt, I added a direction for each tile and a secondary tile layer to rooms; here’s the editor for this (the orange arrows let me “paint” direction on tiles):
Once directions are specified, I can check them against the required directions and switch to secondary layout tiles as appropriate. The two toggleable editor modes looks like this (arrows are colored according to the secondary layer):
The second issue is that rooms don’t overlap, which is obvious in how they (mis)align (note the double doors):
Now, that’s a much easier fix. I simply make the distance between rooms one less than the room size:
This works because I always assume that the edge tiles are empty, walls or doors and the doors are always in the middle. So I can just not place duplicate tiles for walls and doors — nothing should conflict. I might change this in the future, but that’s the assumption for now, which let’s me not worry about a whole slew of complications.
At this point I did a bunch more dungeon generations stuff and realized some deficiencies in my approach. It sounds cool in theory that each room can “transform” to match entrances and exits. But it turns out I don’t actually want to do it this way, because I cannot have that many variations and future specifying of room contents would be cumbersome at best. For example, it’s hard to specify or assume “this room has a corner here, so there should be spiderwebs” or “this is a cave, so there are some organic features”. So, for my second attempt, I simply made the rooms specify which direction the room is for:
I am still keeping the secondary tile layer, but I’ll likely just use it for something else. Of course, explicit room directions now means that I need to make a bunch more rooms for each direction combination (the letters are the cardinal Up, Right, Down, Left directions):
But it’s not actually that many. From here, I can apply rotational “symmetry”. That is RightDown room is the same as UpRight room rotated 90*. Nothing in the dungeon really cares about being in a certain orientation (and if it does, I can make the room non-rotatable and add the remaining orientation). In any case, that’s a bit easier than having 7 more room assets (RD, DL, LU, RL, RDL, DLU, LUR,
This is also where having collections of rooms instead of individual rooms comes in handy. A collection can collect all the variations and possible direction setups of the room:
But the level definition only needs to reference the collections of principal room types:
I currently only have exactly 1 variation for everything. But when themes are introduced, the levels would use different (but potentially overlapping) collections of rooms.
Now all that’s left is to have the dungeon generator actually decided what directions it needs, find a matching room, and rotate it before placed.
While working on this, I further realized I don’t actually care what the exact directions are if I am always using Up as the base direction (and if I don’t, I can just specify the direction explicitly). In fact, I only care about the 5 direction layout cases:
This also makes the code for comparing and searching for directions easier and somewhat more modular. First, I need to compare if room’s direction layout matches the required layout for the kind of room I want to place:
So the above places the right rooms. Now I only need to determine how I need to rotate each room, which is just comparing the principal directions:
And there we go, an approach that let’s me customize rooms differently based on their neighboring connections without a complicated editor.
Perhaps I could have avoided changing my approach and redoing some of the work. Perhaps a better initial design would have led me to the right answer sooner. But I think my framework is more stable after surviving the several iterations. And the direction/rotation approach is more robust than hand-specifying finicky room details and potentially getting it wrong. I’ve spent longer on this than I wanted, but at the same time, rooms are a core feature that I don’t want to get wrong.
MicroRogue DevDiary #7 – Items
While running the game today, I noticed that I occasionally got a room or two that were rotated incorrectly. These were always rooms with 3 and sometimes 2 connections. Meanwhile, all the other rooms were always fine.
I started tracking down the reason, but it was hard to reproduce reliably, since the entire dungeon is random. Skip a few hours later and I realized this was an error in determining how much to rotate a room template based off the comparison between desired and actual room directions. Okay so, the actual bug was that directions Up, Right, Left were sorted in that order, when in actuality I needed Left, Up, Right, because I am not just looking for the 3 consecutive directions, but also that they have the same “gap”. Same bug with Up, Left. In the end, I wrote a bunch of unit tests for my newly-made direction and rotation utility library.
Yay, unit tests.
Anyway, my focus was going to be on player equipping and using items. I’m going to talk about the actual combat at a later date when I’ve ironed out the details. It’s likely going to be gun-based, so I’m making the test items be guns for now (although it makes little difference for the framework, might as well be swords and bows). Anyway, first order of business it to make an item framework for the game. Tremble before my might inventory:
Items now have entities, definitions, world objects, sprites, links between all that and their collections in the world. I glossed over these details with other things – mobs and tiles, but they have the same data-definition-view logic. It’s all very independent, encapsulated and structured.
Making the player equip an item is actually the most straightforward part. I made a simple inventory with a weapon slot and I can place any item definition in it, whose sprite is then used on the player’s world object (using debug key to equip here):
In fact, I can extend this further to swap the currently equipped item and drop it on the floor. In fact, this is also quite easy given my item framework is basically a copy of mob/tile framework and those already know how to “appear” in-game:
Now I can also add a couple buttons to drop the current item and another to grab and equip the closest item:
Consequently, the player can swap the item with another by picking it. In fact, let’s polish it a little and drop the old item where the new one is:
Impressive! In all seriousness, I will need to have a much more time-consuming polish pass to actually drop and pick up items smoothly with animation and all sorts of flair.
Now I need to add another information layer to the room definitions. At the simplest, it is currently a list of location within the room that have a certain designation, such as “spawn a mob” or “spawn some loot”. This can be set in the room editor:
This is fairly easy to convert into an action when placing the room (most of the work was done with tiles). So the player gets a gun at the start now:
In fact, pretty much the same works for mobs:
I also created props — in-game objects that are not pickable items and would have collisions and interactions. They have the same exact framework logic as items (and mobs and tiles), so there’s not much to add. Here’s a loot chest prop spawned instead of an item directly:
Now we can get fancy and have the chest spit out an item when the player gets close (for the first time):
Of course, we need visual feedback for actions like opening chests. In fact, I will define my original chest as something I can interact with (chest) and specify that it should transform into an open chest, which is a different prop:
This now means approaching a chest spawn a new open chest and drops an item (but approaching an open chest does nothing):
The transitions happens seamlessly between the two props, so I don’t need to complicate prop logic (yet) with being able to transform them and such. If I ever need to transfer stuff like health between props (or any other property between mobs or items or whatever), I can do so manually while keeping the main logic cleaner.
Later, I will work on the random loot and mob generation and placement in rooms. But I need to get actual combat going followed by actual enemy AI
followed by MMO RTS elements. In other words, I need to start playing the game before I build more systems for it. I don’t really have the luxury to rewrite and redesign large parts of the game, so I need to test and get them right asap and not accidentally proceed into a dead end.
MicroRogue DevDiary #8 – Projectiles
Time to work on some gameplay stuff, so I added a projectile framework following the same logic as tiles, mobs, items and props. I feel like I’m still glossing over this a lot. Here’s the rough schematic of how things relate to each other:
Projectile is the class for these bad boys, doing their own things. Projectiles is where they all live and are controlled from. And World is where everyone (items, props, etc.) lives. Each projectile has its world object that appears in the game scene and is rendered, which used one of the projectile definitions, which is a bunch of properties projectiles can share, such as sprites. All of these derive from Entity parent classes for organization. Similarly, all other entities–tiles, mob, props, items–follow the same pipeline. So it’s all quite modular, reusable and shares common functionality.
Now, let’s make the player “fire” a bullet whenever mouse is clicked (and they have a weapon equipped):
Okay, the bullets don’t actually do anything besides sitting there (I moved the player myself). In fact, before I can point them anywhere, I need to translate the mouse click into the world click to know what angle to shoot the bullet. This would be simple with pure 2D, but my camera is in perspective and slanted, so I will use some raycasting math against a ground plane. Here’s an example 128 degree angle click:
Fascinating! And now that I have fancy math for angles, I can actually spawn a bullet in that direction (at a constant distance) from the player (without moving):
Some regular and some exasperating Unity maths later:
Now I have to fiddle a bit with the movement logic. I want to reuse player’s movement logic with projectiles. It sounds a little funky that I can use the same logic to “walk” the player as to “fly” the projectile, but fundamentally it’s the same “physics”, so why not.
I also have to fiddle with item logic. Different item types (weapon, armor, scroll, whatever) have different properties, act differently, are (if at all) equipped differently, etc. In the immediate logic, I need a projectile spawn distance from the weapon when firing, and that is weapon-specific.
Now, I only need to actually destroy the projectiles when they hit the wall tiles. Unlike the player, they shouldn’t glide along them (which they happily do). Anyway, here is pew pew happening:
This is click->fire each frame. What I need as properties for weapons is manual vs automatic firing mode and firing rate for weapon. So I implemented that. Not sure how the preview would be different much from the above, so just watch the previous GIF and pretend the fire rate is limited and set to automatic.
Finally, the bullets only hit the walls, since that is what the player “hits”. At this point, I worked a bunch on collision detection and experimented, so I will cover that in the next blog post.
For the purposes of projectiles, the collisions now detect when they hit a mob:
Finally, just need to make the enemies take damage when they get hit. And also visually change (to a different sprite for now):
Here the enemy gets hit for lethal damage, and goes through dying into dead state. (At some point, I’ll work on the whole sprite animation framework that I really want.)
Now I can extend and tweak weapons and projectiles to whatever I want. For example, here’s a shotgun that fires multiple projectiles with a slight spread.
Well, this covers the basics of projectile logic. By attempting to move and collide projectiles, I also extended and implemented a whole lot of other systems that I needed. I will be adding weapons and mechanics and various interactions at a later time. And at some point visuals and feedback, hopefully. This is one of the core game parts, so I will be definitely revisiting guns and bullets multiple times.
MicroRogue DevDiary #9 – Collisions
So my original problem of “how do bullets hit mobs?” turned into a much more elaborate “how do I collide stuff?”
As I discussed before, I have special logic for hitting tiles (i.e. walls), which is quite efficient and simple square collision to nearest tile check, and so highly specialized. I need a whole separate way of handling different-sized circle collisions between moving entities. It’s not great that I would have two separate ways of determining collisions with different collider shapes. It also complicates the code a bit. But it’s also very reliable and fully controllable. Pros and cons.
(I also briefly went on a tangent experiment where I did use Unity collisions for raycasting. This means every world object had a collider and I would resize it according to the entity collision size:
This didn’t actually work for many reasons. Unity isn’t very good at taking an entire collider and trying to see if it can move (technically, sweeping a rigid body). So I abandoned this approach. I’m also doing fake 2D, so it’s all 3D colliders and consequent issues. Honestly, I keep wanting to use native Unity physics and every time I find they just don’t do what I want or the way I want it and I cannot even compromise on a solution in between.)
Also, the wall collisions are not “disputable”, that is, you cannot move walls, you definitively cannot pass through them, and everything needs to align precisely; there is almost no leeway. Other stuff, however, mobs and props, and projectiles, and such can theoretically bump into each other, push each other around, collide with slight errors, etc.
So I went ahead and made that additional collision step where it first checks tiles, then checks non-tiles. It feels inelegant to me, but I can also justify this by having somewhat different collision requirements for the two cases.
Anyway, the very simplest non-tile collision version is just not allowing (essentially, stopping) the entity from moving into another entity’s space:
This essentially has to check every moving entity against every other moving entity. There are ways to optimize this that I will likely have to do later. In any case, this works fine for now, expect the player doesn’t “slide” along the collision. Collisions are all or nothing:
Here the player’s collider (blue) will intersect the enemy’s collider (red) if the player moves up (blue arrow). So the potential movement is flagged as “collision expected” and the movement is cancelled. The problem is determining which direction do I actually push he player? I would want to convert the movement along the tangent, then return the proposed direction, then run another collision detection with that direction. You know what, screw this.
Entities collide with square collisions:
Can one really tell it’s square collisions? Yeah, probably. But I have bigger fish to fry. Though I can imagine I will get back to this at some point.
Another consideration is exactly which entities collide together. For the player, it is usually intuitive and the first time you see something block something it shouldn’t, you start to wonder what the rules are. This can get pretty complicated when you consider which objects exactly are supposed to interact. Should items be hit by bullets? Should props block dead bodies? Should flying mobs block player? Do friendly projectiles hit each other?
And this doesn’t even stop and a simple yes/no check. I would need to write a huge method which knows about every single entity and checks them against every other entity. I want something more modular with less hard-coded rules.
So instead, every entity implements a function to look up the desired collision with another entity (and vice versa). This way, they can individually refuse the collision (for example, dead mobs might not want to collide with anything), force the collision (for example, bullets might want to hit almost everything), or accept the collision as needed (for example, props are fine to collide with most stuff with no special rules). Only special cases need extra handling. Here’s a graph:
Refuse takes precedence in these rules, but that’s really just the way I structured it. I could add more collision “results”, but for now this is sufficient to describe everything in the game and on the immediate radar.
Okay, this post has went on for a while with lots of text and not a whole lot of stuff to show.
MicroRogue DevDiary #10 – Room Contents
Time to get back to filling out rooms with stuff. There are still some fundamental things I need to do before I can start adding any kind of real data.
An approach I am already using is to group definitions of rooms and tiles so I can link a single collection asset and it will contain a longer list of individual items. Same with enemies now:
The reason I need this is because first of all I am making an editor for “spots” that appear in rooms. For instance, a spot designated for mob spawning could reference a single mob collection and choose a specific mob randomly:
So if I add a couple more mobs to the game, they can then spawn in-game now:
However, this is not a very flexible approach and more of a proof of concept than anything I can use when designing rooms. The same amount of mobs will always spawn in the same spots. What I want instead is to “paint” certain areas of a room and then specify that area as containing “something”, like certain mobs or items. In short, I want to say “spawn some stuff here”. For that, I will allow each tile to be part of a colored area (technically, numbered, but I am using colors so it’s easier for me to see and I won’t actually edit the raw number anywhere). Here’s an editor for that:
Now I can “paint in my editor”, that is, set tiles to belong to a certain area:
Then I need to make an editor for the currently selected area:
And a few adjustment to the dungeon room placement, and I have stuff spawning in the right areas:
…sort of. It still spawns items for tile individually. I didn’t yet specify how many things I want. So we can do that:
Now I have to tweak the generation to actually gather all the area tiles and then choose the right number of them randomly and spawn stuff there in a separate step:
I have used this approach before, so I implemented all of this fairly quickly and I might be glossing over a lot of details. But it works nicely for what I need and it’s fairly extendable.
And now I can also finally remove my hard-coded “spawn player in the middle of zone” and have an actual area for this:
This, however, is still not quite as modular as I want it to be. That is, I need to change individual numbers of each and every room to balance things. Say, my total number of mobs in a dungeon is 100, but I want to make it 120. Do I go through each room and change the numbers? Numbers are bad in design. You don’t want hard values, you want relative designations. In this case, I have a table like this:
And in the rooms, I now specify:
So “some” amount here translates into 2-4 mobs. All the rooms with “some” will get 2-4 mobs and I can change it in one central place.
Let’s go the same route with enemy definitions as well:
In other words, when I specify “weak” mobs I might not care if it’s skeletons or slimes, but I definitely don’t want dragons or liches. I am using “strength” here as a selector, but technically it can anything. I can have a room for invisible mobs or a room for flying mobs — whatever groups I want to make. I just don’t (necessarily) want to be overly specific, like “skeletons”. In fact, I want to avoid making any more than several of these groups.
Final tweak is that I may want to specify a certain level as “spider caves” or “undead crypt”, so I want to specify actual enemies based on the level/theme, not just strength. So I can add this to my level theme:
I do need new individual assets for each theme, and they will need to point to themed collections as well:
So here’s how it all works out in simple terms: a cave level spawns a room with an area that wants a few strong mobs, which means picking the strong cave mob collection from its enemy selection, which are something like spiders, slimes, skeletons, and spawning a few of them, which is 2-4.
This all sounds unnecessarily-over-complicated, and damn straight it is. Over-engineering is my hobby. And, yes, I love making assets. But here is a neat scenario where a large-scale change happens with relatively very few alterations. I can introduce a new mob (say, rock golem) and place it in relevant collections (say, caves and ruins with strong mobs). And it’s done — the generator will now create rock golems in caves and ruins in rooms that want strong mobs. Imagine going to each room and trying to fiddle with exact mobs it needs to spawn. Or, worse yet, having it stored somewhere in code. Worse yet, making a mistake.
In conclusion, I have a framework/approach to modularly fill out the dungeon with stuff.