diff options
Diffstat (limited to 'html/tower/js/renderer.js')
-rw-r--r-- | html/tower/js/renderer.js | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/html/tower/js/renderer.js b/html/tower/js/renderer.js new file mode 100644 index 0000000..10444aa --- /dev/null +++ b/html/tower/js/renderer.js @@ -0,0 +1,199 @@ +function renderGrid(ctx, grid) { + const cellSize = canvas.width / 20; + + // Draw grid lines + ctx.strokeStyle = '#ccc'; + ctx.lineWidth = 1; + + for (let i = 0; i <= 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(); + } + + // Draw cells + grid.forEach((row, y) => { + row.forEach((cell, x) => { + if (cell === 'path') { + ctx.fillStyle = '#f4a460'; + ctx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize); + } + }); + }); + + // Draw hover preview + if (gameState.phase === GamePhase.PLACEMENT && draggedTowerType && hoverCell) { + const tower = TowerTypes[draggedTowerType]; + const canPlace = grid[hoverCell.y][hoverCell.x] === 'empty' && + gameState.playerCurrency >= tower.cost; + + ctx.fillStyle = canPlace ? tower.color + '80' : 'rgba(255, 0, 0, 0.3)'; + ctx.fillRect( + hoverCell.x * cellSize, + hoverCell.y * cellSize, + cellSize, + cellSize + ); + + // Draw range 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(); + } +} + +function renderEnemies(ctx, enemies) { + const cellSize = canvas.width / 20; + + enemies.forEach(enemy => { + // Draw enemy health bar + const healthPercent = enemy.currentHealth / enemy.maxHealth; + const barWidth = cellSize * 0.8; + const barHeight = 4; + + ctx.fillStyle = '#e74c3c'; + ctx.fillRect( + (enemy.position.x + 0.1) * cellSize, + (enemy.position.y - 0.1) * cellSize - barHeight, + barWidth, + barHeight + ); + + ctx.fillStyle = '#2ecc71'; + ctx.fillRect( + (enemy.position.x + 0.1) * cellSize, + (enemy.position.y - 0.1) * cellSize - barHeight, + barWidth * healthPercent, + barHeight + ); + + // Draw enemy + ctx.fillStyle = 'red'; + ctx.beginPath(); + ctx.arc( + (enemy.position.x + 0.5) * cellSize, + (enemy.position.y + 0.5) * cellSize, + cellSize / 3, + 0, + Math.PI * 2 + ); + ctx.fill(); + }); +} + +function renderUI(ctx, gameState) { + ctx.fillStyle = 'black'; + ctx.font = '20px Arial'; + ctx.fillText(`Currency: ${gameState.playerCurrency}`, 10, 30); + ctx.fillText(`Phase: ${gameState.phase}`, 10, 60); +} + +function renderTowers(ctx, towers) { + const cellSize = canvas.width / 20; + + towers.forEach(tower => { + // Draw tower body + ctx.fillStyle = tower.color; + ctx.fillRect( + tower.position.x * cellSize + cellSize * 0.1, + tower.position.y * cellSize + cellSize * 0.1, + cellSize * 0.8, + cellSize * 0.8 + ); + + // Draw range indicator (only during placement phase) + 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'; // 40 is hex for 25% opacity + 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 <= 1) { + ctx.globalAlpha = 1 - lifePercent; + 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 <= 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(); + } + }); +} \ No newline at end of file |