Space Game Canvas Collision Detection Algorithm: AABB Implementation in JavaScript

The space game canvas collision detection algorithm uses an axis-aligned bounding box (AABB) overlap test to determine when rectangular game entities intersect, checking geometric boundaries each frame to trigger collision events between heroes, enemies, and lasers.

The collision detection system in Microsoft's Web-Dev-For-Beginners repository demonstrates a foundational approach to handling interactions in HTML5 canvas games. This space game canvas collision detection algorithm relies on pure geometric calculations rather than physics engines, comparing the rectangular bounds of sprites to detect overlaps and emit game state changes through an event-driven architecture.

Understanding the Axis-Aligned Bounding Box Approach

The algorithm employs axis-aligned bounding boxes (AABB), a standard technique in 2D game development where every game object is treated as a non-rotated rectangle defined by its top, left, right, and bottom edges. This simplification allows collision detection to use simple numerical comparisons rather than complex polygon intersection calculations, making it ideal for beginner-friendly canvas games where sprites remain parallel to the canvas edges.

Core Components of the Collision System

The intersectRect Function

The geometric heart of the system resides in the intersectRect function located at lines 126-128 in 6-space-game/4-collision-detection/solution/app.js. This pure function implements the separating axis theorem for rectangles by checking if one rectangle's left edge is to the right of the other's right edge, or if one's top is below the other's bottom:

function intersectRect(r1, r2) {
  return !(
    r2.left > r1.right ||
    r2.right < r1.left ||
    r2.top > r1.bottom ||
    r2.bottom < r1.top
  );
}

If any of these four separating conditions are true, the function returns false (no collision); otherwise, the rectangles overlap and it returns true.

The rectFromGameObject Method

Every drawable entity in the game—Hero, Enemy, and Laser—inherits from the GameObject class, which provides the rectFromGameObject method at lines 36-43. This method converts an entity's position and dimensions into a rectangle object compatible with intersectRect:

rectFromGameObject() {
  return {
    top: this.y,
    left: this.x,
    bottom: this.y + this.height,
    right: this.x + this.width,
  };
}

By centralizing this conversion, the system ensures consistent boundary calculations across all game object types, regardless of their specific sprite implementations.

The updateGameObjects Function

The collision orchestration occurs within updateGameObjects at lines 206-229, which the game loop invokes every 100 milliseconds. This function filters the global gameObjects array into enemies and lasers, then executes pairwise collision checks:

  1. Hero-Enemy Collisions: Each enemy rectangle is tested against the hero rectangle using intersectRect. On overlap, the system emits Messages.COLLISION_ENEMY_HERO.
  2. Laser-Enemy Collisions: Nested loops check every laser against every enemy. Successful intersections emit Messages.COLLISION_ENEMY_LASER.
  3. Cleanup: Objects marked as dead are filtered from the array, preventing them from being drawn or participating in later collisions.

Step-by-Step Collision Detection Flow

The algorithm executes through a deterministic sequence each frame:

  • Bounding Box Extraction: For every entity participating in collision, rectFromGameObject() generates current position data based on x, y, width, and height properties.
  • Separating Axis Test: intersectRect() applies the AABB overlap logic, verifying that no edge of one rectangle exists completely outside the corresponding edge of the other.
  • Event Dispatch: Upon detection, the eventEmitter broadcasts specific collision events without immediately modifying game state, maintaining separation between detection and response logic.
  • Object Lifecycle Management: The system flags destroyed objects and purges them from the global pool, ensuring computational efficiency in subsequent frames.

Practical Implementation Examples

Basic AABB Intersection Test

You can reuse the core collision logic independently of the game framework:

function intersectRect(r1, r2) {
  return !(
    r2.left > r1.right ||
    r2.right < r1.left ||
    r2.top > r1.bottom ||
    r2.bottom < r1.top
  );
}

// Example usage
const heroRect = { left: 50, top: 100, right: 149, bottom: 175 };
const enemyRect = { left: 120, top: 150, right: 218, bottom: 200 };
console.log(intersectRect(heroRect, enemyRect)); // true (overlap detected)

Integrating Collision Detection into the Game Loop

The collision system hooks into the main animation cycle through updateGameObjects:

function gameLoop() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  updateGameObjects();   // Collision detection executes here
  drawGameObjects(ctx);  // Render surviving entities
}

// Initialize 100ms interval
setInterval(gameLoop, 100);

Extending the System for New Object Types

To add power-up collisions, extend the message enum and collision logic:

// 1. Define new message type
const Messages = {
  COLLISION_ENEMY_HERO: 'COLLISION_ENEMY_HERO',
  COLLISION_ENEMY_LASER: 'COLLISION_ENEMY_LASER',
  COLLISION_HERO_POWERUP: 'COLLISION_HERO_POWERUP',
};

// 2. Add collision check in updateGameObjects
const powerUps = gameObjects.filter(go => go.type === 'PowerUp');
powerUps.forEach(pu => {
  if (intersectRect(pu.rectFromGameObject(), hero.rectFromGameObject())) {
    eventEmitter.emit(Messages.COLLISION_HERO_POWERUP, { powerUp: pu });
  }
});

// 3. Register handler in initGame()
eventEmitter.on(Messages.COLLISION_HERO_POWERUP, (_, { powerUp }) => {
  powerUp.dead = true;
  hero.points += 500;
});

Summary

  • The space game canvas collision detection algorithm relies on axis-aligned bounding box (AABB) intersection tests to detect overlaps between rectangular game entities.
  • The intersectRect function at lines 126-128 implements the separating axis theorem through simple edge comparisons, returning true only when rectangles overlap on both X and Y axes.
  • rectFromGameObject converts entity positions and dimensions into geometric bounds at lines 36-43, ensuring consistent rectangle representation across all sprite types.
  • updateGameObjects orchestrates collision detection at lines 206-229 by filtering game entities, executing pairwise AABB tests, emitting collision events, and purging destroyed objects from the global pool.
  • The event-driven architecture decouples collision detection from game logic, allowing developers to extend the system with new collision types without modifying the core geometric algorithms.

Frequently Asked Questions

What type of collision detection does the space game use?

The space game uses axis-aligned bounding box (AABB) collision detection, which treats every sprite as a non-rotated rectangle defined by its top, left, right, and bottom edges. This geometric approach uses the intersectRect function to check for overlaps by comparing the relative positions of these edges, making it computationally efficient for 2D canvas games where objects remain parallel to the screen boundaries.

How does the intersectRect function determine if two objects collide?

The intersectRect function applies the separating axis theorem by checking four conditions: whether rectangle B's left edge is to the right of rectangle A's right edge, B's right edge is to the left of A's left edge, B's top is below A's bottom, or B's bottom is above A's top. If any of these separating conditions are true, the rectangles do not overlap and the function returns false; otherwise, it returns true indicating a collision has occurred.

Can this collision algorithm handle rotated objects?

No, the AABB algorithm used in this space game cannot accurately detect collisions for rotated objects because it assumes all rectangles remain axis-aligned (parallel to the canvas edges). If sprites rotate, the bounding boxes would need to be recalculated as oriented bounding boxes (OBB) or use polygon collision detection, requiring replacement of the simple intersectRect logic with trigonometric calculations to account for rotation angles.

How do I add new collision types to the space game?

To add new collision types, first define a new message constant in the Messages object (e.g., COLLISION_HERO_POWERUP), then add a collision check inside updateGameObjects that filters for the new object type and calls intersectRect against the hero or other entities. Finally, register an event handler using eventEmitter.on() to manage the game logic consequences, such as updating scores or marking objects as dead, without modifying the core geometric algorithm in intersectRect.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →