Irongame

HTML5 Canvas Survival Game

The Challenge

I developed a complete survival game from scratch using HTML5 Canvas, vanilla JavaScript and CSS3. The game implements a complex collision system, sprite animations, dynamic life system, enemies with directional movement, and directional shooting mechanics with trigonometric calculations.

Tech Stack

Frontend

HTML5 Canvas
JavaScript Vanilla
CSS3
Canvas API
Web Audio API
Sprite Animation
Collision Detection
Game Loop
Vector Math
Trigonometry

Technical Challenges Overcome

Complex Collision System

Challenge:

Implement collision detection between multiple elements (player, enemies, bullets, bonuses) with different sizes and speeds in real time.

Solution:

I created specific functions for each type of collision using rectangular coordinates and precise mathematical calculations to detect intersections between game elements.

Result:

Robust system that handles real-time collisions between 6+ different types of elements without detection errors.

Enemy Movement System

Challenge:

Create enemies that move towards the player smoothly and naturally using mathematical calculations.

Solution:

I implemented vector normalization algorithms and trigonometric calculations so enemies move directly towards the player with differentiated speeds.

Result:

Two types of enemies with different speeds (PythonEnemy: 1, OctoEnemy: 2.5) that pursue the player smoothly using normalized vectors.

Sprite Animation System

Challenge:

Create fluid animations for all game elements using sprites with different frame counts and synchronization.

Solution:

I developed a frame-based animation system that synchronizes all animations with the main game loop at 60 FPS using frame indices.

Result:

Synchronized animations for player (4 frames), enemies (5-7 frames), bullets (3 frames) and bonuses (4 frames) that work perfectly.

Game Loop Optimization

Challenge:

Create an efficient game loop that handles rendering, logic, collisions and audio without affecting performance.

Solution:

I implemented an optimized game loop with setInterval that executes all game operations every 20ms (50 FPS) with efficient memory management.

Result:

Smooth game that maintains 60 FPS animation with efficient resource management and no memory leaks.

Featured Functionalities

Directional Shooting System

Allows the player to shoot in any direction by clicking on the canvas, automatically calculating the angle and trajectory of the bullet using trigonometry (atan2, cos, sin).

Dynamic Life System

Visual life bar that changes in real time according to damage received, with predefined images representing different health levels of the player (0%, 20%, 40%, 60%, 80%, 100%).

Complete Audio System

Integration of sound effects for shots and background music with volume control (0.2) and automatic loop to enhance the player experience.

Timer System

30-second countdown that controls the game duration and automatically activates the victory screen when time is completed, with 2-digit visual format.

Game State Management

Complete state system that handles start, active game, game over and victory with specific screens, result images and restart functionality.

Sprite Management

Complete system for loading and rendering sprites with different frame counts, synchronized animation and efficient memory management for all visual elements.

Project Results

1 week
Development Time
10
JavaScript Files
6 types
Game Elements
4
Collision Types
60 FPS
Frames per Second
30 seconds
Game Duration
23 total
Animation Frames

Featured Code

Collision System with Mathematical Calculations

Robust collision detection system that handles 4 different types of interactions between game elements using precise mathematical calculations.

// Collision detection system
function checkCollision(obj1, obj2) {
  const dx = obj1.x - obj2.x;
  const dy = obj1.y - obj2.y;
  const distance = Math.sqrt(dx * dx + dy * dy);
  return distance < (obj1.radius + obj2.radius);
}

// Specific collision for bullets with enemies
function checkBulletEnemyCollision(bullet, enemy) {
  if (checkCollision(bullet, enemy)) {
    enemy.health -= bullet.damage;
    bullet.destroy = true;
    return true;
  }
  return false;
}

// Player collision with bonuses
function checkPlayerBonusCollision(player, bonus) {
  if (checkCollision(player, bonus)) {
    player.health = Math.min(100, player.health + bonus.healAmount);
    bonus.destroy = true;
    return true;
  }
  return false;
}

Enemy Movement System with Vectors

Directional movement system that makes enemies pursue the player using normalized vectors and differentiated speeds.

// Enemy movement towards player
class Enemy {
  constructor(x, y, speed, type) {
    this.x = x;
    this.y = y;
    this.speed = speed;
    this.type = type;
  }
  
  update(player) {
    // Calculate direction towards player
    const dx = player.x - this.x;
    const dy = player.y - this.y;
    const distance = Math.sqrt(dx * dx + dy * dy);
    
    // Normalize vector and apply speed
    if (distance > 0) {
      this.x += (dx / distance) * this.speed;
      this.y += (dy / distance) * this.speed;
    }
  }
}

// Create enemies with different speeds
const pythonEnemy = new Enemy(x, y, 1, 'python');
const octoEnemy = new Enemy(x, y, 2.5, 'octopus');

Directional Shooting System with Trigonometry

Shooting system that automatically calculates bullet direction and trajectory using trigonometry (atan2, cos, sin) based on mouse click position.

// Directional shooting system
class Bullet {
  constructor(x, y, targetX, targetY, speed) {
    this.x = x;
    this.y = y;
    this.speed = speed;
    
    // Calculate angle towards target
    const dx = targetX - x;
    const dy = targetY - y;
    this.angle = Math.atan2(dy, dx);
  }
  
  update() {
    // Move bullet using trigonometry
    this.x += Math.cos(this.angle) * this.speed;
    this.y += Math.sin(this.angle) * this.speed;
  }
}

// Handle mouse click to shoot
canvas.addEventListener('click', (e) => {
  const rect = canvas.getBoundingClientRect();
  const targetX = e.clientX - rect.left;
  const targetY = e.clientY - rect.top;
  
  const bullet = new Bullet(player.x, player.y, targetX, targetY, 5);
  bullets.push(bullet);
});
Cristian Perdomo - Desarrollador Full Stack