[Devlog] A new enemy spawn system
Posted: Tue Mar 10, 2026 5:50 pm
Time for another devlog!
There was something a very insightful playtester (thanks zivi!!
) brought up, and it's the kind of thing that, once I heard, it made everything click: The current enemy spawn system tries to find spots near the player to put enemies in. This worked relatively well, but while it lead to fine gameplay, the issue that had been bugging me and I couldn't point out is that it did not really matter where you went: Enemies would keep spawning near you, so you could stay in place and keep farming forever. Sure, the game was incentivising you to move around in other ways (chests, raising difficulty, having to find an exit...), but at the bottommost core gameplay loop the game was incentivising people to stay put.
Now this is fine for a "survivors" style game, a genre in which I have some experience! But Iris Blade is supposed to be the opposite from a survivors game.
So it was time to redo enemy spawn logic!
Mulling it over, and the notebook
I'll go off on a bit of a tangent. I like to avoid "the topic" in my writing because we're all very tired, especially me, but there is one thing that keeps coming up when discussing with the cultists. They all bring up the usefulness of bouncing off ideas against the proverbial deus ex wall and how effective that is at organizing one's thoughts.
And you know what, I gotta give it to the cultists.
There is something truly special about being put in front of with my own thoughts, in writing form, that other forms of thinking don't quite let me reach. This will be different for different people. But I think organizing one's thoughts is truly the key to tackling larger complexity.
So, I devised a contraption that lets me do the same thing with a heavily reduced carbon footprint: The notebook. Now, I didn't invent the notebook. As far as I can tell, this was invented by YouTuber ThinMatrix, of Equilinox fame and Java gamedev extraodinaire. If only he had told us how key the notebook was to his success during the devlogs. Instead, he just hinted at us by showing quick montages of his pages upon pages of doodles every now and then.
Anyway, seriously now: The next time you're struggling with some problem and feel the urge to consult with a talking pile of tensors, try talking to your notebook instead! Oh and drink that glass of water instead, you've earned it!
Alright, It seems I am incapable of seriousness, so goofiness will have to suffice for now. Now, to better illustrate my point, I'm about to let you take very blurry peek into my mind Those are the first two pages, to fully converge on a design for this I wrote about six pages. If you've tried reading a bit of this, you'll notice it's just me rambling. I'm literally thinking and writing it down as I go, stream-of-consciousness style. I find the act of writing helps me connect the dots and steers me away from tangents in a way that's almost impossible to do with freestyle thinking.
You'll also notice my writing style is a bit wasteful, we're lucky paper literally grows on trees, eh?
And the notebook nerds in the room may also have noticed how I like my notebooks clear: no grids or lines. That's just my style and I don't really have strong arguments for it, other than the fact that no lines gives me complete freedom to doodle things, even if this page ended up being a bit more text-y. Maybe you're also having strong opinions about the fact a grown-up is using a pencil. You can even see it in the picture, a 0.7mm Bic Velocity mechanical pencil (to save you the digging). The reason? I find it useful, and even cathartic to be able to conveniently "erase" a thought once I realize something didn't make sense.
The economics of spawning a bunch of slimes
Back to the topic, if there ever was one: The Game Director, which is what I've been calling the bit of code responsible for spawning enemies and making some other interesting gameplay decisions, has now acquired two tasks: (1) Fill up the world with enemies at the start of the level and (2) Respawn enemies as they die so you get to catch a break, but never really run out of them.
In retrospective, this was much simpler than I thought. Anytime you need to do something "procedural", the answer is always chunks and noise functions. What I did is split the game world into chunks (yet again). Each chunk stores two new properties:
With this, we can define what I called the density of a chunk. Now, hopefully you'll excuse phpbb's lack of LaTeX formulas:
The Game Director's goal will be to keep enemy density stable across all chunks. But what does stability mean here? Well, that took a while to figure out, it's on page 4 of the notebook! At each point in time, we have a target density we want for the chunks. At the start of the run, that target density will be low. As the game progresses, we will slowly turn up the density dial, and things will gradually get crazier as the world is filled with more and more enemies, but keeping the original balance: Hotter areas get more enemies than colder ones.
So, by stability, what we mean is that we want to achieve a constant value for... some metric? Let's call it tension, even though it's a bit of a misnomer, like all the other terms here:
The tension formula has some interesting properties:
There was something a very insightful playtester (thanks zivi!!
Now this is fine for a "survivors" style game, a genre in which I have some experience! But Iris Blade is supposed to be the opposite from a survivors game.
So it was time to redo enemy spawn logic!
Mulling it over, and the notebook
I'll go off on a bit of a tangent. I like to avoid "the topic" in my writing because we're all very tired, especially me, but there is one thing that keeps coming up when discussing with the cultists. They all bring up the usefulness of bouncing off ideas against the proverbial deus ex wall and how effective that is at organizing one's thoughts.
And you know what, I gotta give it to the cultists.
So, I devised a contraption that lets me do the same thing with a heavily reduced carbon footprint: The notebook. Now, I didn't invent the notebook. As far as I can tell, this was invented by YouTuber ThinMatrix, of Equilinox fame and Java gamedev extraodinaire. If only he had told us how key the notebook was to his success during the devlogs. Instead, he just hinted at us by showing quick montages of his pages upon pages of doodles every now and then.
Anyway, seriously now: The next time you're struggling with some problem and feel the urge to consult with a talking pile of tensors, try talking to your notebook instead! Oh and drink that glass of water instead, you've earned it!
Alright, It seems I am incapable of seriousness, so goofiness will have to suffice for now. Now, to better illustrate my point, I'm about to let you take very blurry peek into my mind Those are the first two pages, to fully converge on a design for this I wrote about six pages. If you've tried reading a bit of this, you'll notice it's just me rambling. I'm literally thinking and writing it down as I go, stream-of-consciousness style. I find the act of writing helps me connect the dots and steers me away from tangents in a way that's almost impossible to do with freestyle thinking.
You'll also notice my writing style is a bit wasteful, we're lucky paper literally grows on trees, eh?
And the notebook nerds in the room may also have noticed how I like my notebooks clear: no grids or lines. That's just my style and I don't really have strong arguments for it, other than the fact that no lines gives me complete freedom to doodle things, even if this page ended up being a bit more text-y. Maybe you're also having strong opinions about the fact a grown-up is using a pencil. You can even see it in the picture, a 0.7mm Bic Velocity mechanical pencil (to save you the digging). The reason? I find it useful, and even cathartic to be able to conveniently "erase" a thought once I realize something didn't make sense.
The economics of spawning a bunch of slimes
Back to the topic, if there ever was one: The Game Director, which is what I've been calling the bit of code responsible for spawning enemies and making some other interesting gameplay decisions, has now acquired two tasks: (1) Fill up the world with enemies at the start of the level and (2) Respawn enemies as they die so you get to catch a break, but never really run out of them.
In retrospective, this was much simpler than I thought. Anytime you need to do something "procedural", the answer is always chunks and noise functions. What I did is split the game world into chunks (yet again). Each chunk stores two new properties:
- Enemy count
- Heat
With this, we can define what I called the density of a chunk. Now, hopefully you'll excuse phpbb's lack of LaTeX formulas:
Code: Select all
density = enemyCount / heat
So, by stability, what we mean is that we want to achieve a constant value for... some metric? Let's call it tension, even though it's a bit of a misnomer, like all the other terms here:
Code: Select all
tension = targetDensity / density
- If the chunk is at the target enemy density, it has a value of 1.
- If the chunk has a lot more enemies than it should, its value gradually go towards zero.
- If the chunk has less enemies than it should, its value will quickly raise
The mathematicians are screaming into the monitor as I am explaining division to the crowd. "Look at what gamedevs need to mimick a fraction", or something
But tension was the main ingredient here: When it's time to spawn an enemy, the Game Director will rank chunks by tension, and favor those with higher tension. Picking an element from a list at random with weighted probabilities was a recent topic of discussion, so I won't delve into that.
There's some twists I added to the idea, for extra chaos. Heat is typically computed by checking things in that chunk, like chests and whatnot. Each chest adds some heat, barrels add some heat too, and so on. But then I added a noise function on top, so even if two chunks have the same amount of stuff in it, some chunks will tend to be a lot more densely populated than others, just like life itself: And to you, the player, the real reason behind this variance is that I'm sure those slimes have a plan which makes them have some areas more heavily guarded than others.
I mentioned at the start of the section the game director had two goals: It turns out, the two goals are actually one and the same. A nice property of this system is that Initial spawn and respawning are two sides of the same coin. You start with an empty map, and you keep spawning enemies until you're satisfied!
It's hard to show this in action since the point is to feel it over the course of the run, but this was my best attempt in a short looping gif: And then the FPS dropped
But no tale is complete without some performance testing.
What's this I see? 45 FPS in my debug build? No, that won't do.
Spawning enemies near the player has some advantages. You get to play smoke and mirrors with them and despawn enemies once they venture too far off. When it's you against the horde, nobody will notice a missing bat.
But now that there's enemies all over, I couldn't pull off this trick anymore. It only took a quick glance at the profiler to notice the issue. Hear me out now: Invest some time into having a good profiling system!
The solution? Simple! Every performance issue can be solved in one of two ways: (1) Do it faster, (2) Do less work. Since my enemy logic is a port from Carrot Survivors, I know it was pretty optimized already: zero-allocation, uses a fast path for the spatial partitioning logic that's specific to enemies... So (2) was the obvious choice.
The next best thing you can do when you can't despawn faraway enemies is to freeze them. And that turned out reasonably well! I also took the chance to add culling logic to my Sprite component, which I hadn't had the need to until now (because most things in the game are tiles or grass and those are culled!).
Closing
Anyway, I hope you enjoyed the devlog!
I tried to go for a longer one this time, but I think it was time well spent. If I get to be a little selfish, please do let me know if you enjoy these. Gamedev can feel a bit lonely sometimes and despite what it might seem, morale among the carrot ranks hasn't been the highest.