about summary refs log tree commit diff stats
path: root/html/tower/docs/renderer.js.html
diff options
context:
space:
mode:
Diffstat (limited to 'html/tower/docs/renderer.js.html')
-rw-r--r--html/tower/docs/renderer.js.html431
1 files changed, 431 insertions, 0 deletions
diff --git a/html/tower/docs/renderer.js.html b/html/tower/docs/renderer.js.html
new file mode 100644
index 0000000..ed49c44
--- /dev/null
+++ b/html/tower/docs/renderer.js.html
@@ -0,0 +1,431 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title>JSDoc: Source: renderer.js</title>
+
+    <script src="scripts/prettify/prettify.js"> </script>
+    <script src="scripts/prettify/lang-css.js"> </script>
+    <!--[if lt IE 9]>
+      <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
+    <![endif]-->
+    <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
+    <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
+</head>
+
+<body>
+
+<div id="main">
+
+    <h1 class="page-title">Source: renderer.js</h1>
+
+    
+
+
+
+    
+    <section>
+        <article>
+            <pre class="prettyprint source linenums"><code>/**
+ * Rendering Module
+ * 
+ * This module handles all game rendering operations using HTML5 Canvas.
+ * Demonstrates key game development patterns:
+ * 1. Layer-based rendering
+ * 2. Particle systems
+ * 3. Visual state feedback
+ * 4. Canvas state management
+ * 
+ * @module renderer
+ */
+
+/**
+ * Renders the game grid with path and hover previews
+ * Implements visual feedback for player actions
+ * 
+ * @param {CanvasRenderingContext2D} ctx - Canvas rendering context
+ * @param {Array&lt;Array&lt;string>>} grid - Game grid state
+ */
+function renderGrid(ctx, grid) {
+    const cellSize = canvas.width / 20;
+    
+    // Draw grid lines for visual reference
+    ctx.strokeStyle = '#ccc';
+    ctx.lineWidth = 1;
+    
+    for (let i = 0; i &lt;= 20; i++) {
+        // Vertical lines
+        ctx.beginPath();
+        ctx.moveTo(i * cellSize, 0);
+        ctx.lineTo(i * cellSize, canvas.height);
+        ctx.stroke();
+        
+        // Horizontal lines
+        ctx.beginPath();
+        ctx.moveTo(0, i * cellSize);
+        ctx.lineTo(canvas.width, i * cellSize);
+        ctx.stroke();
+    }
+    
+    // Render grid cells with path highlighting
+    grid.forEach((row, y) => {
+        row.forEach((cell, x) => {
+            if (cell === 'path') {
+                ctx.fillStyle = '#f4a460';
+                ctx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize);
+            }
+        });
+    });
+
+    // Render tower placement preview
+    if (gameState.phase === GamePhase.PLACEMENT &amp;&amp; draggedTowerType &amp;&amp; hoverCell) {
+        const tower = TowerTypes[draggedTowerType];
+        const canPlace = grid[hoverCell.y][hoverCell.x] === 'empty' &amp;&amp;
+                        gameState.playerCurrency >= tower.cost;
+        
+        // Visual feedback for placement validity
+        ctx.fillStyle = canPlace ? tower.color + '80' : 'rgba(255, 0, 0, 0.3)';
+        ctx.fillRect(
+            hoverCell.x * cellSize,
+            hoverCell.y * cellSize,
+            cellSize,
+            cellSize
+        );
+        
+        // Range indicator preview
+        ctx.beginPath();
+        ctx.arc(
+            (hoverCell.x + 0.5) * cellSize,
+            (hoverCell.y + 0.5) * cellSize,
+            tower.range * cellSize,
+            0,
+            Math.PI * 2
+        );
+        ctx.strokeStyle = canPlace ? tower.color + '40' : 'rgba(255, 0, 0, 0.2)';
+        ctx.stroke();
+    }
+}
+
+/**
+ * Renders all enemies with health indicators and effects
+ * Implements visual state representation
+ * 
+ * @param {CanvasRenderingContext2D} ctx - Canvas rendering context
+ * @param {Array&lt;Object>} enemies - Array of enemy objects
+ */
+function renderEnemies(ctx, enemies) {
+    const cellSize = canvas.width / 20;
+    
+    enemies.forEach(enemy => {
+        // Health-based opacity for visual feedback
+        const healthPercent = enemy.currentHealth / enemy.maxHealth;
+        const opacity = 0.3 + (healthPercent * 0.7);
+        
+        // Dynamic color based on enemy state
+        const color = EnemyTypes[enemy.type].color;
+        const hexOpacity = Math.floor(opacity * 255).toString(16).padStart(2, '0');
+        
+        // Draw enemy body with solid black border
+        ctx.beginPath();
+        ctx.arc(
+            (enemy.position.x + 0.5) * cellSize,
+            (enemy.position.y + 0.5) * cellSize,
+            cellSize / 3,
+            0,
+            Math.PI * 2
+        );
+        
+        // Fill with dynamic opacity
+        ctx.fillStyle = `${color}${hexOpacity}`;
+        ctx.fill();
+        
+        // Add solid black border
+        ctx.strokeStyle = 'black';
+        ctx.lineWidth = 2;
+        ctx.stroke();
+        
+        // Range indicator for special enemy types
+        if (EnemyTypes[enemy.type].isRanged) {
+            ctx.beginPath();
+            ctx.arc(
+                (enemy.position.x + 0.5) * cellSize,
+                (enemy.position.y + 0.5) * cellSize,
+                EnemyTypes[enemy.type].attackRange * cellSize,
+                0,
+                Math.PI * 2
+            );
+            ctx.strokeStyle = `${EnemyTypes[enemy.type].color}40`;
+            ctx.stroke();
+        }
+    });
+}
+
+/**
+ * Renders game UI elements with clean state management
+ * Implements heads-up display (HUD) pattern
+ * 
+ * @param {CanvasRenderingContext2D} ctx - Canvas rendering context
+ * @param {Object} gameState - Current game state
+ */
+function renderUI(ctx, gameState) {
+    const padding = 20;
+    const lineHeight = 30;
+    const startY = padding;
+    const width = 200;
+    const height = lineHeight * 5;
+    
+    // Save the current canvas state
+    ctx.save();
+    
+    // Reset any transformations
+    ctx.setTransform(1, 0, 0, 1, 0, 0);
+    
+    // Semi-transparent background for readability
+    ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
+    ctx.fillRect(0, 0, width, height + padding);
+    
+    // Text rendering setup
+    ctx.fillStyle = 'black';
+    ctx.font = '20px Arial';
+    ctx.textAlign = 'left';
+    ctx.textBaseline = 'top';
+    
+    // Game state information
+    ctx.fillText(`Level: ${gameState.level}`, padding, startY);
+    ctx.fillText(`Currency: $${gameState.currency}`, padding, startY + lineHeight);
+    ctx.fillText(`Phase: ${gameState.phase}`, padding, startY + lineHeight * 2);
+    ctx.fillText(`Destroyed: ${gameState.enemiesDestroyed}`, padding, startY + lineHeight * 3);
+    ctx.fillText(`Escaped: ${gameState.enemiesEscaped}`, padding, startY + lineHeight * 4);
+    
+    // Restore the canvas state
+    ctx.restore();
+}
+
+function renderTowers(ctx, towers) {
+    const cellSize = canvas.width / 20;
+    
+    towers.forEach(tower => {
+        const healthPercent = tower.currentHealth / tower.maxHealth;
+        
+        // Draw tower body
+        ctx.fillStyle = tower.color + Math.floor(healthPercent * 255).toString(16).padStart(2, '0');
+        ctx.fillRect(
+            tower.position.x * cellSize + cellSize * 0.1,
+            tower.position.y * cellSize + cellSize * 0.1,
+            cellSize * 0.8,
+            cellSize * 0.8
+        );
+        
+        // Draw ammo count
+        ctx.fillStyle = 'white';
+        ctx.font = '12px Arial';
+        ctx.textAlign = 'center';
+        ctx.fillText(
+            tower.ammo,
+            (tower.position.x + 0.5) * cellSize,
+            (tower.position.y + 0.7) * cellSize
+        );
+        
+        // Draw range indicator
+        if (gameState.phase === GamePhase.PLACEMENT) {
+            ctx.beginPath();
+            ctx.arc(
+                (tower.position.x + 0.5) * cellSize,
+                (tower.position.y + 0.5) * cellSize,
+                tower.range * cellSize,
+                0,
+                Math.PI * 2
+            );
+            ctx.strokeStyle = tower.color + '40';
+            ctx.stroke();
+        }
+    });
+}
+
+// Add new render function for particles
+function renderParticles(ctx, particles) {
+    particles.forEach(particle => {
+        const age = performance.now() - particle.createdAt;
+        const lifePercent = age / particle.lifetime;
+        
+        if (lifePercent &lt;= 1) {
+            if (particle.type === 'SLIME_TRAIL') {
+                // Calculate opacity based on lifetime and fade start
+                let opacity = 1;
+                if (lifePercent > particle.fadeStart) {
+                    opacity = 1 - ((lifePercent - particle.fadeStart) / (1 - particle.fadeStart));
+                }
+                opacity *= 0.3; // Make it translucent
+                
+                ctx.globalAlpha = opacity;
+                ctx.fillStyle = particle.color;
+                
+                // Draw a circular slime splat
+                ctx.beginPath();
+                ctx.arc(
+                    particle.position.x,
+                    particle.position.y,
+                    particle.size * (1 - lifePercent * 0.3), // Slightly shrink over time
+                    0,
+                    Math.PI * 2
+                );
+                ctx.fill();
+                
+                // Add some variation to the splat
+                for (let i = 0; i &lt; 3; i++) {
+                    const angle = (Math.PI * 2 * i) / 3;
+                    const distance = particle.size * 0.4;
+                    ctx.beginPath();
+                    ctx.arc(
+                        particle.position.x + Math.cos(angle) * distance,
+                        particle.position.y + Math.sin(angle) * distance,
+                        particle.size * 0.4 * (1 - lifePercent * 0.3),
+                        0,
+                        Math.PI * 2
+                    );
+                    ctx.fill();
+                }
+            } else if (particle.type === 'AOE_EXPLOSION') {
+                // Draw expanding circle
+                const radius = particle.initialRadius + 
+                    (particle.finalRadius - particle.initialRadius) * lifePercent;
+                
+                // Draw multiple rings for better effect
+                const numRings = 3;
+                for (let i = 0; i &lt; numRings; i++) {
+                    const ringRadius = radius * (1 - (i * 0.2));
+                    const ringAlpha = (1 - lifePercent) * (1 - (i * 0.3));
+                    
+                    ctx.beginPath();
+                    ctx.arc(
+                        particle.position.x,
+                        particle.position.y,
+                        ringRadius,
+                        0,
+                        Math.PI * 2
+                    );
+                    ctx.strokeStyle = particle.color;
+                    ctx.lineWidth = particle.ringWidth * (1 - (i * 0.2));
+                    ctx.globalAlpha = ringAlpha;
+                    ctx.stroke();
+                }
+                
+                // Draw affected area
+                ctx.beginPath();
+                ctx.arc(
+                    particle.position.x,
+                    particle.position.y,
+                    radius,
+                    0,
+                    Math.PI * 2
+                );
+                ctx.fillStyle = particle.color + '20'; // Very transparent fill
+                ctx.fill();
+            } else {
+                // Original particle rendering
+                ctx.fillStyle = particle.color;
+                ctx.beginPath();
+                ctx.arc(
+                    particle.position.x,
+                    particle.position.y,
+                    particle.size * (1 - lifePercent),
+                    0,
+                    Math.PI * 2
+                );
+                ctx.fill();
+            }
+        }
+    });
+    ctx.globalAlpha = 1;
+}
+
+// Add new render function for projectiles
+function renderProjectiles(ctx, projectiles) {
+    const cellSize = canvas.width / 20;
+    
+    projectiles.forEach(projectile => {
+        const age = performance.now() - projectile.createdAt;
+        const progress = age / projectile.lifetime;
+        
+        if (progress &lt;= 1) {
+            // Draw projectile trail
+            ctx.beginPath();
+            ctx.moveTo(
+                projectile.startPos.x * cellSize + cellSize / 2,
+                projectile.startPos.y * cellSize + cellSize / 2
+            );
+            
+            const currentX = projectile.startPos.x + (projectile.targetPos.x - projectile.startPos.x) * progress;
+            const currentY = projectile.startPos.y + (projectile.targetPos.y - projectile.startPos.y) * progress;
+            
+            ctx.lineTo(
+                currentX * cellSize + cellSize / 2,
+                currentY * cellSize + cellSize / 2
+            );
+            
+            ctx.strokeStyle = '#fff';
+            ctx.lineWidth = 2;
+            ctx.stroke();
+            
+            // Draw projectile head
+            ctx.beginPath();
+            ctx.arc(
+                currentX * cellSize + cellSize / 2,
+                currentY * cellSize + cellSize / 2,
+                4,
+                0,
+                Math.PI * 2
+            );
+            ctx.fillStyle = '#fff';
+            ctx.fill();
+        }
+    });
+}
+
+// Update level complete message in game.js
+function handleLevelComplete() {
+    gameState.phase = GamePhase.TRANSITION;
+    
+    // Calculate ammo bonus
+    let ammoBonus = 0;
+    gameState.towers.forEach(tower => {
+        ammoBonus += tower.ammo * 2;
+    });
+    
+    const message = `
+        Level ${gameState.level} Complete!
+        Current Money: $${gameState.currency}
+        Ammo Bonus: +$${ammoBonus}
+        Level Bonus: +$10
+        
+        Ready for Level ${gameState.level + 1}?
+    `;
+    
+    setTimeout(() => {
+        if (confirm(message)) {
+            startNextLevel();
+        }
+    }, 100);
+} </code></pre>
+        </article>
+    </section>
+
+
+
+
+</div>
+
+<nav>
+    <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-game.html">game</a></li><li><a href="module-gameState.html">gameState</a></li><li><a href="module-mechanics.html">mechanics</a></li><li><a href="module-path.html">path</a></li><li><a href="module-renderer.html">renderer</a></li><li><a href="module-uiHandlers.html">uiHandlers</a></li></ul>
+</nav>
+
+<br class="clear">
+
+<footer>
+    Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.3</a> on Mon Feb 17 2025 09:19:19 GMT-0500 (Eastern Standard Time)
+</footer>
+
+<script> prettyPrint(); </script>
+<script src="scripts/linenumber.js"> </script>
+</body>
+</html>