about summary refs log tree commit diff stats
path: root/html
diff options
context:
space:
mode:
Diffstat (limited to 'html')
-rw-r--r--html/tower/js/game.js101
1 files changed, 83 insertions, 18 deletions
diff --git a/html/tower/js/game.js b/html/tower/js/game.js
index 57eaa3a..5c39b8b 100644
--- a/html/tower/js/game.js
+++ b/html/tower/js/game.js
@@ -1,37 +1,70 @@
+/** Canvas elements for rendering the game */
 const canvas = document.getElementById('gameCanvas');
 const ctx = canvas.getContext('2d');
 
+/** Game timing variables */
 let lastTimestamp = 0;
-const ENEMY_SPAWN_INTERVAL = 1000; // 1 second
+const ENEMY_SPAWN_INTERVAL = 1000; // 1 second between enemy spawns
 let lastEnemySpawn = 0;
 let enemiesRemaining = 0;
 
+/** Drag and drop state tracking */
 let draggedTowerType = null;
 let hoverCell = null;
 
+/**
+ * Main game loop using requestAnimationFrame
+ * This is the heart of the game, running approximately 60 times per second
+ * 
+ * @param {number} timestamp - Current time in milliseconds, provided by requestAnimationFrame
+ * 
+ * Key concepts:
+ * - RequestAnimationFrame for smooth animation
+ * - Delta time for consistent motion regardless of frame rate
+ * - Game state management
+ */
 function gameLoop(timestamp) {
+    // Calculate time since last frame for consistent motion
     const deltaTime = timestamp - lastTimestamp;
     lastTimestamp = timestamp;
     
+    // Clear the canvas for the next frame
     ctx.clearRect(0, 0, canvas.width, canvas.height);
     
+    // Update game state based on current phase
     if (gameState.phase === GamePhase.COMBAT) {
         handleCombatPhase(timestamp, deltaTime);
     }
     
+    // Render the current game state
     renderGame();
+    // Schedule the next frame
     requestAnimationFrame(gameLoop);
 }
 
+/**
+ * Handles all combat phase updates including enemy movement, attacks, and collisions
+ * 
+ * @param {number} timestamp - Current game time in milliseconds
+ * @param {number} deltaTime - Time elapsed since last frame
+ * 
+ * Key concepts:
+ * - Game state updates
+ * - Entity management (enemies, towers, projectiles)
+ * - Particle effects
+ * - Combat mechanics
+ */
 function handleCombatPhase(timestamp, deltaTime) {
     spawnEnemies(timestamp);
     updateEnemies();
+    // Update particle effects with time-based animation
     gameState.particles = updateParticles(gameState.particles, timestamp, deltaTime);
+    // Remove expired projectiles
     gameState.projectiles = gameState.projectiles.filter(p => timestamp - p.createdAt < p.lifetime);
     
     const cellSize = canvas.width / 20;
     
-    // Process tower and enemy attacks
+    // Process combat interactions
     processTowerAttacks(
         gameState.towers,
         gameState.enemies,
@@ -49,7 +82,8 @@ function handleCombatPhase(timestamp, deltaTime) {
         cellSize
     );
     
-    // Remove dead enemies and destroyed towers
+    // Remove defeated enemies and destroyed towers
+    // Uses array filter with a callback that has side effects (awarding currency)
     gameState.enemies = gameState.enemies.filter(enemy => {
         if (enemy.currentHealth <= 0) {
             gameState.awardEnemyDestroyed();
@@ -60,6 +94,16 @@ function handleCombatPhase(timestamp, deltaTime) {
     gameState.towers = gameState.towers.filter(tower => tower.currentHealth > 0);
 }
 
+/**
+ * Spawns new enemies at regular intervals during combat
+ * 
+ * @param {number} timestamp - Current game time in milliseconds
+ * 
+ * Key concepts:
+ * - Time-based game events
+ * - Enemy creation and management
+ * - Game balance through spawn timing
+ */
 function spawnEnemies(timestamp) {
     if (enemiesRemaining > 0 && timestamp - lastEnemySpawn > ENEMY_SPAWN_INTERVAL) {
         gameState.enemies.push(createEnemy({ x: 0, y: gameState.path[0].y }));
@@ -68,13 +112,21 @@ function spawnEnemies(timestamp) {
     }
 }
 
+/**
+ * Renders all game elements to the canvas
+ * 
+ * Key concepts:
+ * - Layer-based rendering
+ * - Canvas drawing order (background to foreground)
+ * - Separation of rendering and game logic
+ */
 function renderGame() {
-    renderGrid(ctx, gameState.grid);
-    renderProjectiles(ctx, gameState.projectiles);
-    renderEnemies(ctx, gameState.enemies);
-    renderTowers(ctx, gameState.towers);
-    renderParticles(ctx, gameState.particles);
-    renderUI(ctx, gameState);
+    renderGrid(ctx, gameState.grid);        // Background grid
+    renderProjectiles(ctx, gameState.projectiles); // Projectiles
+    renderEnemies(ctx, gameState.enemies);   // Enemies
+    renderTowers(ctx, gameState.towers);     // Towers
+    renderParticles(ctx, gameState.particles); // Visual effects
+    renderUI(ctx, gameState);                // User interface
 }
 
 // Start the game
@@ -99,13 +151,22 @@ function startCombat() {
     }
 }
 
-// Add event listeners for tower placement
+/**
+ * Sets up all event listeners for user interaction
+ * 
+ * Key concepts:
+ * - Event-driven programming
+ * - HTML5 Drag and Drop API
+ * - DOM manipulation
+ * - Method decoration (towers.push)
+ */
 function initializeEventListeners() {
-    // Tower palette drag events
+    // Set up tower palette drag events
     document.querySelectorAll('.tower-option').forEach(option => {
         option.addEventListener('dragstart', (e) => {
             draggedTowerType = e.target.dataset.towerType;
-            e.dataTransfer.setData('text/plain', ''); // Required for Firefox
+            // Required for Firefox - must set data for drag operation
+            e.dataTransfer.setData('text/plain', '');
         });
         
         option.addEventListener('dragend', () => {
@@ -114,13 +175,15 @@ function initializeEventListeners() {
         });
     });
 
-    // Canvas drag events
+    // Set up canvas drag and drop handling
     canvas.addEventListener('dragover', (e) => {
-        e.preventDefault();
+        e.preventDefault(); // Required for drop to work
         const rect = canvas.getBoundingClientRect();
+        // Convert mouse coordinates to grid coordinates
         const x = Math.floor((e.clientX - rect.left) / (canvas.width / 20));
         const y = Math.floor((e.clientY - rect.top) / (canvas.height / 20));
         
+        // Validate grid boundaries
         if (x >= 0 && x < 20 && y >= 0 && y < 20) {
             hoverCell = { x, y };
         } else {
@@ -132,11 +195,13 @@ function initializeEventListeners() {
         hoverCell = null;
     });
 
+    // Handle tower placement on drop
     canvas.addEventListener('drop', (e) => {
         e.preventDefault();
         if (!draggedTowerType || !hoverCell) return;
 
         const tower = TowerTypes[draggedTowerType];
+        // Validate placement and currency
         if (
             gameState.grid[hoverCell.y][hoverCell.x] === 'empty' &&
             gameState.currency >= tower.cost
@@ -146,20 +211,21 @@ function initializeEventListeners() {
             gameState.currency -= tower.cost;
         }
         
+        // Reset drag state
         draggedTowerType = null;
         hoverCell = null;
     });
 
-    // Replace the space key event with button click
+    // Combat phase transition
     document.getElementById('startCombat').addEventListener('click', startCombat);
     
-    // Update button state when towers are placed
+    // Dynamic button state management
     const updateStartButton = () => {
         const button = document.getElementById('startCombat');
         button.disabled = gameState.towers.length === 0;
     };
     
-    // Add tower placement observer
+    // Decorator pattern: Enhance towers.push to update UI
     const originalPush = gameState.towers.push;
     gameState.towers.push = function(...args) {
         const result = originalPush.apply(this, args);
@@ -167,6 +233,5 @@ function initializeEventListeners() {
         return result;
     };
     
-    // Initial button state
     updateStartButton();
 } 
\ No newline at end of file