[READ-ONLY] Mirror of https://github.com/flo-bit/shadow-shmup. Fun and casual top-down, roguelike shoot 'em up browsergame with shadow elements and colorful neon effects flo-bit.dev/shadow-shmup/
browsergame pixijs rapier2d roguelike shoot-em-up typescript webgame
0

Configure Feed

Select the types of activity you want to include in your feed.

first publish

Florian (Jul 31, 2024, 1:52 PM +0200) cb54bc2d 51b1124d

+772 -112
+26 -2
index.html
··· 30 30 > 31 31 <div></div> 32 32 <div class="flex flex-col items-center"> 33 - <h1 id="title" class="font-bold text-5xl mb-8">shadow shooter</h1> 33 + <h1 id="title" class="font-bold text-5xl mb-8">shadow shmup</h1> 34 34 <button 35 35 id="play" 36 36 class="text-2xl font-semibold border border-white/20 rounded-xl py-2 px-4 bg-white/10 hover:bg-white/20 backdrop-blur-sm mb-4" ··· 46 46 </div> 47 47 <div class="text-white mb-4 flex flex-col items-center gap-4 text-xs"> 48 48 <div class="flex items-center gap-3"> 49 - code by <span class="font-semibold">flo-bit</span> 49 + code and concept by <span class="font-semibold">flo-bit</span> 50 50 <a href="https://github.com/flo-bit" target="_blank"> 51 51 <svg 52 52 fill="currentColor" ··· 75 75 /> 76 76 </svg> 77 77 </a> 78 + 78 79 </div> 80 + 81 + <div class="flex items-center gap-3"> 82 + code and concept by 83 + 84 + <span class="font-semibold">unbedenklich</span> 85 + <a href="https://github.com/unbedenklich" target="_blank"> 86 + <svg 87 + fill="currentColor" 88 + viewBox="0 0 24 24" 89 + aria-hidden="true" 90 + class="w-5 fill-white hover:fill-cyan-400" 91 + > 92 + <path 93 + fill-rule="evenodd" 94 + d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" 95 + clip-rule="evenodd" 96 + /> 97 + </svg> 98 + <span class="sr-only">github link</span> 99 + </a> 100 + </div> 101 + 102 + 79 103 <div class="flex items-center gap-3"> 80 104 music by <span class="font-semibold">nicholas palmer</span> 81 105 <a href="https://discordapp.com/users/702179454818189313/" target="_blank">
+1 -4
src/app.ts
··· 242 242 this.startMusic(); 243 243 244 244 this.playingTime = 0; 245 - 246 - this.upgradeManager.showUpgradeMenu(); 247 - this.paused = true; 248 245 }); 249 246 250 247 const playCoopButton = document.getElementById('play-coop'); ··· 318 315 } 319 316 320 317 if (enemy && weapon) { 321 - this.spawnParticles(weapon.x, weapon.y, 10, weapon.color); 318 + this.spawnParticles(weapon.x, weapon.y, 50, weapon.color); 322 319 323 320 enemy.takeDamage(weapon.damage); 324 321
+1 -1
src/enemy.ts
··· 86 86 if (position) { 87 87 // create random direction vector 88 88 let point = { x: Math.random() - 0.5, y: Math.random() - 0.5 }; 89 - let length = 1000; 89 + let length = 500; 90 90 let norm = Math.sqrt(point.x * point.x + point.y * point.y); 91 91 point.x = (point.x / norm) * length; 92 92 point.y = (point.y / norm) * length;
+3 -3
src/player.ts
··· 92 92 93 93 this.createHealthBar(); 94 94 95 - this.speed = 20000; 95 + this.speed = 16000; 96 96 this.shape = shape; 97 97 98 98 this.weapon = new GunWeapon(this.game, { 99 99 color: this.color, 100 100 lifetime: 2000, 101 - piercing: 0, 102 - fireRate: 1000 101 + piercing: 1, 102 + fireRate: 800 103 103 }); 104 104 105 105 this.isPlayer = true;
+3 -2
src/upgrade-manager.ts
··· 53 53 } 54 54 55 55 addItem(item: Item) { 56 - this.xp += item.value; 56 + let value = item.value * 3; 57 + this.xp += value; 57 58 58 59 // get percentage of needed: 59 - const percentage = ((item.value / this.neededXP) * 100).toFixed(2); 60 + const percentage = ((value / this.neededXP) * 100).toFixed(2); 60 61 // add to UI 61 62 if (this.xpUI) { 62 63 let itemUI = document.createElement('div');
+386 -64
src/upgrades-player.ts
··· 37 37 price: 10 38 38 }, 39 39 { 40 + upgrade: (player: Player) => (player.speed *= 1.5), 41 + perk: 'Movement speed', 42 + perkValue: '+50%', 43 + icon: 'movement', 44 + color: 'text-blue-500', 45 + price: 30 46 + }, 47 + { 48 + upgrade: (player: Player) => (player.speed *= 1.5), 49 + perk: 'Movement speed', 50 + perkValue: '+50%', 51 + icon: 'movement', 52 + color: 'text-blue-500', 53 + price: 60 54 + }, 55 + { 56 + upgrade: (player: Player) => (player.speed *= 2), 57 + perk: 'Movement speed', 58 + perkValue: '+100%', 59 + icon: 'movement', 60 + color: 'text-blue-500', 61 + price: 150 62 + }, 63 + { 40 64 upgrade: (player: Player) => (player.speed *= 1.2), 41 65 perk: 'Movement speed', 42 66 perkValue: '+20%', 43 67 icon: 'movement', 44 68 color: 'text-blue-500', 45 - price: 10 69 + price: 450 46 70 }, 47 71 { 48 72 upgrade: (player: Player) => (player.speed *= 1.2), ··· 50 74 perkValue: '+20%', 51 75 icon: 'movement', 52 76 color: 'text-blue-500', 53 - price: 10 77 + price: 1500 54 78 }, 55 79 { 56 - upgrade: (player: Player) => (player.speed *= 1.2), 80 + upgrade: (player: Player) => (player.speed *= 1.02), 57 81 perk: 'Movement speed', 58 - perkValue: '+20%', 82 + perkValue: '+2%', 59 83 icon: 'movement', 60 84 color: 'text-blue-500', 61 - price: 10 85 + price: 5000 62 86 } 63 87 ]; 64 88 65 89 const maxHealthUpgrade: Upgrade[] = [ 66 90 { 67 - upgrade: (player: Player) => (player.maxHealth *= 1.2), 91 + upgrade: (player: Player) => (player.maxHealth *= 1.5), 68 92 perk: 'Max Health', 69 - perkValue: '+20%', 93 + perkValue: '+50%', 70 94 icon: 'health', 71 95 color: 'text-blue-500', 72 96 price: 10 73 97 }, 74 98 { 75 - upgrade: (player: Player) => (player.maxHealth *= 1.2), 99 + upgrade: (player: Player) => (player.maxHealth *= 1.5), 100 + perk: 'Max Health', 101 + perkValue: '+50%', 102 + icon: 'health', 103 + color: 'text-blue-500', 104 + price: 40 105 + }, 106 + { 107 + upgrade: (player: Player) => (player.maxHealth *= 2), 108 + perk: 'Max Health', 109 + perkValue: '+100%', 110 + icon: 'health', 111 + color: 'text-blue-500', 112 + price: 200 113 + }, 114 + { 115 + upgrade: (player: Player) => (player.maxHealth *= 3), 116 + perk: 'Max Health', 117 + perkValue: '+200%', 118 + icon: 'health', 119 + color: 'text-blue-500', 120 + price: 800 121 + }, 122 + { 123 + upgrade: (player: Player) => (player.maxHealth *= 4), 76 124 perk: 'Max Health', 77 - perkValue: '+20%', 125 + perkValue: '+400%', 78 126 icon: 'health', 79 127 color: 'text-blue-500', 80 - price: 10 128 + price: 2000 81 129 }, 82 130 { 83 - upgrade: (player: Player) => (player.maxHealth *= 1.2), 131 + upgrade: (player: Player) => (player.maxHealth *= 2), 84 132 perk: 'Max Health', 85 - perkValue: '+20%', 133 + perkValue: '+200%', 86 134 icon: 'health', 87 135 color: 'text-blue-500', 88 - price: 10 136 + price: 10000 89 137 }, 90 138 { 91 - upgrade: (player: Player) => (player.maxHealth *= 1.2), 139 + upgrade: (player: Player) => (player.maxHealth *= 1.02), 92 140 perk: 'Max Health', 93 - perkValue: '+20%', 141 + perkValue: '+2%', 94 142 icon: 'health', 95 143 color: 'text-blue-500', 96 - price: 10 144 + price: 50000 97 145 } 98 146 ]; 99 147 ··· 112 160 perkValue: '+20%', 113 161 icon: 'coins', 114 162 color: 'text-blue-500', 115 - price: 10 163 + price: 40 116 164 }, 117 165 { 118 166 upgrade: (player: Player) => (player.coinMagnetRange *= 1.2), ··· 120 168 perkValue: '+20%', 121 169 icon: 'coins', 122 170 color: 'text-blue-500', 123 - price: 10 171 + price: 80 124 172 }, 125 173 { 126 174 upgrade: (player: Player) => (player.coinMagnetRange *= 1.2), ··· 128 176 perkValue: '+20%', 129 177 icon: 'coins', 130 178 color: 'text-blue-500', 131 - price: 10 179 + price: 200 180 + }, 181 + { 182 + upgrade: (player: Player) => (player.coinMagnetRange *= 1.02), 183 + perk: 'Coin Magnet Range', 184 + perkValue: '+2%', 185 + icon: 'coins', 186 + color: 'text-blue-500', 187 + price: 1000 132 188 } 133 189 ]; 134 190 135 - // const playerUpgrades: Upgrade[] = [ 136 - // { 137 - // upgrade: (player: Player) => (player.speed *= 1.2), 138 - // perk: 'Movement speed', 139 - // perkValue: '+20%', 140 - // icon: 'movement', 141 - // color: 'text-blue-500', 142 - // price: 10 143 - // }, 144 - // { 145 - // upgrade: (player: Player) => (player.maxHealth *= 1.2), 146 - // perk: 'Max Health', 147 - // perkValue: '+20%', 148 - // icon: 'health', 149 - // color: 'text-blue-500', 150 - // price: 10 151 - // }, 152 - // { 153 - // upgrade: (player: Player) => (player.coinMagnetRange *= 1.2), 154 - // perk: 'Coin Magnet Range', 155 - // perkValue: '+20%', 156 - // icon: 'coins', 157 - // color: 'text-blue-500', 158 - // price: 10 159 - // } 160 - // ]; 161 - 162 191 const gunUpgrades: Upgrade[] = [ 163 192 { 164 193 upgrade: (player: Player) => (player.weapon.fireRate *= 0.66), ··· 169 198 price: 10 170 199 }, 171 200 { 172 - upgrade: (player: Player) => (player.weapon.damage *= 1.5), 201 + upgrade: (player: Player) => (player.weapon.damage *= 2), 173 202 perk: 'Damage', 174 - perkValue: '+50%', 203 + perkValue: '+100%', 175 204 icon: 'damage', 176 205 color: 'text-blue-500', 177 - price: 10 206 + price: 50 178 207 }, 179 208 { 180 209 upgrade: (player: Player) => (player.weapon.piercing += 1), ··· 182 211 perkValue: '+1', 183 212 icon: 'piercing', 184 213 color: 'text-blue-500', 185 - price: 20 214 + price: 200 186 215 }, 187 216 { 188 - upgrade: (player: Player) => (player.shootingRange *= 1.2), 217 + upgrade: (player: Player) => (player.shootingRange *= 1.5), 189 218 perk: 'Shooting distance', 190 - perkValue: '+20%', 219 + perkValue: '+50%', 191 220 icon: 'shootingRange', 192 221 color: 'text-blue-500', 193 - price: 20 222 + price: 1000 194 223 }, 195 224 { 196 - upgrade: (player: Player) => (player.weapon.projectileSpeed *= 1.2), 225 + upgrade: (player: Player) => (player.weapon.projectileSpeed *= 1.5), 197 226 perk: 'Bullet speed', 198 - perkValue: '+20%', 227 + perkValue: '+50%', 199 228 icon: 'bulletSpeed', 200 229 color: 'text-blue-500', 201 - price: 20 230 + price: 3000 202 231 }, 203 232 { 204 - upgrade: (player: Player) => (player.weapon.fireRate *= 0.75), 233 + upgrade: (player: Player) => (player.weapon.fireRate *= 0.5), 205 234 perk: 'Fire rate', 206 - perkValue: '+33%', 235 + perkValue: '+100%', 207 236 icon: 'fireRate', 208 237 color: 'text-blue-500', 209 - price: 10 238 + price: 10000 210 239 }, 211 240 { 212 - upgrade: (player: Player) => (player.weapon.damage *= 1.5), 241 + upgrade: (player: Player) => (player.weapon.damage *= 3), 213 242 perk: 'Damage', 214 - perkValue: '+50%', 243 + perkValue: '+200%', 215 244 icon: 'damage', 216 245 color: 'text-blue-500', 217 - price: 20 246 + price: 40000 247 + }, 248 + { 249 + upgrade: (player: Player) => (player.weapon.piercing += 4), 250 + perk: 'Piercing', 251 + perkValue: '+4', 252 + icon: 'piercing', 253 + color: 'text-blue-500', 254 + price: 100000 255 + }, 256 + { 257 + upgrade: (player: Player) => (player.shootingRange *= 2), 258 + perk: 'Shooting distance', 259 + perkValue: '+100%', 260 + icon: 'shootingRange', 261 + color: 'text-blue-500', 262 + price: 300000 263 + }, 264 + { 265 + upgrade: (player: Player) => (player.weapon.projectileSpeed *= 2), 266 + perk: 'Bullet speed', 267 + perkValue: '+100%', 268 + icon: 'bulletSpeed', 269 + color: 'text-blue-500', 270 + price: 1000000 271 + }, 272 + { 273 + upgrade: (player: Player) => (player.weapon.damage *= 1.02), 274 + perk: 'Damage', 275 + perkValue: '+2%', 276 + icon: 'damage', 277 + color: 'text-blue-500', 278 + price: 2000000 218 279 } 219 280 ]; 220 281 ··· 261 322 upgrade: (player: Player) => { 262 323 // find chainsaw weapon 263 324 const chainsaw = new BallWeapon(player.game, player.color); 264 - chainsaw.distance = 100; 325 + chainsaw.distance = 150; 326 + 327 + // find chainsaw weapon 328 + let oldChainsaw = player.weapons.find((w) => w instanceof BallWeapon); 329 + if (oldChainsaw) { 330 + chainsaw.damage = oldChainsaw.damage; 331 + chainsaw.speed = oldChainsaw.speed; 332 + chainsaw.angle = oldChainsaw.angle + (Math.PI * 2) / 3; 333 + } 265 334 player.weapons.push(chainsaw); 266 335 }, 267 336 perk: 'Chainsaw', 268 337 perkValue: '+1', 269 338 icon: 'new', 270 339 color: 'text-red-500', 271 - price: 200 340 + price: 800 341 + }, 342 + { 343 + upgrade: (player: Player) => { 344 + // for all chainsaws 345 + player.weapons.forEach((w) => { 346 + if (w instanceof BallWeapon) { 347 + w.speed *= 2; 348 + } 349 + }); 350 + }, 351 + perk: 'Chainsaw Speed', 352 + perkValue: '+100%', 353 + icon: 'new', 354 + color: 'text-red-500', 355 + price: 1600 356 + }, 357 + { 358 + upgrade: (player: Player) => { 359 + // find chainsaw weapon 360 + player.weapons.forEach((w) => { 361 + if (w instanceof BallWeapon) { 362 + w.damage *= 2; 363 + } 364 + }); 365 + }, 366 + perk: 'Chainsaw Damage', 367 + perkValue: '+100%', 368 + icon: 'new', 369 + color: 'text-red-500', 370 + price: 3200 371 + }, 372 + { 373 + upgrade: (player: Player) => { 374 + // find chainsaw weapon 375 + const chainsaw = new BallWeapon(player.game, player.color); 376 + chainsaw.distance = 200; 377 + 378 + // find chainsaw weapon 379 + let oldChainsaw = player.weapons.find((w) => w instanceof BallWeapon); 380 + if (oldChainsaw) { 381 + chainsaw.damage = oldChainsaw.damage; 382 + chainsaw.speed = oldChainsaw.speed; 383 + chainsaw.angle = oldChainsaw.angle + (Math.PI * 4) / 3; 384 + } 385 + player.weapons.push(chainsaw); 386 + }, 387 + perk: 'Chainsaw', 388 + perkValue: '+1', 389 + icon: 'new', 390 + color: 'text-red-500', 391 + price: 6400 392 + }, 393 + { 394 + upgrade: (player: Player) => { 395 + // for all chainsaws 396 + player.weapons.forEach((w) => { 397 + if (w instanceof BallWeapon) { 398 + w.speed *= 2; 399 + } 400 + }); 401 + }, 402 + perk: 'Chainsaw Speed', 403 + perkValue: '+100%', 404 + icon: 'new', 405 + color: 'text-red-500', 406 + price: 10000 407 + }, 408 + { 409 + upgrade: (player: Player) => { 410 + // find chainsaw weapon 411 + player.weapons.forEach((w) => { 412 + if (w instanceof BallWeapon) { 413 + w.damage *= 2; 414 + } 415 + }); 416 + }, 417 + perk: 'Chainsaw Damage', 418 + perkValue: '+100%', 419 + icon: 'new', 420 + color: 'text-red-500', 421 + price: 30000 422 + }, 423 + { 424 + upgrade: (player: Player) => { 425 + player.weapons.forEach((w) => { 426 + if (w instanceof BallWeapon) { 427 + w.damage *= 1.02; 428 + } 429 + }); 430 + }, 431 + perk: 'Chainsaw Damage', 432 + perkValue: '+2%', 433 + icon: 'new', 434 + color: 'text-red-500', 435 + price: 100000 272 436 } 273 437 ]; 274 438 ··· 282 446 icon: 'new', 283 447 color: 'text-red-500', 284 448 price: 10 449 + }, 450 + { 451 + upgrade: (player: Player) => { 452 + // find knife weapon 453 + let knife = player.weapons.find((w) => w instanceof Knife); 454 + if (knife) { 455 + knife.speed *= 2; 456 + } 457 + }, 458 + perk: 'Knife Speed', 459 + perkValue: '+100%', 460 + icon: 'new', 461 + color: 'text-red-500', 462 + price: 30 463 + }, 464 + { 465 + upgrade: (player: Player) => { 466 + // find knife weapon 467 + let knife = player.weapons.find((w) => w instanceof Knife); 468 + if (knife) { 469 + knife.damage *= 2; 470 + } 471 + }, 472 + perk: 'Knife Damage', 473 + perkValue: '+100%', 474 + icon: 'new', 475 + color: 'text-red-500', 476 + price: 70 477 + }, 478 + { 479 + upgrade: (player: Player) => { 480 + // find knife weapon 481 + let knife = player.weapons.find((w) => w instanceof Knife); 482 + if (knife) { 483 + knife.distance *= 2; 484 + } 485 + }, 486 + perk: 'Knife Distance', 487 + perkValue: '+100%', 488 + icon: 'new', 489 + color: 'text-red-500', 490 + price: 200 491 + }, 492 + { 493 + upgrade: (player: Player) => { 494 + let knife = new Knife(player.game, player.color); 495 + 496 + // find knife weapon 497 + let oldKnife = player.weapons.find((w) => w instanceof Knife); 498 + if (oldKnife) { 499 + knife.damage = oldKnife.damage; 500 + knife.speed = oldKnife.speed; 501 + knife.angle = oldKnife.angle + (Math.PI * 2) / 3; 502 + knife.distance = oldKnife.distance; 503 + } 504 + 505 + player.weapons.push(knife); 506 + }, 507 + perk: 'Knife', 508 + perkValue: 'New Weapon', 509 + icon: 'new', 510 + color: 'text-red-500', 511 + price: 600 512 + }, 513 + { 514 + upgrade: (player: Player) => { 515 + // for all knives 516 + player.weapons.forEach((w) => { 517 + if (w instanceof Knife) { 518 + w.speed *= 2; 519 + } 520 + }); 521 + }, 522 + perk: 'Knife Speed', 523 + perkValue: '+100%', 524 + icon: 'new', 525 + color: 'text-red-500', 526 + price: 1500 527 + }, 528 + { 529 + upgrade: (player: Player) => { 530 + // find knife weapon 531 + player.weapons.forEach((w) => { 532 + if (w instanceof Knife) { 533 + w.damage *= 2; 534 + } 535 + }); 536 + }, 537 + perk: 'Knife Damage', 538 + perkValue: '+100%', 539 + icon: 'new', 540 + color: 'text-red-500', 541 + price: 4000 542 + }, 543 + { 544 + upgrade: (player: Player) => { 545 + let knife = new Knife(player.game, player.color); 546 + 547 + // find knife weapon 548 + let oldKnife = player.weapons.find((w) => w instanceof Knife); 549 + if (oldKnife) { 550 + knife.damage = oldKnife.damage; 551 + knife.speed = oldKnife.speed; 552 + knife.angle = oldKnife.angle + (Math.PI * 4) / 3; 553 + knife.distance = oldKnife.distance; 554 + } 555 + 556 + player.weapons.push(knife); 557 + }, 558 + perk: 'Knife', 559 + perkValue: 'New Weapon', 560 + icon: 'new', 561 + color: 'text-red-500', 562 + price: 30000 563 + }, 564 + { 565 + upgrade: (player: Player) => { 566 + // for all knives 567 + player.weapons.forEach((w) => { 568 + if (w instanceof Knife) { 569 + w.speed *= 2; 570 + } 571 + }); 572 + }, 573 + perk: 'Knife Speed', 574 + perkValue: '+100%', 575 + icon: 'new', 576 + color: 'text-red-500', 577 + price: 100000 578 + }, 579 + { 580 + upgrade: (player: Player) => { 581 + // find knife weapon 582 + player.weapons.forEach((w) => { 583 + if (w instanceof Knife) { 584 + w.damage *= 2; 585 + } 586 + }); 587 + }, 588 + perk: 'Knife Damage', 589 + perkValue: '+100%', 590 + icon: 'new', 591 + color: 'text-red-500', 592 + price: 200000 593 + }, 594 + { 595 + upgrade: (player: Player) => { 596 + player.weapons.forEach((w) => { 597 + if (w instanceof Knife) { 598 + w.damage *= 1.02; 599 + } 600 + }); 601 + }, 602 + perk: 'Knife Damage', 603 + perkValue: '+2%', 604 + icon: 'new', 605 + color: 'text-red-500', 606 + price: 1000000 285 607 } 286 608 ]; 287 609
+346 -30
src/wave.ts
··· 35 35 this.isActive = true; 36 36 } 37 37 38 - if (this.isActive) { 39 - this.enemies.forEach((enemy, index) => { 40 - this.spawnAccumulators[index] += deltaTimeSeconds; 41 - const spawnInterval = 1 / enemy.spawnRate; 38 + // if (this.isActive) { 39 + this.enemies.forEach((enemy, index) => { 40 + this.spawnAccumulators[index] += deltaTimeSeconds; 41 + const spawnInterval = 1 / enemy.spawnRate; 42 + 43 + while (this.spawnAccumulators[index] >= spawnInterval) { 44 + if (!enemy.maxCount || this.enemyCounts[index] < enemy.maxCount) { 45 + let spawned = this.spawnEnemy(enemy.type); 46 + 47 + // if (index === 0 && spawned) { 48 + // // triple speed 49 + // spawned.speed *= 3; 50 + // } 42 51 43 - while (this.spawnAccumulators[index] >= spawnInterval) { 44 - if (!enemy.maxCount || this.enemyCounts[index] < enemy.maxCount) { 45 - this.spawnEnemy(enemy.type); 46 - this.enemyCounts[index]++; 47 - } 48 - this.spawnAccumulators[index] -= spawnInterval; 52 + this.enemyCounts[index]++; 49 53 } 50 - }); 51 - } 54 + this.spawnAccumulators[index] -= spawnInterval; 55 + } 56 + }); 57 + // } 52 58 } 53 59 54 60 spawnEnemy(enemyType: typeof Enemy) { ··· 58 64 const upgrades = this.game.waveManager?.getEnemyUpgrades(enemyType) ?? []; 59 65 upgrades.forEach((upgrade) => upgrade(enemy)); 60 66 } 67 + return enemy; 61 68 } 62 69 } 63 70 ··· 139 146 140 147 // Example usage: 141 148 const exampleWaves: WaveData[] = [ 149 + // wave 1 142 150 { 143 151 enemies: [ 144 152 { 145 153 type: SphereEnemy, 146 154 spawnRate: 1, 147 155 upgradeFunction: (enemy) => { 148 - enemy.health = 20; 149 - enemy.value = 3; 156 + enemy.health *= 1.8; 157 + enemy.value *= 3; 150 158 } 151 159 }, 152 160 { 153 161 type: TriangleEnemy, 154 162 spawnRate: 1, 155 163 upgradeFunction: (enemy) => { 156 - enemy.speed *= 1.2; 157 - enemy.value = 2; 164 + enemy.speed *= 1.3; 165 + enemy.value *= 2.5; 158 166 } 159 167 } 160 168 ], 161 169 startDelay: 3, 162 170 neededItems: 10 163 171 }, 172 + // wave 2 164 173 { 165 174 enemies: [ 166 175 { 167 176 type: SphereEnemy, 168 177 spawnRate: 1, 169 178 upgradeFunction: (enemy) => { 170 - enemy.health = 30; 171 - enemy.value += 1; 179 + enemy.health *= 2; 180 + enemy.value *= 2; 172 181 if (enemy instanceof SphereEnemy) { 173 182 enemy.burstNumber *= 1.3; 174 183 } ··· 179 188 spawnRate: 0.1, 180 189 upgradeFunction: (enemy) => { 181 190 if (enemy instanceof PentagonEnemy) { 182 - enemy.weapon.fireRate *= 0.9; 191 + enemy.weapon.fireRate *= 0.8; 183 192 } 193 + 194 + enemy.value *= 3; 184 195 } 185 196 } 186 197 ], 187 198 startDelay: 3, 188 199 neededItems: 20 189 200 }, 201 + // wave 3 190 202 { 191 203 enemies: [ 192 204 { 193 205 type: PentagonEnemy, 194 206 spawnRate: 1, 195 207 upgradeFunction: (enemy) => { 196 - enemy.health *= 1.5; 208 + enemy.health *= 1.4; 209 + 210 + enemy.value *= 2; 197 211 } 198 212 }, 199 213 { 200 214 type: TriangleEnemy, 201 215 spawnRate: 2, 202 216 upgradeFunction: (enemy) => { 203 - enemy.speed *= 1.1; 204 - enemy.value *= 1.5; 217 + enemy.speed *= 1.3; 218 + 219 + enemy.value *= 3; 205 220 } 206 221 } 207 222 ], 208 223 startDelay: 3, 209 224 neededItems: 50 210 225 }, 226 + // wave 4 211 227 { 212 228 enemies: [ 213 229 { 214 230 type: SphereEnemy, 215 - spawnRate: 3, 231 + spawnRate: 0.6, 216 232 upgradeFunction: (enemy) => { 217 - enemy.value *= 1.5; 233 + enemy.value *= 3; 234 + 218 235 if (enemy instanceof SphereEnemy) { 219 - enemy.weapon.damage *= 1.5; 236 + enemy.weapon.damage *= 2; 220 237 enemy.burstNumber *= 1.5; 221 - if(enemy.weapon.lifetime) enemy.weapon.lifetime *= 1.5; 238 + if (enemy.weapon.lifetime) enemy.weapon.lifetime *= 1.5; 222 239 } 223 240 } 224 241 }, 225 242 { 226 243 type: TriangleEnemy, 227 - spawnRate: 3, 244 + spawnRate: 0.6, 228 245 upgradeFunction: (enemy) => { 229 - enemy.value *= 1.5; 246 + enemy.value *= 2; 247 + 230 248 enemy.speed *= 1.2; 231 249 if (enemy instanceof TriangleEnemy) { 232 250 enemy.projectile.damage *= 2; ··· 235 253 }, 236 254 { 237 255 type: PentagonEnemy, 256 + spawnRate: 0.6, 257 + upgradeFunction: (enemy) => { 258 + enemy.value *= 3; 259 + 260 + if (enemy instanceof PentagonEnemy) { 261 + enemy.weapon.damage *= 2; 262 + enemy.health *= 1.5; 263 + } 264 + } 265 + } 266 + ], 267 + startDelay: 3, 268 + neededItems: 100 269 + }, 270 + // wave 5 271 + { 272 + enemies: [ 273 + { 274 + type: PentagonEnemy, 275 + spawnRate: 1, 276 + upgradeFunction: (enemy) => { 277 + enemy.value *= 4; 278 + 279 + if (enemy instanceof PentagonEnemy) { 280 + enemy.weapon.damage *= 1.5; 281 + } 282 + } 283 + } 284 + ], 285 + startDelay: 3, 286 + neededItems: 300 287 + }, 288 + // wave 6 289 + { 290 + enemies: [ 291 + { 292 + type: TriangleEnemy, 238 293 spawnRate: 3, 239 294 upgradeFunction: (enemy) => { 240 - enemy.value *= 1.5; 295 + enemy.value *= 4; 296 + 297 + if (enemy instanceof TriangleEnemy) { 298 + enemy.speed *= 1.5; 299 + enemy.projectile.damage *= 2; 300 + enemy.health *= 1.7; 301 + } 302 + } 303 + } 304 + ], 305 + startDelay: 3, 306 + neededItems: 500 307 + }, 308 + // wave 7 309 + { 310 + enemies: [ 311 + { 312 + type: SphereEnemy, 313 + spawnRate: 3, 314 + upgradeFunction: (enemy) => { 315 + enemy.value *= 3; 316 + 317 + if (enemy instanceof SphereEnemy) { 318 + enemy.speed *= 1.5; 319 + enemy.health *= 1.2; 320 + enemy.burstNumber *= 1.5; 321 + enemy.weapon.damage *= 1.5; 322 + } 323 + } 324 + } 325 + ], 326 + startDelay: 3, 327 + neededItems: 1000 328 + }, 329 + // wave 8 330 + { 331 + enemies: [ 332 + { 333 + type: SphereEnemy, 334 + spawnRate: 2, 335 + upgradeFunction: (enemy) => { 336 + enemy.value *= 3; 337 + 338 + if (enemy instanceof SphereEnemy) { 339 + enemy.speed *= 1.5; 340 + enemy.health *= 1.2; 341 + enemy.burstNumber *= 1.5; 342 + enemy.weapon.damage *= 1.5; 343 + } 344 + } 345 + }, 346 + { 347 + type: PentagonEnemy, 348 + spawnRate: 2, 349 + upgradeFunction: (enemy) => { 350 + enemy.value *= 3; 351 + 241 352 if (enemy instanceof PentagonEnemy) { 353 + enemy.speed *= 1.5; 354 + enemy.health *= 1.2; 242 355 enemy.weapon.damage *= 1.5; 356 + enemy.weapon.fireRate *= 0.8; 243 357 } 244 358 } 245 359 } 246 360 ], 247 361 startDelay: 3, 248 - neededItems: 100 362 + neededItems: 2000 363 + }, 364 + // wave 9 365 + { 366 + enemies: [ 367 + { 368 + type: SphereEnemy, 369 + spawnRate: 2, 370 + upgradeFunction: (enemy) => { 371 + enemy.value *= 4; 372 + 373 + if (enemy instanceof SphereEnemy) { 374 + enemy.speed *= 2; 375 + enemy.health *= 1.4; 376 + } 377 + } 378 + } 379 + ], 380 + startDelay: 3, 381 + neededItems: 4000 382 + }, 383 + // wave 10 384 + { 385 + enemies: [ 386 + { 387 + type: TriangleEnemy, 388 + spawnRate: 4, 389 + upgradeFunction: (enemy) => { 390 + enemy.value *= 3; 391 + 392 + if (enemy instanceof SphereEnemy) { 393 + enemy.speed *= 1.5; 394 + enemy.health *= 1.5; 395 + } 396 + } 397 + } 398 + ], 399 + startDelay: 3, 400 + neededItems: 10000 401 + }, 402 + // wave 11 403 + { 404 + enemies: [ 405 + { 406 + type: PentagonEnemy, 407 + spawnRate: 4, 408 + upgradeFunction: (enemy) => { 409 + enemy.value *= 5; 410 + 411 + if (enemy instanceof SphereEnemy) { 412 + enemy.speed *= 1.5; 413 + enemy.health *= 1.3; 414 + enemy.weapon.damage *= 2; 415 + } 416 + } 417 + } 418 + ], 419 + startDelay: 3, 420 + neededItems: 20000 421 + }, 422 + // wave 12 423 + { 424 + enemies: [ 425 + { 426 + type: TriangleEnemy, 427 + spawnRate: 3, 428 + upgradeFunction: (enemy) => { 429 + enemy.value *= 3; 430 + 431 + if (enemy instanceof TriangleEnemy) { 432 + enemy.speed *= 2; 433 + enemy.health *= 1.2; 434 + } 435 + } 436 + }, 437 + { 438 + type: SphereEnemy, 439 + spawnRate: 3, 440 + upgradeFunction: (enemy) => { 441 + enemy.value *= 4; 442 + 443 + if (enemy instanceof SphereEnemy) { 444 + enemy.weapon.damage *= 1.5; 445 + enemy.health *= 1.5; 446 + enemy.burstNumber *= 1.5; 447 + } 448 + } 449 + } 450 + ], 451 + startDelay: 3, 452 + neededItems: 40000 453 + }, 454 + // wave 13 455 + { 456 + enemies: [ 457 + { 458 + type: TriangleEnemy, 459 + spawnRate: 3, 460 + upgradeFunction: (enemy) => { 461 + enemy.value *= 3; 462 + 463 + if (enemy instanceof TriangleEnemy) { 464 + enemy.speed *= 2; 465 + enemy.health *= 1.2; 466 + } 467 + } 468 + }, 469 + { 470 + type: SphereEnemy, 471 + spawnRate: 3, 472 + upgradeFunction: (enemy) => { 473 + enemy.value *= 4; 474 + 475 + if (enemy instanceof SphereEnemy) { 476 + enemy.weapon.damage *= 1.5; 477 + enemy.health *= 2; 478 + enemy.burstNumber *= 1.5; 479 + } 480 + } 481 + }, 482 + { 483 + type: PentagonEnemy, 484 + spawnRate: 4, 485 + upgradeFunction: (enemy) => { 486 + enemy.value *= 5; 487 + 488 + if (enemy instanceof SphereEnemy) { 489 + enemy.speed *= 1.5; 490 + enemy.health *= 2; 491 + enemy.weapon.fireRate *= 0.6; 492 + enemy.weapon.damage *= 2; 493 + } 494 + } 495 + } 496 + ], 497 + startDelay: 3, 498 + neededItems: 80000 499 + }, 500 + // wave 14 501 + { 502 + enemies: [ 503 + { 504 + type: TriangleEnemy, 505 + spawnRate: 5, 506 + upgradeFunction: (enemy) => { 507 + enemy.value *= 3; 508 + 509 + if (enemy instanceof TriangleEnemy) { 510 + enemy.speed *= 2; 511 + enemy.health *= 1.2; 512 + } 513 + } 514 + }, 515 + { 516 + type: SphereEnemy, 517 + spawnRate: 5, 518 + upgradeFunction: (enemy) => { 519 + enemy.value *= 4; 520 + 521 + if (enemy instanceof SphereEnemy) { 522 + enemy.weapon.damage *= 1.5; 523 + enemy.health *= 1.5; 524 + enemy.burstNumber *= 1.5; 525 + } 526 + } 527 + }, 528 + { 529 + type: PentagonEnemy, 530 + spawnRate: 3, 531 + upgradeFunction: (enemy) => { 532 + enemy.value *= 3; 533 + 534 + if (enemy instanceof SphereEnemy) { 535 + enemy.speed *= 1.5; 536 + enemy.health *= 2; 537 + enemy.weapon.fireRate *= 0.6; 538 + enemy.weapon.damage *= 2; 539 + } 540 + } 541 + } 542 + ], 543 + startDelay: 3, 544 + neededItems: 80000 545 + }, 546 + // wave 15 547 + { 548 + enemies: [ 549 + { 550 + type: SphereEnemy, 551 + spawnRate: 8, 552 + upgradeFunction: (enemy) => { 553 + enemy.value *= 4; 554 + 555 + if (enemy instanceof SphereEnemy) { 556 + enemy.weapon.damage *= 1.5; 557 + enemy.health *= 1.5; 558 + enemy.burstNumber *= 1.5; 559 + } 560 + } 561 + } 562 + ], 563 + startDelay: 3, 564 + neededItems: 100000 249 565 } 250 566 ];
+2 -2
src/weapons/ball.ts
··· 9 9 * ball that flies in a circle around player 10 10 */ 11 11 export class BallWeapon extends Weapon { 12 - distance: number = 200; 13 - speed: number = 0.001; 12 + distance: number = 100; 13 + speed: number = 0.002; 14 14 angle: number = 0; 15 15 16 16 constructor(game: Game, color: number) {
+3 -3
src/weapons/knife.ts
··· 9 9 * triangle that spins and goes to left and right of player 10 10 */ 11 11 export class Knife extends Weapon { 12 - speed: number = 0.006; 13 - distance: number = 300; 12 + speed: number = 0.003; 13 + distance: number = 150; 14 14 current: number = 0; 15 15 16 - angle: number = 0; 16 + angle: number = 1; 17 17 18 18 direction: 'left' | 'right' | 'both' = 'both'; 19 19
+1 -1
src/weapons/weapon.ts
··· 10 10 11 11 size: number = 10; 12 12 13 - damage: number = 20; 13 + damage: number = 10; 14 14 15 15 color: number; 16 16