Skip to content

Conversation

@burinc
Copy link
Collaborator

@burinc burinc commented Nov 9, 2025

Critical bug fix: Enemies weren't being destroyed when hit by bullets. This was caused by two interrelated issues in collision detection.

Problems Fixed:

  1. STALE DATA: bullets and enemies were captured at the start of update-game!, but collision checks happened AFTER bullet position updates. Result: checking collisions with old positions.

  2. RACE CONDITIONS: Each collision in doseq triggered separate swap! calls, but all iterations used the ORIGINAL collections. Multiple collisions on same bullet/enemy caused state corruption.

Solution: Collision Batching

  • Capture FRESH bullets/enemies right before collision detection
  • Collect all collisions in sets (preventing duplicate processing)
  • Apply ALL effects in a single atomic swap! at the end
  • Use :when guards to skip already-processed objects

Benefits:

  • Enemies now properly destroyed when shot
  • Boss enemies correctly track 2-hit damage
  • No race conditions or state corruption
  • Single re-render per collision batch
  • Predictable, deterministic behavior

This uses the same collision batching pattern from Asteroids, inspired by Erik Assum's feedback on atomic state updates.

Also updated article documentation to explain the bug and solution with detailed code examples and credit to Erik Assum.

Critical bug fix: Enemies weren't being destroyed when hit by bullets.
This was caused by two interrelated issues in collision detection.

Problems Fixed:
1. STALE DATA: bullets and enemies were captured at the start of
   update-game!, but collision checks happened AFTER bullet position
   updates. Result: checking collisions with old positions.

2. RACE CONDITIONS: Each collision in doseq triggered separate swap!
   calls, but all iterations used the ORIGINAL collections. Multiple
   collisions on same bullet/enemy caused state corruption.

Solution: Collision Batching
- Capture FRESH bullets/enemies right before collision detection
- Collect all collisions in sets (preventing duplicate processing)
- Apply ALL effects in a single atomic swap! at the end
- Use :when guards to skip already-processed objects

Benefits:
- Enemies now properly destroyed when shot
- Boss enemies correctly track 2-hit damage
- No race conditions or state corruption
- Single re-render per collision batch
- Predictable, deterministic behavior

This uses the same collision batching pattern from Asteroids,
inspired by Erik Assum's feedback on atomic state updates.

Also updated article documentation to explain the bug and solution
with detailed code examples and credit to Erik Assum.
@burinc burinc merged commit 964e143 into ClojureCivitas:main Nov 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant