the game

feat: add healing

dunkirk.sh e0161e21 db297c00

verified
+102 -31
+8 -1
src/enemy.ts
··· 161 161 162 162 // Damage player 163 163 if (playerObj.damage) { 164 - playerObj.damage(5); 164 + // Get current difficulty level to scale damage 165 + const difficultyLevel = k.get("game-score-tracker")[0]?.difficultyLevel || 1; 166 + 167 + // Base damage is 5, increases with difficulty 168 + const baseDamage = 5; 169 + const scaledDamage = Math.round(baseDamage + (difficultyLevel - 1) * 2); 170 + 171 + playerObj.damage(scaledDamage); 165 172 } 166 173 167 174 // Knockback effect
+73 -30
src/main.ts
··· 91 91 let score = 0; 92 92 93 93 const scoreText = k.add([k.text(`Score: ${score}`), k.pos(16, 16), "score"]); 94 - 94 + 95 95 // Add a hidden score tracker that can be accessed by other components 96 96 const scoreTracker = k.add([ 97 97 k.pos(0, 0), 98 98 "game-score-tracker", 99 99 { 100 100 score: score, 101 + difficultyLevel: difficultyLevel, 101 102 updateScore(newScore: number) { 102 103 this.score = newScore; 103 104 score = newScore; // Update the main score variable 104 - } 105 - } 105 + }, 106 + updateDifficulty(newLevel: number) { 107 + this.difficultyLevel = newLevel; 108 + }, 109 + }, 106 110 ]); 107 111 108 112 // Difficulty scaling 109 113 function updateDifficulty() { 110 114 if (!gameActive) return; 111 - 115 + 112 116 gameTime += 1; // Increment game time by 1 second 113 - 117 + 114 118 // Check if it's time to increase difficulty based on score 115 119 // Use a formula that scales with difficulty level 116 120 const scoreThreshold = 50 * difficultyLevel; 117 - 121 + 118 122 if (score >= scoreThreshold && score % scoreThreshold < 10) { 119 123 // Only trigger once when crossing the threshold 120 124 if (!k.get("level-up-text").length) { 121 125 difficultyLevel += 1; 122 - 126 + 127 + // Update difficulty in tracker 128 + const tracker = k.get("game-score-tracker")[0]; 129 + if (tracker) { 130 + tracker.updateDifficulty(difficultyLevel); 131 + } 132 + 123 133 // Increase max enemies (cap at 15) 124 134 maxEnemies = Math.min(initialMaxEnemies + difficultyLevel, 15); 125 - 135 + 126 136 // Decrease spawn interval (minimum 0.5 seconds) 127 137 spawnInterval = Math.max( 128 138 initialSpawnInterval - difficultyLevel * 0.2, 129 - 0.5 139 + 0.5, 130 140 ); 131 - 141 + 132 142 console.log( 133 - `Difficulty increased to level ${difficultyLevel}. Max enemies: ${maxEnemies}, Spawn interval: ${spawnInterval}s` 143 + `Difficulty increased to level ${difficultyLevel}. Max enemies: ${maxEnemies}, Spawn interval: ${spawnInterval}s`, 134 144 ); 135 - 145 + 136 146 // Cancel previous spawn loop and start a new one with updated interval 137 - k.cancel("spawnEnemy"); 138 - k.loop(spawnInterval, spawnEnemy, "spawnEnemy"); 139 - 147 + k.loop(spawnInterval, spawnEnemy); 148 + 140 149 // Visual feedback for difficulty increase 141 150 const screenCenter = k.vec2(k.width() / 2, k.height() / 2); 142 151 if (k.addConfetti) { 143 152 k.addConfetti(screenCenter); 144 153 } 145 - 154 + 146 155 // Add difficulty level text 147 156 const levelText = k.add([ 148 157 k.text(`Difficulty Level ${difficultyLevel}!`, { size: 32 }), ··· 152 161 k.outline(2, k.rgb(0, 0, 0)), 153 162 k.z(100), 154 163 k.opacity(1), 155 - "level-up-text" 164 + "level-up-text", 156 165 ]); 157 - 166 + 158 167 // Fade out and destroy the text 159 168 k.tween( 160 169 1, ··· 165 174 levelText.opacity = v; 166 175 } 167 176 }, 168 - k.easings.easeInQuad 177 + k.easings.easeInQuad, 169 178 ); 170 - 179 + 171 180 k.wait(2, () => { 172 181 if (levelText.exists()) levelText.destroy(); 173 182 }); ··· 188 197 // Random position at the edges of the screen 189 198 // As difficulty increases, add chance to spawn in center 190 199 let spawnSide; 191 - 200 + 192 201 // Calculate center spawn chance based on difficulty level 193 202 // 0% at level 1-2, increasing to 30% at level 10+ 194 - const centerSpawnChance = difficultyLevel <= 2 ? 0 : Math.min((difficultyLevel - 2) * 0.04, 0.3); 195 - 203 + const centerSpawnChance = 204 + difficultyLevel <= 2 ? 0 : Math.min((difficultyLevel - 2) * 0.04, 0.3); 205 + 196 206 // Determine spawn location 197 207 if (Math.random() < centerSpawnChance) { 198 208 // Center spawn ··· 201 211 // Side spawn (left or right) 202 212 spawnSide = Math.floor(Math.random() * 2); // 0: left, 1: right 203 213 } 204 - 214 + 205 215 let x = 0, 206 216 y = 0; 207 217 ··· 235 245 236 246 // Update score display 237 247 scoreText.text = `Score: ${score}`; 238 - 248 + 239 249 // Update score tracker 240 250 const tracker = k.get("game-score-tracker")[0]; 241 251 if (tracker) { 242 252 tracker.score = score; 243 253 } 244 254 255 + // Heal player when killing an enemy 256 + const player = k.get("player")[0]; 257 + if (player && player.heal) { 258 + // Heal amount is 5 health points 259 + const healAmount = 5; 260 + player.heal(healAmount); 261 + 262 + // Show healing effect 263 + const healText = k.add([ 264 + k.text(`+${healAmount} HP`, { size: 16 }), 265 + k.pos(player.pos.x, player.pos.y - 60), 266 + k.anchor("center"), 267 + k.color(0, 255, 0), 268 + k.z(100), 269 + k.opacity(1), 270 + ]); 271 + 272 + // Float upward and fade out 273 + k.tween( 274 + 1, 275 + 0, 276 + 0.8, 277 + (v) => { 278 + if (healText.exists()) { 279 + healText.opacity = v; 280 + healText.pos.y -= 0.5; 281 + } 282 + }, 283 + k.easings.easeOutQuad, 284 + ); 285 + 286 + k.wait(0.8, () => { 287 + if (healText.exists()) healText.destroy(); 288 + }); 289 + } 290 + 245 291 if (Math.random() < 0.2 * Math.pow(difficultyLevel, 0.75)) spawnEnemy(); 246 292 }); 247 293 } 248 294 249 295 // Start spawning enemies 250 - k.loop(spawnInterval, spawnEnemy, "spawnEnemy"); 296 + k.loop(spawnInterval, spawnEnemy); 251 297 252 298 // Game loop 253 299 k.onUpdate(() => { ··· 258 304 // Listen for game over event 259 305 playerObj.on("death", () => { 260 306 gameActive = false; 261 - 307 + 262 308 // Get final score from tracker 263 309 const tracker = k.get("game-score-tracker")[0]; 264 310 if (tracker) { ··· 266 312 } else { 267 313 finalScore = score; 268 314 } 269 - 270 - // Stop enemy spawning 271 - k.cancel("spawnEnemy"); 272 315 273 316 // Wait a moment before showing game over screen 274 317 k.wait(2, () => {
+21
src/player.ts
··· 7 7 health: number; 8 8 maxHealth: number; 9 9 damage(amount: number): void; 10 + heal(amount: number): void; 10 11 attack(): void; 11 12 update(): void; 12 13 } ··· 108 109 109 110 // Emit death event for game over handling 110 111 this.trigger("death"); 112 + } 113 + }, 114 + 115 + // Heal player 116 + heal(this: GameObj, amount: number) { 117 + // Add health but don't exceed max health 118 + health = Math.min(health + amount, maxHealth); 119 + 120 + // Flash green when healed 121 + this.color = k.rgb(0, 255, 0); 122 + 123 + // Reset color after a short time 124 + k.wait(0.1, () => { 125 + this.color = k.rgb(); 126 + }); 127 + 128 + // Update health bar 129 + if (healthBar) { 130 + const healthPercent = Math.max(0, health / maxHealth); 131 + healthBar.width = 60 * healthPercent; 111 132 } 112 133 }, 113 134