Posted January 07, 2025 by Avskum
Today I rolled out the Iron Skin passive ability, a new defensive upgrade system for my game.
The primary challenge was determining how the damage reduction should scale. While sky-high reduction might sound appealing, it could easily break the game by making players immortal. I settled on 5% reduction per level, capped at 3 levels (15% total). This strikes a balance between meaningful protection and maintaining the game’s challenge.
I faced an architectural decision: should the damage reduction logic live in the player class or the health component? Ultimately, I chose the health component because:
Another subtle but critical challenge was deciding when to apply the damage reduction in the damage calculation pipeline. Placing it too late could cause inconsistencies with systems like critical strikes or enemy buffs. I resolved this by applying the reduction as early as possible for consistent behavior.
Testing uncovered a few pesky edge cases:
I implemented robust debug logging to track damage calculations step by step. This approach was a lifesaver in identifying and fixing these issues.
Playtesting revealed that 5% per level felt just right — impactful but not overpowered. To future-proof, I also capped total damage reduction at 90% to avoid stacking abuse from other defensive upgrades.
I’m considering:
The second major feature I tackled was a dynamic weapon and upgrade visualization system. The goal was to create an intuitive HUD that shows players their weapons and associated upgrades in real-time.
The biggest challenge was making the HUD truly dynamic. Unlike static placeholders, the HUD needed to reflect only the weapons and upgrades players had acquired, starting with the default sword.
The HUD is structured vertically for clarity:
One significant challenge was handling the node structure in the HUD’s UI framework. Missing containers for upgrades caused display issues. The solution was enforcing proper node creation order and parent-child relationships.
This feature reinforced the importance of:
During playtesting, I discovered a critical bug in the player damage system. If the player remained stationary while in contact with enemies, they would only take damage upon initial contact. This created an unintended "safe state" where standing still allowed players to avoid further damage.
The issue stemmed from relying solely on Area2D’s enter/exit signals for damage detection. While these signals worked for detecting initial contact, they didn’t account for ongoing collisions. Once an enemy entered the player’s collision area, no further damage checks occurred unless new movement triggered another signal.
I overhauled the damage detection system to actively check for overlapping bodies each frame, ensuring damage is applied consistently as long as enemies remain in contact. The solution respects the existing damage cooldown timer to prevent excessive damage application.
This fix restores combat fairness by requiring players to manage their positioning at all times. Standing still no longer provides immunity, aligning with the intended design of tactical movement and enemy avoidance.
The new system is more robust but slightly more resource-intensive due to continuous collision checks. However, the performance impact is negligible given the limited scope of these checks.
This fix prompted a broader review of collision-based mechanics. I’m evaluating other systems that might benefit from similar ongoing state checks instead of relying purely on event signals.
The Iron Skin Defense System, Dynamic Weapon HUD, and Player Damage Fixes are solid updates that address core gameplay issues and enhance the player experience. While not groundbreaking, these features mark steady progress and reflect thoughtful system design, debugging, and balancing.
Next steps? More playtesting, player feedback, and refining these systems to ensure they shine in the chaotic, fast-paced roguelike environment. Stay tuned for more updates!