diff options
-rw-r--r-- | html/plains/enemies.js | 61 | ||||
-rw-r--r-- | html/plains/game.js | 148 |
2 files changed, 114 insertions, 95 deletions
diff --git a/html/plains/enemies.js b/html/plains/enemies.js index 77f5245..e3be9af 100644 --- a/html/plains/enemies.js +++ b/html/plains/enemies.js @@ -69,6 +69,36 @@ const generateEnemies = (villagers, collisionMap) => { return enemies; }; +const createDeathParticles = (enemy) => { + const numParticles = 15 + Math.floor(Math.random() * 10); + for (let i = 0; i < numParticles; i++) { + const particleAngle = (i / numParticles) * Math.PI * 2; + const speed = 2 + Math.random() * 3; + state.particles.push({ + x: enemy.x, + y: enemy.y, + dx: Math.cos(particleAngle) * speed, + dy: Math.sin(particleAngle) * speed, + size: enemy.size * (0.1 + Math.random() * 0.2), + color: enemy.color, + lifetime: 1000, + createdAt: animationTime + }); + } +}; + +const createDeathDiamonds = (enemy) => { + const diamondCount = Math.floor(Math.random() * 5); + for (let i = 0; i < diamondCount; i++) { + state.diamonds.push({ + x: enemy.x + (Math.random() - 0.5) * 20, + y: enemy.y + (Math.random() - 0.5) * 20, + size: 6, + collected: false + }); + } +}; + const handleEnemyDamage = (enemy, damage, knockbackForce = 0, angle = 0) => { const gridSize = CONFIG.display.grid.size; enemy.hp -= damage; @@ -79,7 +109,7 @@ const handleEnemyDamage = (enemy, damage, knockbackForce = 0, angle = 0) => { // Apply knockback if there's a force if (knockbackForce > 0) { - const knockbackDistance = gridSize * 0.5; // Half grid cell knockback + const knockbackDistance = gridSize * 0.5; enemy.knockback = { active: true, startX: enemy.x, @@ -92,33 +122,8 @@ const handleEnemyDamage = (enemy, damage, knockbackForce = 0, angle = 0) => { } if (damage > 0 && enemy.hp <= 0) { - // Create death particles - const numParticles = 15 + Math.floor(Math.random() * 10); - for (let i = 0; i < numParticles; i++) { - const particleAngle = (i / numParticles) * Math.PI * 2; - const speed = 2 + Math.random() * 3; - state.particles.push({ - x: enemy.x, - y: enemy.y, - dx: Math.cos(particleAngle) * speed, - dy: Math.sin(particleAngle) * speed, - size: enemy.size * (0.1 + Math.random() * 0.2), - color: enemy.color, - lifetime: 1000, - createdAt: animationTime - }); - } - - // Generate diamonds when enemy is defeated - const diamondCount = Math.floor(Math.random() * 5); - for (let i = 0; i < diamondCount; i++) { - state.diamonds.push({ - x: enemy.x + (Math.random() - 0.5) * 20, - y: enemy.y + (Math.random() - 0.5) * 20, - size: 6, - collected: false - }); - } + createDeathParticles(enemy); + createDeathDiamonds(enemy); } return damage > 0 && enemy.hp <= 0; diff --git a/html/plains/game.js b/html/plains/game.js index 993ba45..12742d4 100644 --- a/html/plains/game.js +++ b/html/plains/game.js @@ -749,6 +749,22 @@ const createBubbleAttack = (state, animationTime) => { }; }; +// Add this helper function near other weapon-related functions +const checkEnemyCollision = (enemy, sourceX, sourceY, range) => { + if (enemy.stunned) return false; + + const dx = enemy.x - sourceX; + const dy = enemy.y - sourceY; + const distance = Math.sqrt(dx * dx + dy * dy); + + if (distance < enemy.size + range) { + const knockbackAngle = Math.atan2(dy, dx); + enemySystem.handleEnemyDamage(enemy, 1, 1, knockbackAngle); + return true; + } + return false; +}; + const weaponSystems = { updateBubbles: (state, animationTime) => { const updatedBubbles = state.player.bubbles @@ -756,18 +772,8 @@ const weaponSystems = { .map(bubble => { // Check for enemy collisions state.enemies.forEach(enemy => { - if (!enemy.stunned) { - const dx = enemy.x - bubble.x; - const dy = enemy.y - bubble.y; - const distance = Math.sqrt(dx * dx + dy * dy); - - if (distance < enemy.size + CONFIG.bubble.size) { - const knockbackAngle = Math.atan2(dy, dx); - enemySystem.handleEnemyDamage(enemy, 1, 1, knockbackAngle); - } - } + checkEnemyCollision(enemy, bubble.x, bubble.y, CONFIG.bubble.size); }); - return updateBubble(bubble, animationTime); }); @@ -793,24 +799,9 @@ const weaponSystems = { const newAngle = state.player.swordAngle + CONFIG.sword.swingSpeed; const swingComplete = newAngle > Math.atan2(state.player.direction.y, state.player.direction.x) + Math.PI / 2; - // Add sword collision detection - const swordTip = { - x: state.player.x + Math.cos(state.player.swordAngle) * CONFIG.sword.length, - y: state.player.y + Math.sin(state.player.swordAngle) * CONFIG.sword.length - }; - // Check all enemies for sword collision const updatedEnemies = state.enemies.map(enemy => { - if (!enemy.stunned) { - const dx = enemy.x - state.player.x; - const dy = enemy.y - state.player.y; - const distance = Math.sqrt(dx * dx + dy * dy); - - if (distance < enemy.size + CONFIG.sword.length) { - const knockbackAngle = Math.atan2(dy, dx); - enemySystem.handleEnemyDamage(enemy, 1, 1, knockbackAngle); - } - } + checkEnemyCollision(enemy, state.player.x, state.player.y, CONFIG.sword.length); return enemy; }); @@ -1894,63 +1885,86 @@ const getCellInfo = (x, y) => { }; }; -const showSwordUnlockAnimation = () => { - // Create container for animation +const createFloatingMessage = (messageConfig) => { + const { + text, + duration = null, // null means permanent + backgroundColor = 'rgba(0, 0, 0, 0.8)', + glowColor = null, + glowDuration = 2000 // 2s default for glow animation + } = messageConfig; + + // Create container const container = document.createElement('div'); container.style.position = 'fixed'; container.style.top = '50%'; container.style.left = '50%'; container.style.transform = 'translate(-50%, -50%)'; container.style.padding = '20px'; - container.style.backgroundColor = 'rgba(0, 0, 0, 0.8)'; + container.style.backgroundColor = backgroundColor; container.style.borderRadius = '10px'; - container.style.animation = 'glow 2s ease-in-out'; container.style.zIndex = '1000'; - - // Add CSS animation - const style = document.createElement('style'); - style.textContent = ` - @keyframes glow { - 0% { box-shadow: 0 0 0 0 ${CONFIG.player.equipment.unlockAnimation.glowColor}; opacity: 0; } - 50% { box-shadow: 0 0 30px 10px ${CONFIG.player.equipment.unlockAnimation.glowColor}; opacity: 1; } - 100% { box-shadow: 0 0 0 0 ${CONFIG.player.equipment.unlockAnimation.glowColor}; opacity: 0; } - } - `; - document.head.appendChild(style); - + // Add message text const message = document.createElement('div'); - message.textContent = CONFIG.player.equipment.unlockAnimation.messageText; - message.style.color = CONFIG.player.equipment.unlockAnimation.messageColor; + message.textContent = text; + message.style.color = 'white'; message.style.fontSize = '24px'; message.style.textAlign = 'center'; container.appendChild(message); - - // Add to document and remove after animation + + // Add glow animation if specified + if (glowColor) { + container.style.animation = `glow ${glowDuration}ms ease-in-out`; + + const style = document.createElement('style'); + style.textContent = ` + @keyframes glow { + 0% { box-shadow: 0 0 0 0 ${glowColor}; opacity: 0; } + 50% { box-shadow: 0 0 30px 10px ${glowColor}; opacity: 1; } + 100% { box-shadow: 0 0 0 0 ${glowColor}; opacity: ${duration ? 0 : 1}; } + } + `; + document.head.appendChild(style); + + // Clean up style element after animation + setTimeout(() => { + document.head.removeChild(style); + if (!duration) { + // For permanent messages, set final glow state after animation + container.style.boxShadow = `0 0 30px 10px ${glowColor}`; + } + }, glowDuration); + } + + // Add to document and remove after duration (if specified) document.body.appendChild(container); - setTimeout(() => { - document.body.removeChild(container); - document.head.removeChild(style); - }, CONFIG.player.equipment.unlockAnimation.duration); + if (duration) { + setTimeout(() => { + document.body.removeChild(container); + }, duration); + } + + return container; // Return container for manual removal if needed }; +// Update showGameOver to be permanent const showGameOver = () => { - const gameOverDiv = document.createElement('div'); - gameOverDiv.style.position = 'fixed'; - gameOverDiv.style.top = '50%'; - gameOverDiv.style.left = '50%'; - gameOverDiv.style.transform = 'translate(-50%, -50%)'; - gameOverDiv.style.backgroundColor = 'rgba(0, 0, 0, 0.8)'; - gameOverDiv.style.padding = '20px'; - gameOverDiv.style.borderRadius = '10px'; - gameOverDiv.style.color = 'white'; - gameOverDiv.style.textAlign = 'center'; - gameOverDiv.style.fontSize = '24px'; - gameOverDiv.innerHTML = ` - <h2>Game Over</h2> - <p>Press Space to restart</p> - `; - document.body.appendChild(gameOverDiv); + createFloatingMessage({ + text: 'Game Over\nPress Space to restart', + duration: null, // Permanent message + glowColor: 'rgba(255, 0, 0, 0.6)' + }); +}; + +// Update showSwordUnlockAnimation with explicit timing +const showSwordUnlockAnimation = () => { + createFloatingMessage({ + text: CONFIG.player.equipment.unlockAnimation.messageText, + duration: CONFIG.player.equipment.unlockAnimation.duration, + glowColor: CONFIG.player.equipment.unlockAnimation.glowColor, + glowDuration: 2000 // Explicit glow animation duration + }); }; // Update the player's HP when collecting diamonds |