diff options
author | elioat <elioat@tilde.institute> | 2025-02-16 16:36:44 -0500 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2025-02-16 16:36:44 -0500 |
commit | b86049a413b7a63e04adeb6d2afd80801313b019 (patch) | |
tree | 6fc8fc49895c470b733dd6af49128c92f2baf6e8 /html | |
parent | 651ba65917968af90b97a77d02e28648c808b672 (diff) | |
download | tour-b86049a413b7a63e04adeb6d2afd80801313b019.tar.gz |
*
Diffstat (limited to 'html')
-rw-r--r-- | html/tower/index.html | 3 | ||||
-rw-r--r-- | html/tower/js/game.js | 12 | ||||
-rw-r--r-- | html/tower/js/gameState.js | 42 | ||||
-rw-r--r-- | html/tower/js/mechanics.js | 49 | ||||
-rw-r--r-- | html/tower/js/renderer.js | 51 |
5 files changed, 125 insertions, 32 deletions
diff --git a/html/tower/index.html b/html/tower/index.html index e27cf28..d9dd854 100644 --- a/html/tower/index.html +++ b/html/tower/index.html @@ -95,10 +95,7 @@ </div> <!-- Core game modules --> - <script src="js/grid.js"></script> <script src="js/path.js"></script> - <script src="js/tower.js"></script> - <script src="js/enemy.js"></script> <script src="js/mechanics.js"></script> <script src="js/uiHandlers.js"></script> diff --git a/html/tower/js/game.js b/html/tower/js/game.js index 5c28f31..7d362ae 100644 --- a/html/tower/js/game.js +++ b/html/tower/js/game.js @@ -43,6 +43,8 @@ function handleCombatPhase(timestamp, deltaTime) { gameState.projectiles = gameState.projectiles.filter(p => timestamp - p.createdAt < p.lifetime); const cellSize = canvas.width / 20; + + // Process tower and enemy attacks processTowerAttacks( gameState.towers, gameState.enemies, @@ -52,7 +54,17 @@ function handleCombatPhase(timestamp, deltaTime) { cellSize ); + processEnemyAttacks( + gameState.enemies, + gameState.towers, + gameState.particles, + timestamp, + cellSize + ); + + // Remove dead enemies and destroyed towers gameState.enemies = gameState.enemies.filter(enemy => enemy.currentHealth > 0); + gameState.towers = gameState.towers.filter(tower => tower.currentHealth > 0); } function spawnEnemies(timestamp) { diff --git a/html/tower/js/gameState.js b/html/tower/js/gameState.js index a1ab765..49708ee 100644 --- a/html/tower/js/gameState.js +++ b/html/tower/js/gameState.js @@ -43,21 +43,53 @@ const ParticleTypes = { } }; +const EnemyTypes = { + BASIC: { + color: '#ff0000', + baseHealth: { min: 2, max: 6 }, + speed: { min: 1, max: 1.5 }, + damage: 0, + isRanged: false + }, + RANGED: { + color: '#8e44ad', // Purple + baseHealth: { min: 1, max: 4 }, + speed: { min: 0.7, max: 1.2 }, + damage: 0.3, + attackRange: 3, + attackSpeed: 1, // attacks per second + isRanged: true + } +}; + function createTower(type, position) { return { ...TowerTypes[type], + type, position, - lastAttackTime: 0 + lastAttackTime: 0, + currentHealth: 10, + maxHealth: 10 }; } function createEnemy(startPosition) { + // 20% chance for ranged enemy + const type = Math.random() < 0.2 ? 'RANGED' : 'BASIC'; + const enemyType = EnemyTypes[type]; + const health = Math.floor(Math.random() * + (enemyType.baseHealth.max - enemyType.baseHealth.min + 1)) + + enemyType.baseHealth.min; + return { position: { ...startPosition }, - currentHealth: Math.floor(Math.random() * 5) + 2, // 2-6 health - maxHealth: this.currentHealth, - speed: 1 + Math.random() * 0.5, // 1-1.5 speed - pathIndex: 0 + currentHealth: health, + maxHealth: health, + speed: enemyType.speed.min + Math.random() * (enemyType.speed.max - enemyType.speed.min), + pathIndex: 0, + type, + lastAttackTime: 0, + damage: enemyType.damage }; } diff --git a/html/tower/js/mechanics.js b/html/tower/js/mechanics.js index 72b284a..4babe2a 100644 --- a/html/tower/js/mechanics.js +++ b/html/tower/js/mechanics.js @@ -91,4 +91,53 @@ function handleTowerAttack(tower, target, projectiles, particles, timestamp, cel if (target.currentHealth <= 0) { particles.push(...createDeathParticles(target, cellSize)); } +} + +function processEnemyAttacks(enemies, towers, particles, timestamp, cellSize) { + enemies.forEach(enemy => { + if (!EnemyTypes[enemy.type].isRanged) return; + + if (timestamp - enemy.lastAttackTime > 1000 / EnemyTypes[enemy.type].attackSpeed) { + const towersInRange = findTowersInRange(enemy, towers); + + if (towersInRange.length > 0) { + const target = towersInRange[0]; + handleEnemyAttack(enemy, target, particles, timestamp, cellSize); + } + } + }); +} + +function findTowersInRange(enemy, towers) { + return towers.filter(tower => { + const dx = tower.position.x - enemy.position.x; + const dy = tower.position.y - enemy.position.y; + return Math.sqrt(dx * dx + dy * dy) <= EnemyTypes[enemy.type].attackRange; + }); +} + +function handleEnemyAttack(enemy, tower, particles, timestamp, cellSize) { + // Create enemy projectile + const projectileColor = '#8e44ad80'; // Semi-transparent purple + particles.push(createParticle( + { + ...ParticleTypes.PROJECTILE, + color: projectileColor, + lifetime: 500 + }, + { + x: (enemy.position.x + 0.5) * cellSize, + y: (enemy.position.y + 0.5) * cellSize + }, + Math.atan2( + tower.position.y - enemy.position.y, + tower.position.x - enemy.position.x + ) + )); + + tower.currentHealth -= enemy.damage; + enemy.lastAttackTime = timestamp; + + // Reduce tower's damage as it takes damage + tower.damage = TowerTypes[tower.type].damage * (tower.currentHealth / tower.maxHealth); } \ No newline at end of file diff --git a/html/tower/js/renderer.js b/html/tower/js/renderer.js index 10444aa..b0d1da0 100644 --- a/html/tower/js/renderer.js +++ b/html/tower/js/renderer.js @@ -61,29 +61,15 @@ 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; + const opacity = 0.3 + (healthPercent * 0.7); - 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 - ); + // Use enemy type color + ctx.fillStyle = `${EnemyTypes[enemy.type].color}${Math.floor(opacity * 255).toString(16).padStart(2, '0')}`; + ctx.strokeStyle = 'rgba(0, 0, 0, 0.8)'; + ctx.lineWidth = 2; - // Draw enemy - ctx.fillStyle = 'red'; + // Draw enemy body ctx.beginPath(); ctx.arc( (enemy.position.x + 0.5) * cellSize, @@ -93,6 +79,21 @@ function renderEnemies(ctx, enemies) { Math.PI * 2 ); ctx.fill(); + ctx.stroke(); + + // Draw range indicator for ranged enemies + 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(); + } }); } @@ -107,8 +108,10 @@ function renderTowers(ctx, towers) { const cellSize = canvas.width / 20; towers.forEach(tower => { - // Draw tower body - ctx.fillStyle = tower.color; + const healthPercent = tower.currentHealth / tower.maxHealth; + + // Draw tower body with opacity based on health + 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, @@ -116,7 +119,7 @@ function renderTowers(ctx, towers) { cellSize * 0.8 ); - // Draw range indicator (only during placement phase) + // Draw range indicator if (gameState.phase === GamePhase.PLACEMENT) { ctx.beginPath(); ctx.arc( @@ -126,7 +129,7 @@ function renderTowers(ctx, towers) { 0, Math.PI * 2 ); - ctx.strokeStyle = tower.color + '40'; // 40 is hex for 25% opacity + ctx.strokeStyle = tower.color + '40'; ctx.stroke(); } }); |