diff options
author | elioat <elioat@tilde.institute> | 2024-12-07 15:40:58 -0500 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2024-12-07 15:40:58 -0500 |
commit | 72dccb46d7f9b51496ab14b37ab9f988e9b370f9 (patch) | |
tree | f3fd05d6912ecb2647b4c82bbc2fab39b859bf4b | |
parent | e720cb7f47e74eaef81fa11cef2954d7a566185e (diff) | |
download | tour-72dccb46d7f9b51496ab14b37ab9f988e9b370f9.tar.gz |
*
-rw-r--r-- | html/mountain/game.js | 71 |
1 files changed, 52 insertions, 19 deletions
diff --git a/html/mountain/game.js b/html/mountain/game.js index a05bdb9..8cbfa4d 100644 --- a/html/mountain/game.js +++ b/html/mountain/game.js @@ -8,7 +8,7 @@ canvas.style.left = '0'; const GAME_STATE = { PLAYING: 'playing', - GAME_OVER: 'game_over' + GAME_OVER: 'game_over' // (ノಠ益ಠ)ノ }; const PLATFORM_TYPE = { @@ -88,6 +88,27 @@ const keys = {}; window.addEventListener('keydown', e => keys[e.key] = true); window.addEventListener('keyup', e => keys[e.key] = false); +const COLORS = { + BACKGROUND: '#E0E0E0', + PLATFORM: { + NORMAL: '#1A1A1A', + DEADLY: 'tomato', + FALLING: 'rgba(26, 26, 26, 0.5)' + }, + PLAYER: { + NORMAL: '#1A1A1A', + INVERTED: '#4A90E2' + }, + ENEMY: 'tomato', + EXIT: 'teal', + TEXT: '#1A1A1A', + GAME_OVER: { + OVERLAY: 'rgba(0, 0, 0, 0.7)', + TEXT: 'rgba(255, 255, 255, 0.75)' + }, + DEADLY_BORDER: 'tomato' +}; + function randomRange(min, max) { return min + Math.random() * (max - min); } @@ -215,7 +236,6 @@ function updateEnemies() { }); } -// 9. Level Generation function generatePlatformsForPartition(partition) { if (partition.width < MIN_PLATFORM_WIDTH || partition.height < PLATFORM_HEIGHT * 2) { return []; @@ -232,22 +252,31 @@ function generatePlatformsForPartition(partition) { let validPlatform = null; let attempts = 0; + // Try to create a platform, but don't try too hard so that things get stuck while (!validPlatform && attempts < maxAttempts) { + // Generate a random width for the platform, that is between a min and a max const platformWidth = randomRange( MIN_PLATFORM_WIDTH, - Math.min(MAX_PLATFORM_WIDTH, partition.width * 0.8) + Math.min(MAX_PLATFORM_WIDTH, partition.width * 0.8) ); + // Generate the minimum x position, which is either the partition's start + // or a position based on the platform's number being placed (i/platformCount) + // This spreads the platforms out more evenly across the partition const minX = Math.max( partition.x, partition.x + (partition.width * (i / platformCount)) ); + + // Along the same lines, calculate a max x position that accounts for platform width const maxX = Math.min( partition.x + partition.width - platformWidth, partition.x + (partition.width * ((i + 1) / platformCount)) ); + // Try to place a platform if there is a valid range if (maxX > minX) { + // Create a candidate platform with a random position and properties const candidatePlatform = { x: randomRange(minX, maxX), y: randomRange( @@ -256,6 +285,7 @@ function generatePlatformsForPartition(partition) { ), width: platformWidth, height: PLATFORM_HEIGHT, + // After level 1, there is a chance that a platform will be deadly, or falling! type: (() => { if (level > 1 && Math.random() < 0.2) return PLATFORM_TYPE.DEADLY; if (level > 1 && Math.random() < 0.3) { @@ -267,6 +297,7 @@ function generatePlatformsForPartition(partition) { velocityY: 0 }; + // Check if the platform overlaps with any existing platforms let overlapping = false; for (const existingPlatform of [...platforms, ...newPlatforms]) { if (platformsOverlap(candidatePlatform, existingPlatform)) { @@ -275,6 +306,8 @@ function generatePlatformsForPartition(partition) { } } + // If there isn't an overlap the platform is valid! + // Place it! if (!overlapping) { validPlatform = candidatePlatform; } @@ -501,10 +534,10 @@ function resizeCanvas() { } function draw(currentTime) { - ctx.fillStyle = '#E0E0E0'; + ctx.fillStyle = COLORS.BACKGROUND; ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.fillStyle = 'tomato'; + ctx.fillStyle = COLORS.DEADLY_BORDER; ctx.fillRect(0, 0, canvas.width - exit.size - 300, DEADLY_BORDER_HEIGHT); ctx.fillRect(0, canvas.height - DEADLY_BORDER_HEIGHT, platforms[0].x, DEADLY_BORDER_HEIGHT); @@ -516,26 +549,26 @@ function draw(currentTime) { ); for (let platform of platforms) { - ctx.fillStyle = platform.type === PLATFORM_TYPE.DEADLY ? 'tomato' : - platform.type === PLATFORM_TYPE.FALLING ? 'rgba(26, 26, 26, 0.75)' : - '#1A1A1A'; + ctx.fillStyle = platform.type === PLATFORM_TYPE.DEADLY ? COLORS.PLATFORM.DEADLY : + platform.type === PLATFORM_TYPE.FALLING ? COLORS.PLATFORM.FALLING : + COLORS.PLATFORM.NORMAL; ctx.fillRect(platform.x, platform.y, platform.width, platform.height); } - ctx.fillStyle = 'teal'; + ctx.fillStyle = COLORS.EXIT; ctx.fillRect(exit.x, exit.y, exit.size, exit.size); if (!player.isDead) { - ctx.fillStyle = player.gravityMultiplier > 0 ? '#1A1A1A' : '#4A90E2'; + ctx.fillStyle = player.gravityMultiplier > 0 ? COLORS.PLAYER.NORMAL : COLORS.PLAYER.INVERTED; ctx.fillRect(player.x, player.y, PLAYER_SIZE, PLAYER_SIZE); } - ctx.fillStyle = '#000000'; + ctx.fillStyle = COLORS.TEXT; ctx.font = '20px Arial'; ctx.textAlign = 'left'; ctx.fillText(`Level: ${level}`, 10, 30); - // Draw particles with different opacities + // Particles can have different opacities particles.forEach(particle => { const alpha = (particle.life / PARTICLE_LIFETIME) * particle.initialOpacity; ctx.fillStyle = `rgba(26, 26, 26, ${alpha})`; @@ -543,11 +576,11 @@ function draw(currentTime) { }); enemies.forEach(enemy => { - ctx.fillStyle = 'tomato'; + ctx.fillStyle = COLORS.ENEMY; ctx.fillRect(enemy.x, enemy.y, enemy.width, enemy.height); }); - // Death particles! + // Death particles x_x deathParticles.forEach(particle => { const alpha = (particle.life / DEATH_PARTICLE_LIFETIME) * particle.initialOpacity; ctx.fillStyle = `rgba(26, 26, 26, ${alpha})`; @@ -555,10 +588,10 @@ function draw(currentTime) { }); if (gameState === GAME_STATE.GAME_OVER && deathAnimationTimer <= 0) { - ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'; + ctx.fillStyle = COLORS.GAME_OVER.OVERLAY; ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.fillStyle = 'rgba(255, 255, 255, 0.75)'; + ctx.fillStyle = COLORS.GAME_OVER.TEXT; ctx.font = '100px Arial'; ctx.textAlign = 'center'; ctx.fillText('GAME OVER', canvas.width / 2, canvas.height / 2); @@ -569,14 +602,14 @@ function draw(currentTime) { ctx.textAlign = 'left'; } - // Show help text on the first level + // Show some help text on the first level so that folks know what to do if (level === 1 && gameState === GAME_STATE.PLAYING) { - ctx.fillStyle = '#1A1A1A'; + ctx.fillStyle = COLORS.TEXT; ctx.font = '24px Arial'; ctx.textAlign = 'center'; ctx.fillText('Arrow keys move the player.', canvas.width / 2, canvas.height / 2 - 20); ctx.fillText('Space bar reverses gravity.', canvas.width / 2, canvas.height / 2 + 20); - ctx.textAlign = 'left'; // Reset text alignment for other text + ctx.textAlign = 'left'; } } |