Game Engine Code Snippets by Topic

1. Transition Screens

Victory Screen Implementation

The victory screen system handles game completion with proper state management and visual feedback.

// Enhanced method to handle victory
handleVictory() {
  console.log('handleVictory called with hitCount:', this.fireballHitCount);
  
  // Prevent multiple victory screens
  if (this.victoryTriggered) {
    console.log('Victory already triggered, ignoring');
    return;
  }
  
  this.victoryTriggered = true;
  
  // Remove any existing victory screen
  const existingVictory = document.getElementById('victory-screen');
  if (existingVictory) {
    existingVictory.remove();
  }
  
  this.showVictoryScreen();
  
  setTimeout(() => {
    location.reload();
  }, 3000);
}
// Enhanced method to display victory screen
showVictoryScreen() {
  console.log('Showing victory screen');
  
  const victoryDiv = document.createElement('div');
  victoryDiv.id = 'victory-screen';
  victoryDiv.style.cssText = `
    position: fixed !important; 
    top: 0 !important; 
    left: 0 !important; 
    width: 100% !important; 
    height: 100% !important;
    background-color: rgba(0, 50, 0, 0.95) !important; 
    display: flex !important; 
    flex-direction: column !important;
    justify-content: center !important; 
    align-items: center !important; 
    z-index: 99999 !important;
    color: #00FF00 !important; 
    font-size: 48px !important; 
    font-family: Arial, sans-serif !important;
    text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8) !important;
    pointer-events: auto !important;
  `;
  victoryDiv.innerHTML = `
    <div>🎉 VICTORY! 🎉</div>
    <div style="font-size: 32px; margin-top: 20px;">You defeated the Ghast!</div>
    <div style="font-size: 24px; margin-top: 10px;">Fireballs Hit Back: ${this.fireballHitCount}/2</div>
    <div style="font-size: 18px; margin-top: 20px;">Restarting in 3 seconds...</div>
  `;
  
  // Ensure it's added to the body and visible
  document.body.appendChild(victoryDiv);
  
  // Force visibility
  setTimeout(() => {
    victoryDiv.style.display = 'flex';
  }, 10);
  
  console.log('Victory screen added to DOM');
}

Game Over Screen

Simple game over implementation with automatic restart functionality.

handleGameOver: function() {
  this.showGameOverScreen();
  setTimeout(() => {
    location.reload();
  }, 3000);
},

showGameOverScreen: function() {
  const gameOverDiv = document.createElement('div');
  gameOverDiv.id = 'game-over-screen';
  gameOverDiv.style.cssText = `
    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
    background-color: rgba(0, 0, 0, 0.8); display: flex; flex-direction: column;
    justify-content: center; align-items: center; z-index: 10000;
    color: #FF0000; font-size: 48px; font-family: Arial, sans-serif;
  `;
  gameOverDiv.innerHTML = `
    <div>GAME OVER</div>
    <div style="font-size: 24px; margin-top: 20px;">Restarting in 3 seconds...</div>
  `;
  document.body.appendChild(gameOverDiv);
}

2. Enemy System

Ghast Enemy Configuration

Complete enemy configuration with health, animations, and behavior patterns.

const sprite_data_ghast = {
  id: 'Ghast',
  down: { row: 0, start: 0, columns: 4 },
  greeting: "ROOOOOAAAAAR! *shoots fireballs*",
  src: sprite_src_ghast,
  SCALE_FACTOR: GHAST_SCALE_FACTOR,
  ANIMATION_RATE: 100,
  pixels: { width: 256, height: 256 },
  INIT_POSITION: { x: width - 300, y: 100 },
  orientation: { rows: 2, columns: 4 },
  idle: { row: 0, start: 0, columns: 4 },
  shooting: { row: 1, start: 0, columns: 4 },
  hitbox: { widthPercentage: 0.8, heightPercentage: 0.8 },
  health: 150,
  fireballCooldown: 0,
  fireballRate: 120,
  isEnemy: true,
  
  gameEnv: gameEnv,
  lastFireballTime: 0,
  
  reaction: function () {
    this.health -= 30;
    console.log('Ghast health:', this.health);
    if (this.health <= 0) {
      console.log('Ghast destroyed!');
      if (this.parent && this.gameEnv && this.gameEnv.gameObjects) {
        const index = this.gameEnv.gameObjects.indexOf(this.parent);
        if (index > -1) {
          this.gameEnv.gameObjects.splice(index, 1);
        }
      }
      // Trigger victory when ghast is destroyed
      if (gameLevel) {
        console.log('Calling handleVictory from ghast destruction');
        gameLevel.handleVictory();
      }
    }
  }
};

Enemy Behavior Update System

AI behavior system with distance-based attack patterns and cooldown management.

npcInstance.updateGhastBehavior = function() {
  if (this.spriteData.fireballCooldown > 0) {
    this.spriteData.fireballCooldown--;
  }

  const players = this.gameEnv.gameObjects.filter(obj =>
    obj.constructor.name === 'Player' && obj.spriteData.id === 'Steve'
  );

  if (players.length === 0) return;
  
  const player = players[0];
  if (!player.position || !this.position) return;
  
  const dx = player.position.x - this.position.x;
  const dy = player.position.y - this.position.y;
  const distance = Math.sqrt(dx * dx + dy * dy);

  if (this.spriteData.fireballCooldown <= 0 && distance < 600) {
    this.shootFireball(player);
    this.spriteData.fireballCooldown = this.spriteData.fireballRate;
    this.direction = 'shooting';
  } else {
    this.direction = 'idle';
  }
};

3. Blocks and Environmental Hazards

Lava Block Hazard

Environmental hazard implementation with damage and visual effects.

const sprite_data_lava = {
  id: 'Lava-Pool',
  src: sprite_src_lava,
  SCALE_FACTOR: 8,
  ANIMATION_RATE: 75,
  pixels: { width: 128, height: 64 },
  INIT_POSITION: { x: width / 2, y: height - 100 },
  orientation: { rows: 1, columns: 8 },
  down: { row: 0, start: 0, columns: 8 },
  hitbox: { widthPercentage: 0.9, heightPercentage: 0.5 },
  damage: 15,
  reaction: function () {
    // Damage reaction could be implemented here
  }
};

4. Canvas and Game Object Management APIs

Canvas Management API

Dynamic canvas creation and management for rendering game elements.

// Canvas creation and management
this.canvas = document.createElement('canvas');
this.canvas.width = gameEnv.innerWidth;
this.canvas.height = gameEnv.innerHeight;
this.canvas.style.position = 'absolute';
this.canvas.style.top = '0';
this.canvas.style.left = '0';
this.canvas.style.pointerEvents = 'none';
this.canvas.style.zIndex = '10';
this.canvas.id = `fireball-canvas-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
this.ctx = this.canvas.getContext('2d');

// Add canvas to game container
if (gameEnv.gameContainer) {
  gameEnv.gameContainer.appendChild(this.canvas);
} else {
  document.getElementById('gameContainer')?.appendChild(this.canvas);
}

Game Object Management API

Comprehensive cleanup system for managing game objects and preventing memory leaks.

clearGameObjects(gameEnv) {
  if (gameEnv && gameEnv.gameObjects) {
    const objectsToRemove = [...gameEnv.gameObjects];
    
    objectsToRemove.forEach(obj => {
      try {
        if (obj && typeof obj.destroy === 'function') {
          obj.destroy();
        }
        
        if (obj && obj.element && obj.element.parentNode) {
          if (obj.element.tagName !== 'CANVAS') {
            obj.element.parentNode.removeChild(obj.element);
          }
        }
        
        if (obj.intervalId) {
          clearInterval(obj.intervalId);
        }
        
        if (obj.timeoutId) {
          clearTimeout(obj.timeoutId);
        }
        
      } catch (error) {
        console.warn('Error cleaning up object:', error);
      }
    });
    
    gameEnv.gameObjects.length = 0;
  }
}

5. Animation Systems

Enemy Animation State System

Multi-state animation system for enemy behaviors.

const sprite_data_ghast = {
  // Animation configurations
  orientation: { rows: 2, columns: 4 },
  idle: { row: 0, start: 0, columns: 4 },
  shooting: { row: 1, start: 0, columns: 4 },
  ANIMATION_RATE: 100,
  
  // Animation state management in behavior update
  updateGhastBehavior: function() {
    // ... distance and cooldown logic ...
    
    if (this.spriteData.fireballCooldown <= 0 && distance < 600) {
      this.shootFireball(player);
      this.spriteData.fireballCooldown = this.spriteData.fireballRate;
      this.direction = 'shooting'; // Switch to shooting animation
    } else {
      this.direction = 'idle'; // Switch to idle animation
    }
  }
};

Player Animation States

8-directional player animation system with rotation support.

const sprite_data_steve = {
  orientation: {rows: 8, columns: 4 },
  down: {row: 1, start: 0, columns: 4 },
  downRight: {row: 7, start: 0, columns: 4, rotate: Math.PI/8 },
  downLeft: {row: 5, start: 0, columns: 4, rotate: -Math.PI/8 },
  left: {row: 5, start: 0, columns: 4 },
  right: {row: 7, start: 0, columns: 4 },
  up: {row: 3, start: 0, columns: 4 },
  upLeft: {row: 5, start: 0, columns: 4, rotate: Math.PI/8 },
  upRight: {row: 7, start: 0, columns: 4, rotate: -Math.PI/8 },
  ANIMATION_RATE: 25,
};

6. Dialogue and Interaction Systems

NPC Dialogue Configuration

Interactive dialogue system with portal and item interactions.

const sprite_data_portal = {
  id: 'Nether-Portal',
  greeting: "Return to the Desert?",
  dialogues: [
    "The portal shimmers with otherworldly energy.",
    "You can return to the Desert through this portal.",
    "The familiar world awaits beyond this threshold."
  ],
  interact: function () {
    const confirmReturn = confirm("Return to the Desert? (This will end the Nether challenge)");
    if (confirmReturn) {
      if (gameEnv && gameEnv.gameControl) {
        this.cleanupNetherLevel();
        gameEnv.gameControl.goToLevel("Desert");
      }
    }
  }
};

const sprite_data_potion = {
  id: 'Health-Potion',
  greeting: "Health Potion - restores 50 HP",
  // Interaction through collision/pickup system
};

7. Combat and Interaction Systems

Player Attack System

Comprehensive attack system with fireball deflection mechanics.

const sprite_data_steve = {
  canHitFireballs: true,
  isAttacking: false,
  attackCooldown: 0,
  
  handleAttack: function() {
    console.log('handleAttack called, cooldown:', this.attackCooldown);
    if (this.attackCooldown <= 0) {
      this.isAttacking = true;
      this.attackCooldown = 20;
      
      // Call checkFireballHit with proper context
      this.checkFireballHit.call(this);
      
      setTimeout(() => {
        this.isAttacking = false;
      }, 300);
    }
  },
  
  checkFireballHit: function() {
    console.log('checkFireballHit called');
    if (!this.gameEnv || !this.gameEnv.gameObjects) {
      console.log('No gameEnv or gameObjects');
      return;
    }
    
    const playerPos = this.parent ? this.parent.position : null;
    if (!playerPos) {
      console.log('No player position');
      return;
    }
    
    const fireballs = this.gameEnv.gameObjects.filter(obj => 
      obj instanceof GhastFireball && 
      obj.spriteData && 
      obj.spriteData.canBeHitBack &&
      obj.spriteData.damagePlayer === true
    );
    
    console.log('Found fireballs:', fireballs.length);
    
    for (let fireball of fireballs) {
      if (!fireball.position) continue;
      
      const dx = fireball.position.x - playerPos.x;
      const dy = fireball.position.y - playerPos.y;
      const distance = Math.sqrt(dx * dx + dy * dy);
      
      console.log('Fireball distance:', distance);
      
      if (distance < 80) {
        console.log('Fireball hit! Distance:', distance);
        
        const ghasts = this.gameEnv.gameObjects.filter(obj =>
          obj.spriteData && obj.spriteData.id === 'Ghast'
        );
        
        if (ghasts.length > 0) {
          fireball.reverseDirection(ghasts[0]);
          
          // Increment hit count and check for win condition
          if (this.gameLevel) {
            this.gameLevel.fireballHitCount++;
            console.log('Hit count increased to:', this.gameLevel.fireballHitCount);
            
            if (this.gameLevel.fireballHitCount >= 2) {
              console.log('Victory condition met!');
              this.gameLevel.handleVictory();
            }
          }
        }
        break;
      }
    }
  }
};

Damage System

Health management and game over mechanics for both players and enemies.

// Player damage reaction
reaction: function () {
  if (this.health > 0) {
    this.health -= 20;
    if (this.health <= 0) {
      this.handleGameOver();
    }
  }
},

// Enemy damage and destruction
reaction: function () {
  this.health -= 30;
  console.log('Ghast health:', this.health);
  if (this.health <= 0) {
    console.log('Ghast destroyed!');
    if (this.parent && this.gameEnv && this.gameEnv.gameObjects) {
      const index = this.gameEnv.gameObjects.indexOf(this.parent);
      if (index > -1) {
        this.gameEnv.gameObjects.splice(index, 1);
      }
    }
    // Trigger victory when ghast is destroyed
    if (gameLevel) {
      gameLevel.handleVictory();
    }
  }
}

8. Projectile Systems

Fireball Projectile Class

Complete projectile implementation with homing behavior and collision detection.

class GhastFireball {
  constructor(x, y, target, gameEnv, speed = 3, turnRate = 0.06) {
    this.gameEnv = gameEnv;
    this.target = target;
    this.speed = speed;
    this.turnRate = turnRate;
    this.radius = 15;
    this.baseRadius = 15;
    this.color = "#FF4500"; // Orange-red fireball color
    this.active = true;
    this.exploding = false;
    this.impactFrames = 0;
    this.maxImpactFrames = 45;
    
    this.position = { x: x, y: y };

    // Add sprite data for compatibility with game engine
    this.spriteData = {
      id: 'Ghast-Fireball',
      canBeHitBack: true,
      damagePlayer: true,
      damageGhast: false,
      hitBackSpeed: 6
    };

    // Calculate initial velocity toward target
    const dx = target.position.x - x;
    const dy = target.position.y - y;
    const angle = Math.atan2(dy, dx);
    this.velocity = {
      x: Math.cos(angle) * speed,
      y: Math.sin(angle) * speed
    };
  }
}

Homing Projectile Behavior

Advanced AI targeting system with gradual turning and collision detection.

update() {
  // ... validation code ...
  
  // Calculate distance to target
  const dx = this.target.position.x - this.position.x;
  const dy = this.target.position.y - this.position.y;
  const distance = Math.sqrt(dx * dx + dy * dy);

  // Check for collision with target (player)
  const collisionDistance = this.radius + (this.target.size?.width || 30) / 2;
  if (distance < collisionDistance) {
    console.log('💥 Direct hit on player!');
    this.explode();
    this.damagePlayer();
    return;
  }

  // Homing behavior - adjust velocity toward target
  if (this.spriteData.damagePlayer) {
    const targetAngle = Math.atan2(dy, dx);
    const currentAngle = Math.atan2(this.velocity.y, this.velocity.x);
    
    // Calculate angle difference and normalize
    let angleDiff = targetAngle - currentAngle;
    while (angleDiff > Math.PI) angleDiff -= 2 * Math.PI;
    while (angleDiff < -Math.PI) angleDiff += 2 * Math.PI;

    // Apply gradual turning
    const newAngle = currentAngle + this.turnRate * angleDiff;
    this.velocity.x = Math.cos(newAngle) * this.speed;
    this.velocity.y = Math.sin(newAngle) * this.speed;
  }

  // Update position
  this.position.x += this.velocity.x;
  this.position.y += this.velocity.y;
}

Projectile Reversal Mechanic

Fireball deflection system that changes target and visual properties.

// Method to reverse fireball direction (for hitting back)
reverseDirection(newTarget) {
  if (!newTarget || !newTarget.position) return;

  this.target = newTarget;
  
  // Calculate new direction
  const dx = newTarget.position.x - this.position.x;
  const dy = newTarget.position.y - this.position.y;
  const distance = Math.sqrt(dx * dx + dy * dy);
  
  if (distance > 0) {
    const newSpeed = this.spriteData.hitBackSpeed || 6;
    this.velocity.x = (dx / distance) * newSpeed;
    this.velocity.y = (dy / distance) * newSpeed;
    this.speed = newSpeed;
    
    // Change damage properties
    this.spriteData.damagePlayer = false;
    this.spriteData.damageGhast = true;
    
    // Visual feedback - change color slightly
    this.color = "#4169E1"; // Royal blue when hit back
    
    console.log("🔄 Fireball reversed direction!");
  }
}

9. Visual Effects and Particle Systems

Particle System for Fireballs

Trail and particle effects for enhanced visual feedback.

// Fireball trail effect
this.trail = [];
this.maxTrailLength = 8;

// Particle effects
this.particles = [];
this.maxParticles = 6;

updateTrail() {
  // Add current position to trail
  this.trail.unshift({ 
    x: this.position.x, 
    y: this.position.y,
    alpha: 1.0
  });
  
  // Remove old trail points
  if (this.trail.length > this.maxTrailLength) {
    this.trail.pop();
  }
  
  // Fade trail points
  this.trail.forEach((point, index) => {
    point.alpha = 1.0 - (index / this.maxTrailLength);
  });
}

updateParticles() {
  // Add new particles
  if (this.particles.length < this.maxParticles) {
    this.particles.push({
      x: this.position.x + (Math.random() - 0.5) * 10,
      y: this.position.y + (Math.random() - 0.5) * 10,
      vx: (Math.random() - 0.5) * 2,
      vy: (Math.random() - 0.5) * 2,
      life: 1.0,
      decay: 0.05 + Math.random() * 0.05
    });
  }
  
  // Update existing particles
  this.particles = this.particles.filter(particle => {
    particle.x += particle.vx;
    particle.y += particle.vy;
    particle.life -= particle.decay;
    return particle.life > 0;
  });
}

Visual Effects Rendering

Advanced rendering with gradients, pulsing effects, and layered visuals.

drawFireball(ctx) {
  // Pulsing effect while moving
  const time = Date.now();
  const pulse = Math.sin(time / 80) * 3;
  const drawRadius = this.baseRadius + pulse;

  // Outer glow
  const gradient = ctx.createRadialGradient(
    this.position.x, this.position.y, 0,
    this.position.x, this.position.y, drawRadius + 10
  );
  gradient.addColorStop(0, 'rgba(255, 255, 100, 0.8)');
  gradient.addColorStop(0.4, 'rgba(255, 69, 0, 0.6)');
  gradient.addColorStop(1, 'rgba(255, 0, 0, 0.1)');

  ctx.beginPath();
  ctx.arc(this.position.x, this.position.y, drawRadius + 10, 0, Math.PI * 2);
  ctx.fillStyle = gradient;
  ctx.fill();

  // Main fireball body
  ctx.beginPath();
  ctx.arc(this.position.x, this.position.y, drawRadius, 0, Math.PI * 2);
  ctx.fillStyle = this.color;
  ctx.fill();

  // Inner core
  ctx.beginPath();
  ctx.arc(this.position.x, this.position.y, drawRadius * 0.6, 0, Math.PI * 2);
  ctx.fillStyle = '#FFFF00'; // Bright yellow core
  ctx.fill();

  // Hot white center
  ctx.beginPath();
  ctx.arc(this.position.x, this.position.y, drawRadius * 0.3, 0, Math.PI * 2);
  ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
  ctx.fill();
}

Explosion Effects

Multi-layered explosion animation with particle effects and fade-out.

drawExplosion(ctx) {
  const progress = this.impactFrames / this.maxImpactFrames;
  const alpha = 1 - progress;
  const explosionRadius = this.radius + this.impactFrames * 2;

  // Draw explosion particles first
  this.drawParticles(ctx);

  // Outer explosion ring
  ctx.beginPath();
  ctx.arc(this.position.x, this.position.y, explosionRadius, 0, Math.PI * 2);
  ctx.fillStyle = `rgba(255, 100, 0, ${alpha * 0.6})`;
  ctx.fill();

  // Middle ring
  ctx.beginPath();
  ctx.arc(this.position.x, this.position.y, explosionRadius * 0.7, 0, Math.PI * 2);
  ctx.fillStyle = `rgba(255, 150, 0, ${alpha * 0.8})`;
  ctx.fill();

  // Inner core
  ctx.beginPath();
  ctx.arc(this.position.x, this.position.y, explosionRadius * 0.4, 0, Math.PI * 2);
  ctx.fillStyle = `rgba(255, 255, 100, ${alpha})`;
  ctx.fill();

  // White hot center
  if (this.impactFrames < 20) {
    ctx.beginPath();
    ctx.arc(this.position.x, this.position.y, explosionRadius * 0.2, 0, Math.PI * 2);
    ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`;
    ctx.fill();
  }

  // Explosion outline
  ctx.beginPath();
  ctx.arc(this.position.x, this.position.y, explosionRadius, 0, Math.PI * 2);
  ctx.strokeStyle = `rgba(255, 255, 255, ${alpha * 0.8})`;
  ctx.lineWidth = 3;
  ctx.stroke();
}

Final Project Learning Connections

Each section of code demonstrates key computer science concepts required for the final project:

Software Engineering & Development Lifecycle Practices

  • Planning & Documentation: Extensive code comments and structured organization throughout all sections
  • Source Control: Modular code structure enabling easy forking, branching, and merging
  • Testing & Verification: Console logging and debug statements in victory/game over screens for troubleshooting
  • Code Reviews: Clear method separation and readable function names facilitate review processes

Data Types

  • Numbers: Health values (150, 30, 20), coordinates (x, y), animation rates (100, 25), and mathematical calculations
  • Strings: Entity IDs (‘Ghast’, ‘Steve’), CSS styling strings, and console messages
  • Booleans: State flags (victoryTriggered, isAttacking, canBeHitBack, active)
  • Arrays: Game object collections (gameObjects), trail points, and particle systems
  • JSON Objects: Sprite data configurations, position objects, and game state management

Operators

  • String Operations: Template literals for CSS styling and HTML content creation
  • Mathematical Operations: Distance calculations (Math.sqrt, dxdx + dydy), trigonometry (Math.atan2, Math.sin), and coordinate transformations
  • Boolean Expressions: Conditional checks (health <= 0, distance < 80, this.attackCooldown <= 0)

Control Structures

  • Iterations: forEach loops for object cleanup, filter operations for game object selection, and particle system updates
  • Conditions: Victory/defeat state management, collision detection, and animation state switching
  • Nested Conditions: Complex game logic combining health checks, distance calculations, and cooldown management

Input/Output

  • HTML5 Input: Key event handling for attack actions and movement
  • DOM Manipulation: Dynamic creation of victory/game over screens, canvas management, and element styling
  • Validation: Input validation for game state changes and collision detection

Classes & Object-Oriented Programming

  • Class Definition: GhastFireball class with constructor and methods
  • Method Creation: handleVictory(), checkFireballHit(), updateGhastBehavior() methods
  • Object Instantiation: Creating sprite data objects, canvas elements, and game entities
  • Method Calls: Calling reaction(), destroy(), and update() methods with proper parameters
  • Return Values: Distance calculations, collision detection results, and state validations

Coding Practices

  • Single Responsibility Principle (SRP): Each function handles one specific task (victory handling, collision detection, animation updates)
  • Object Literals: Sprite data configurations using object literal syntax with properties and methods
  • Object Instances: Creating specific instances of game entities with unique properties and behaviors
  • Finite State Machines (FSMs): Animation state management (idle, shooting, exploding) and game state transitions
  • Inheritance: Sprite data objects sharing common properties while maintaining unique characteristics