▲ 16 r/Knightmared+5 crossposts

"I’ll replace it later" was a lie I told myself for almost 2 years

Lately, I’ve been working on new visuals across the whole game: VFX, enemies, tiles, UI, and UX.

Honestly, if I could start over, I would never rely on so much free placeholder art. Telling myself "I’ll replace it later" seemed harmless at the time, but after almost two years of development, it has become a real pain.

Wish list and/or play public Beta! :)

https://store.steampowered.com/app/3447010/Knightmared/

u/DeliriumMonstruozum — 2 days ago
▲ 10 r/Knightmared+6 crossposts

Godot 4 horde optimization: hundreds of enemies, lots of Area2D, and a painful reminder that 2D still needs performance work

I tried to put hundreds of real enemies in my Godot 4 horde survival game. The bottleneck was not sprites.

Test the game here: https://store.steampowered.com/app/3447010/Knightmared/

I have been working on performance for Knightmared, my 2D pixel-art horde survival game built in Godot 4, and the biggest lesson was pretty simple:

2D does not mean performance is free.

The Goal

My goal was to support hundreds of enemies during late runs. Not fake background enemies, but real enemies that can:

  • move through the map,
  • collide with obstacles,
  • damage the player,
  • get hit by abilities,
  • receive status effects,
  • die correctly,
  • return to pools,
  • use AI and pathfinding,
  • keep pressure on the player.

The Bottleneck

That is where Godot 4 started pushing back.

The bottleneck was not really drawing sprites. A pixel-art sprite is cheap. The expensive part was simulation: hundreds of physics bodies, Area2D hurtboxes, collision checks, navigation reads, animation updates, AI behavior, and ability interactions all active at the same time.

In a normal fight, that is fine.

In a horde survival game, every small cost gets multiplied.

I started seeing uneven frame pacing and stutter during heavier runs, especially when the screen was full and enemies were pressing around the player. At first it was tempting to blame one thing: movement, pathfinding, rendering, too many sprites, whatever. But after profiling, it was really a stack of smaller costs landing in the same frames.

Investigation

So I built more profiling/debug tools inside the game. I added toggles to isolate things like:

  • enemy hurtboxes,
  • enemy body physics,
  • Area2D monitoring,
  • animations,
  • Y-sort,
  • enemy visuals,
  • pathfinding,
  • FPS caps.

One useful lesson there: profiling while capped at 60 FPS can hide a lot. If your optimization only keeps the game at the cap, you do not really know how much work you removed. Being able to uncap during tests made it much easier to compare changes.

I also considered more radical solutions, like MultiMeshInstance2D or swarm/proxy enemies.

MultiMesh is very tempting for hordes because drawing hundreds of identical enemies in one pass sounds perfect. But my problem was not just visuals. If the enemy still needs collision, hurtboxes, damage reactions, abilities, pooling, pathfinding, and obstacle-aware movement, GPU instancing alone does not solve the actual bottleneck.

Swarm proxy logic is also interesting: a few leaders pathfind, and the rest follow simpler steering. I may still use ideas from that later. But for this pass I did not want enemies that only looked real. If the player hits an enemy, it should be a real enemy.

So the direction became: keep the real enemies, but make them cheaper.

What I Changed

  • Navigation is staggered and cached so hundreds of enemies do not ask Godot for path data at the same time.
  • Nearby enemies use direct chasing when full pathfinding is not needed.
  • Far/off-screen enemies can reduce expensive physics, Area2D, hurtbox, and animation work until they matter again.
  • Enemy spawning ramps toward a target alive count instead of creating rough bursts.
  • Special enemies have caps so behavior-heavy units do not flood the map.
  • Crowd movement stays collision-aware, so enemies do not just cut through walls for the sake of performance.
  • Menus are capped at 60 FPS because menus do not need to run at hundreds/thousands of FPS and waste power.
  • VSync is available as an option.

Result

My goal was not to make the game easier. I wanted the pressure to come from the horde design, not from Godot suddenly processing too many collisions, areas, navigation queries, and AI updates in one frame.

This was a good reminder that in 2D games, bottlenecks often move away from rendering and into gameplay simulation. The sprites may be cheap, but a living enemy with physics, Area2D hurtboxes, pathfinding, AI, animation, and damage logic is not just a sprite anymore.

For anyone else making a horde game in Godot 4: profile early, isolate systems one by one, and think carefully before assuming that "2D" means you can ignore performance architecture.

I can share more details later about the navigation changes, far-enemy culling, or the debug toggles I used to isolate the bottlenecks.

Test the game here: https://store.steampowered.com/app/3447010/Knightmared/

u/DeliriumMonstruozum — 25 days ago
▲ 4 r/Knightmared+1 crossposts

Knightmared public beta is live: a 20-minute auto-attack survival roguelike with weapon mastery and build-focused progression

 Hey everyone,

 I opened the public beta for Knightmared, our auto-attack survival roguelite where you build a knight into a demon-slaying machine over short, escalating runs.

 You fight through an arena filled with demons while the pressure keeps rising. Your weapons attack automatically, so the game is less about aiming or twitch reflexes and more about movement, positioning, upgrade choices, and building
 a run strong enough to survive until the boss.

https://preview.redd.it/1yjfaj5bcx3h1.jpg?width=1232&format=pjpg&auto=webp&s=71859c39cb28f57db39ea0cd2b39486c67a6fdfe

 Runs are designed to last around 15–20 minutes. Enemies get more dangerous over time, spawn density increases, and the run builds toward a final boss fight. If you kill the boss, you win the run. If you die, you still keep gold that
 can be spent on permanent upgrades.

 The main feature I am building around is Weapon Mastery. Weapons don’t just improve through level-up choices. They also progress as you use them. Kills with a weapon unlock deeper mastery tiers:

 Apprentice -> Advanced -> Expert -> Master

 As a weapon reaches higher mastery tiers, new upgrade options become available. The idea is to make weapon choice feel like a real investment, not just something you pick once and forget. If you commit to a favorite weapon across
 runs, its upgrade path opens up further.

 Current public beta features include:

 - One fully playable arena with escalating difficulty and a boss fight
 - Six weapons with distinct attack patterns and upgrade paths
 - Weapon mastery tiers that unlock advanced upgrades
 - Items and player upgrades for build variety
 - Gold-based meta progression between runs
 - Permanent stat upgrades
 - Arsenal Expansion, which unlocks extra weapon slots for multi-weapon builds
 - Short runs built around “one more try” pacing

 I am still actively developing the game, so feedback is genuinely useful right now. I am especially interested in hearing thoughts on:

 - Balance and difficulty pacing
 - Weapon feel
 - Upgrade choices
 - Which builds feel fun, weak, or too strong
 - Enemy pressure and readability
 - Bugs, performance issues, or confusing UI
 - What content you’d most like to see next

 If this sounds like your kind of game, I’d really appreciate you trying the public beta and telling us what you think. Wishlisting on Steam also helps a lot while I am trying to find the right audience.

 Steam page: https://store.steampowered.com/app/3447010/Knightmared/#
 Thanks for checking it out. Happy to answer questions here, and I'd love to hear how your runs go.

reddit.com
u/DeliriumMonstruozum — 1 month ago