User prompt
Reduce the boss's health by half
User prompt
My player keeps firing
User prompt
After each wave, the boss comes
User prompt
Let the game continue normally and the boss come after each wave.
User prompt
High score should not be reset
User prompt
high score keep the last highest score
User prompt
add high score in the top right corner
User prompt
add game boss
User prompt
Continue the game as normal and the boss will appear at the end of each wave.
User prompt
fix all bugs and optimize the game
User prompt
remove boss from game
User prompt
At the end of each wave there will be a boss
User prompt
A boss comes in every wave
User prompt
Reduce the boss's health to half
User prompt
the next wave is not coming fix it
User prompt
detect and fix bugs in the game
User prompt
Reduce the boss's health a little bit
User prompt
bullets pass through the boot fix that
User prompt
My character does not fire when the boss comes, fix it
User prompt
Please fix the bug: 'ReferenceError: Boss is not defined' in or related to this line: 'boss = new Boss();' Line Number: 525
User prompt
At the end of each wave there will be a boss
User prompt
Fix background stars change color every 2 waves code
User prompt
Increase firing speed by 0.15 times with each wave
User prompt
Increase fire rate by 0.20x every 2 waves
User prompt
Increase fire rate by 0.15x every 2 waves
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Alien class var Alien = Container.expand(function () { var self = Container.call(this); // Attach a default sprite, but allow it to be replaced after construction var alienSprite = self.attachAsset('alien', { anchorX: 0.5, anchorY: 0.5 }); self.width = alienSprite.width; self.height = alienSprite.height; self.speed = 2.5; self.hp = 1; self.wave = 1; self.lastX = self.x; self.lastY = self.y; self.lastIntersecting = false; self.isDead = false; self.update = function () { self.lastY = self.y; self.y += self.speed; }; return self; }); // Bonus box class var BonusBox = Container.expand(function () { var self = Container.call(this); var bonusSprite = self.attachAsset('bonus', { anchorX: 0.5, anchorY: 0.5 }); self.width = bonusSprite.width; self.height = bonusSprite.height; self.lastY = self.y; self.lastIntersecting = false; self.type = null; // Set on spawn self.fallSpeed = 10; // Speed at which the bonus moves toward the player self.update = function () { // Move toward the player's current position if (typeof player !== "undefined" && player !== null) { var dx = player.x - self.x; var dy = player.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 2) { // Normalize and move toward player self.x += dx / dist * self.fallSpeed; self.y += dy / dist * self.fallSpeed; } } }; return self; }); // Crystal class var Crystal = Container.expand(function () { var self = Container.call(this); var crystalSprite = self.attachAsset('crystal', { anchorX: 0.5, anchorY: 0.5 }); self.width = crystalSprite.width; self.height = crystalSprite.height; self.lastY = self.y; self.lastIntersecting = false; self.fallSpeed = 12; // Speed at which the crystal falls toward the player self.update = function () { // Move toward the player's current position if (typeof player !== "undefined" && player !== null) { var dx = player.x - self.x; var dy = player.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 2) { // Normalize and move toward player self.x += dx / dist * self.fallSpeed; self.y += dy / dist * self.fallSpeed; } } }; return self; }); // Laser class var Laser = Container.expand(function () { var self = Container.call(this); var laserSprite = self.attachAsset('laser', { anchorX: 0.5, anchorY: 1 }); self.width = laserSprite.width; self.height = laserSprite.height; self.speed = 32; self.pierce = false; self.lastY = self.y; self.lastIntersecting = false; self.update = function () { self.y -= self.speed; }; return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); var playerSprite = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.width = playerSprite.width; self.height = playerSprite.height; self.shootCooldown = 0; self.moveSpeed = 32; // px per tick when dragged self.leftLimit = 0 + self.width / 2 + 40; self.rightLimit = 2048 - self.width / 2 - 40; self.powered = false; self.powerTimer = 0; self.powerType = null; // For powerup visuals self.setPower = function (type, duration) { self.powered = true; self.powerType = type; self.powerTimer = duration; if (type === 'rapid') { playerSprite.tint = 0xffe100; } else if (type === 'pierce') { playerSprite.tint = 0x00ffb0; } else if (type === 'shield') { playerSprite.tint = 0x00eaff; } }; self.clearPower = function () { self.powered = false; self.powerType = null; self.powerTimer = 0; playerSprite.tint = 0xffffff; }; self.update = function () { if (self.powered) { self.powerTimer--; if (self.powerTimer <= 0) { self.clearPower(); } } }; return self; }); // Star class for background stars var Star = Container.expand(function () { var self = Container.call(this); // Use a white ellipse as a star, randomize size (doubled) var size = randInt(4, 12); var starSprite = self.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: size / 100, scaleY: size / 100, tint: 0xffffff }); self.starSprite = starSprite; // Store for tinting self.width = size; self.height = size; // Double the speed range self.speed = randInt(1, 4) * 0.4; // doubled speed for parallax self.alpha = Math.random() * 0.5 + 0.5; self.setColor = function (color) { if (self.starSprite) self.starSprite.tint = color; }; self.update = function () { self.y += self.speed; if (self.y > GAME_HEIGHT + self.height) { self.y = -self.height; self.x = randInt(0, GAME_WIDTH); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Music // Sound effects // Bonus box // Crystal (collectible) // Player bullet (laser) // Alien (enemy) // Player // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; // --- Starfield background --- // Star color palette (cycle every 2 waves) var STAR_COLORS = [0xffffff, // white 0xffe100, // yellow 0x00eaff, // cyan 0xff00cc, // magenta 0x00ffb0, // green 0xffa500, // orange 0xAAFFFF, // light blue 0xff0000 // red ]; function getStarColorForWave(wave) { var idx = Math.floor((wave - 1) / 2) % STAR_COLORS.length; return STAR_COLORS[idx]; } var NUM_STARS = 160; var stars = []; for (var i = 0; i < NUM_STARS; i++) { var star = new Star(); star.x = randInt(0, GAME_WIDTH); star.y = randInt(0, GAME_HEIGHT); stars.push(star); game.addChild(star); } var GROUND_Y = GAME_HEIGHT - 220; var PLAYER_START_X = GAME_WIDTH / 2; var PLAYER_START_Y = GROUND_Y; var PLAYER_MIN_X = 160 + 40; var PLAYER_MAX_X = GAME_WIDTH - 160 - 40; var ENEMY_START_X_MIN = 160; var ENEMY_START_X_MAX = GAME_WIDTH - 160; // Define Y spawn range for enemies (top margin to bottom margin for bonus box spawn) var ENEMY_START_Y_MIN = 0; var ENEMY_START_Y_MAX = GAME_HEIGHT - 400; // Define 3 fixed road X positions for aliens to spawn and move along (top to bottom) var ROAD_X_POSITIONS = [ENEMY_START_X_MIN + Math.floor((ENEMY_START_X_MAX - ENEMY_START_X_MIN) * 0.2), ENEMY_START_X_MIN + Math.floor((ENEMY_START_X_MAX - ENEMY_START_X_MIN) * 0.5), ENEMY_START_X_MIN + Math.floor((ENEMY_START_X_MAX - ENEMY_START_X_MIN) * 0.8)]; var LASER_COOLDOWN = 18; // ticks var LASER_COOLDOWN_RAPID = 6; // Track current firing cooldown, increases as waves progress var currentLaserCooldown = LASER_COOLDOWN; var currentLaserCooldownRapid = LASER_COOLDOWN_RAPID; var CRYSTAL_COLLECT_DIST = 120; var BONUS_COLLECT_DIST = 120; var CRYSTAL_MOVE_STEP = 180; // How much movement area expands per crystal var MAX_CRYSTALS = 8; var WAVE_ENEMY_BASE = 10; var WAVE_ENEMY_INC = 5; // Increase by 5 each wave var WAVE_SPEED_INC = 0.10; var WAVE_HP_INC = 1; var BONUS_WAVE_INTERVAL = 3; var POWERUP_DURATION = 360; // 6 seconds at 60fps // Game state var player = null; var aliens = []; var lasers = []; var crystals = []; var bonuses = []; var boss = null; var bossActive = false; var bossDefeated = false; var dragNode = null; var dragOffsetX = 0; var dragOffsetY = 0; var lastMoveX = 0; var lastMoveY = 0; var lastAlienSpawnTick = 0; var wave = 1; var enemiesLeft = 0; var enemiesToSpawn = 0; var enemiesKilled = 0; var aliensKilledThisWave = 0; // Track aliens killed in current wave var crystalsCollected = 0; var leftLimit = PLAYER_MIN_X; var rightLimit = PLAYER_MAX_X; var bonusActive = false; var bonusType = null; // Double shot state for player bonus var doubleShotActive = false; var doubleShotTimer = 0; // Removed score and scoreTxt, replaced by crystalTxt var waveTxt = null; var powerupTxt = null; var gameOver = false; var youWin = false; // GUI // Crystal icon in upper left (avoid top left 100x100 for menu) // Crystal icon and count, aligned and sized together var crystalIcon = LK.getAsset('crystal', { anchorX: 0, anchorY: 0.5 }); crystalIcon.x = 20; crystalIcon.y = 160 + 40; // center of 80px icon at 160+40=200 crystalIcon.width = 100; crystalIcon.height = 100; LK.gui.topLeft.addChild(crystalIcon); // Crystal count text, vertically centered with icon, same height var crystalTxt = new Text2('0', { size: 100, fill: 0x00eaff }); crystalTxt.anchor.set(0, 0.5); crystalTxt.x = crystalIcon.x + crystalIcon.width + 24; crystalTxt.y = crystalIcon.y; LK.gui.topLeft.addChild(crystalTxt); waveTxt = new Text2('Wave 1', { size: 80, fill: 0xAAFFFF }); waveTxt.anchor.set(0.5, 0); LK.gui.top.addChild(waveTxt); waveTxt.y = 120; powerupTxt = new Text2('', { size: 70, fill: 0xFFE100 }); powerupTxt.anchor.set(0.5, 0); LK.gui.top.addChild(powerupTxt); powerupTxt.y = 220; // Start music LK.playMusic('bgmusic'); // Spawn player player = new Player(); player.x = PLAYER_START_X; player.y = PLAYER_START_Y; game.addChild(player); // Set initial movement limits leftLimit = player.leftLimit; rightLimit = player.rightLimit; // Start first wave function startWave(waveNum) { wave = waveNum; waveTxt.setText('Wave ' + wave); // Remove previous boss if any if (boss && boss.parent) { boss.destroy(); } boss = null; bossActive = false; bossDefeated = false; // Set enemiesToSpawn to 30 for each wave, so wave increases every 30 aliens enemiesToSpawn = 30; enemiesLeft = enemiesToSpawn; lastAlienSpawnTick = LK.ticks; aliensKilledThisWave = 0; // Reset for new wave // Change star color every 2 waves var starColor = getStarColorForWave(waveNum); for (var i = 0; i < stars.length; i++) { stars[i].setColor(starColor); } // Reset firing speed to base values every wave, then increase firing speed by 0.15x per wave currentLaserCooldown = Math.max(2, Math.round(LASER_COOLDOWN * Math.pow(0.85, wave - 1))); currentLaserCooldownRapid = Math.max(1, Math.round(LASER_COOLDOWN_RAPID * Math.pow(0.85, wave - 1))); } // Set initial star color var initialStarColor = getStarColorForWave(1); for (var i = 0; i < stars.length; i++) { stars[i].setColor(initialStarColor); } startWave(1); // Utility: clamp function clamp(val, min, max) { if (val < min) return min; if (val > max) return max; return val; } // Utility: random int function randInt(min, max) { return min + Math.floor(Math.random() * (max - min + 1)); } // Utility: random powerup function randomPowerup() { var arr = ['rapid', 'pierce', 'shield']; return arr[randInt(0, arr.length - 1)]; } // Handle movement (dragging) function handleMove(x, y, obj) { if (dragNode === player) { // Clamp to current movement limits var newX = clamp(x, leftLimit, rightLimit); player.x = newX; lastMoveX = newX; lastMoveY = player.y; } } game.move = handleMove; game.down = function (x, y, obj) { // Only allow drag if touch/click is on player or below if (y > GROUND_Y - 200) { dragNode = player; handleMove(x, y, obj); } }; game.up = function (x, y, obj) { dragNode = null; }; // Main game update game.update = function () { // Update background stars for (var i = 0; i < stars.length; i++) { stars[i].update(); } if (gameOver || youWin) return; // Player update (powerup timer) player.update(); // Aliens update for (var i = aliens.length - 1; i >= 0; i--) { var alien = aliens[i]; alien.update(); // Check if alien reached bottom edge (player dies) if (alien.y > GAME_HEIGHT + alien.height / 2) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); gameOver = true; return; } // Check collision with player (if shielded, destroy alien) if (player.powered && player.powerType === 'shield' && alien.intersects(player)) { LK.getSound('alien_die').play(); LK.effects.flashObject(alien, 0x00eaff, 400); alien.isDead = true; aliens.splice(i, 1); alien.destroy(); continue; } } // Boss update if (bossActive && boss && !boss.isDead) { boss.update(); // If boss reaches bottom, game over if (boss.y > GAME_HEIGHT + boss.height / 2) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); gameOver = true; return; } // If player has shield and collides with boss, destroy boss if (player.powered && player.powerType === 'shield' && boss.intersects(player)) { LK.getSound('alien_die').play(); LK.effects.flashObject(boss, 0x00eaff, 600); boss.isDead = true; bossActive = false; bossDefeated = true; boss.destroy(); // Drop multiple crystals for (var c = 0; c < 3; c++) { var crystal = new Crystal(); crystal.x = boss.x + randInt(-60, 60); crystal.y = boss.y + randInt(-60, 60); crystals.push(crystal); game.addChild(crystal); } } } // Lasers update for (var i = lasers.length - 1; i >= 0; i--) { var laser = lasers[i]; laser.update(); // Remove if off screen if (laser.y < -100) { lasers.splice(i, 1); laser.destroy(); continue; } // Check collision with aliens var hit = false; for (var j = aliens.length - 1; j >= 0; j--) { var alien = aliens[j]; if (!alien.isDead && laser.intersects(alien)) { alien.hp -= player.powered && player.powerType === 'pierce' ? 2 : 1; if (alien.hp <= 0) { // Alien dies LK.getSound('alien_die').play(); LK.effects.flashObject(alien, 0xff0000, 400); alien.isDead = true; // Drop crystal var crystal = new Crystal(); crystal.x = alien.x; crystal.y = alien.y; crystals.push(crystal); game.addChild(crystal); // Remove alien aliens.splice(j, 1); alien.destroy(); enemiesLeft--; enemiesKilled++; aliensKilledThisWave++; // Every 30 aliens, increase wave by 1 (only if all 30 were killed in this wave) if (aliensKilledThisWave > 0 && aliensKilledThisWave % 30 === 0 && enemiesLeft === 0) { // If boss is not active, spawn boss for this wave if (!bossActive && !bossDefeated) { boss = new Boss(); boss.x = GAME_WIDTH / 2; boss.y = -boss.height / 2; boss.hp = 30 + (wave - 1) * 10; boss.maxHp = boss.hp; boss.speed = 2.2 + (wave - 1) * 0.12; bossActive = true; game.addChild(boss); return; // Wait for boss to be defeated before starting next wave } // If boss was just defeated, start next wave if (bossDefeated) { // If boss is not active, spawn boss for this wave if (!bossActive && !bossDefeated) { boss = new Boss(); boss.x = GAME_WIDTH / 2; boss.y = -boss.height / 2; boss.hp = 30 + (wave - 1) * 10; boss.maxHp = boss.hp; boss.speed = 2.2 + (wave - 1) * 0.12; bossActive = true; game.addChild(boss); return; // Wait for boss to be defeated before starting next wave } // If boss was just defeated, start next wave if (bossDefeated) { startWave(wave + 1); // Bonus box every BONUS_WAVE_INTERVAL after wave increment if ((wave + 1) % BONUS_WAVE_INTERVAL === 0) { var bonus = new BonusBox(); bonus.x = randInt(leftLimit + 100, rightLimit - 100); bonus.y = randInt(ENEMY_START_Y_MIN + 100, ENEMY_START_Y_MAX - 100); bonus.type = randomPowerup(); bonuses.push(bonus); game.addChild(bonus); } bossDefeated = false; bossDefeated = false; return; // Prevent double wave start if also enemiesLeft==0 } return; // Prevent double wave start if also enemiesLeft==0 } return; // Prevent double wave start if also enemiesLeft==0 } // New wave? if (enemiesLeft <= 0) { // No wave increase here, handled by 30 aliens killed logic } } hit = true; if (!(player.powered && player.powerType === 'pierce')) break; } } // Check collision with boss if (bossActive && boss && !boss.isDead && laser.intersects(boss)) { boss.hp -= player.powered && player.powerType === 'pierce' ? 2 : 1; LK.effects.flashObject(boss, 0xff0000, 200); if (boss.hp <= 0) { LK.getSound('alien_die').play(); boss.isDead = true; bossActive = false; bossDefeated = true; boss.destroy(); // Drop multiple crystals for (var c = 0; c < 3; c++) { var crystal = new Crystal(); crystal.x = boss.x + randInt(-60, 60); crystal.y = boss.y + randInt(-60, 60); crystals.push(crystal); game.addChild(crystal); } } hit = true; if (!(player.powered && player.powerType === 'pierce')) { lasers.splice(i, 1); laser.destroy(); } } if (hit && !(player.powered && player.powerType === 'pierce')) { lasers.splice(i, 1); laser.destroy(); } } // Crystals update for (var i = crystals.length - 1; i >= 0; i--) { var crystal = crystals[i]; // If player close enough, collect var dx = player.x - crystal.x; var dy = player.y - crystal.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < CRYSTAL_COLLECT_DIST) { LK.getSound('crystal_get').play(); LK.effects.flashObject(crystal, 0x00eaff, 400); crystals.splice(i, 1); crystal.destroy(); // Expand movement area and always update score crystalsCollected++; crystalTxt.setText(crystalsCollected); if (crystalsCollected <= MAX_CRYSTALS) { leftLimit = Math.max(PLAYER_MIN_X - crystalsCollected * CRYSTAL_MOVE_STEP, 80 + player.width / 2); rightLimit = Math.min(PLAYER_MAX_X + crystalsCollected * CRYSTAL_MOVE_STEP, GAME_WIDTH - 80 - player.width / 2); } } } // Bonus boxes update for (var i = bonuses.length - 1; i >= 0; i--) { var bonus = bonuses[i]; var dx = player.x - bonus.x; var dy = player.y - bonus.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < BONUS_COLLECT_DIST) { LK.getSound('bonus_get').play(); LK.effects.flashObject(bonus, 0xffe100, 400); bonuses.splice(i, 1); bonus.destroy(); // Grant powerup player.setPower(bonus.type, POWERUP_DURATION); if (bonus.type === 'rapid') { powerupTxt.setText('Rapid Fire!'); } else if (bonus.type === 'pierce') { powerupTxt.setText('Piercing Shots!'); } else if (bonus.type === 'shield') { powerupTxt.setText('Shield!'); } // Double shot bonus: always grant for 5 seconds (300 ticks) when bonus is collected doubleShotActive = true; doubleShotTimer = 300; } } // Powerup text timer if (player.powered) { powerupTxt.alpha = 1; } else { if (powerupTxt.alpha > 0) { powerupTxt.alpha -= 0.04; if (powerupTxt.alpha < 0) powerupTxt.alpha = 0; } powerupTxt.setText(''); } // Double shot timer if (doubleShotActive) { // Set player and all lasers to red tint if (player && player.children && player.children.length > 0) { // Player sprite is always first child if (player.children[0].tint !== 0xff0000) player.children[0].tint = 0xff0000; } for (var i = 0; i < lasers.length; i++) { if (lasers[i].children && lasers[i].children.length > 0) { if (lasers[i].children[0].tint !== 0xff0000) lasers[i].children[0].tint = 0xff0000; } } doubleShotTimer--; if (doubleShotTimer <= 0) { doubleShotActive = false; // Restore player tint (respect powerup color if active) if (player && player.children && player.children.length > 0) { if (player.powered) { if (player.powerType === 'rapid') { player.children[0].tint = 0xffe100; } else if (player.powerType === 'pierce') { player.children[0].tint = 0x00ffb0; } else if (player.powerType === 'shield') { player.children[0].tint = 0x00eaff; } } else { player.children[0].tint = 0xffffff; } } // Restore all lasers to normal tint for (var i = 0; i < lasers.length; i++) { if (lasers[i].children && lasers[i].children.length > 0) { lasers[i].children[0].tint = 0xffffff; } } } } // Player auto-fire var cooldown = player.powered && player.powerType === 'rapid' ? currentLaserCooldownRapid : currentLaserCooldown; if (player.shootCooldown > 0) player.shootCooldown--; // Find nearest alien in range var nearestAlien = null; var minDist = 99999; for (var i = 0; i < aliens.length; i++) { var alien = aliens[i]; var dx = alien.x - player.x; var dy = alien.y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dy > 0) continue; // Only shoot aliens above the player if (dist < minDist) { minDist = dist; nearestAlien = alien; } } if (nearestAlien && player.shootCooldown <= 0) { // Fire laser(s) if (doubleShotActive) { // Double shot: fire two lasers, slightly offset var laser1 = new Laser(); laser1.x = player.x - 32; laser1.y = player.y - player.height / 2 + 10; if (player.powered && player.powerType === 'pierce') { laser1.pierce = true; } // Set laser red if double shot if (laser1.children && laser1.children.length > 0) { laser1.children[0].tint = 0xff0000; } lasers.push(laser1); game.addChild(laser1); var laser2 = new Laser(); laser2.x = player.x + 32; laser2.y = player.y - player.height / 2 + 10; if (player.powered && player.powerType === 'pierce') { laser2.pierce = true; } // Set laser red if double shot if (laser2.children && laser2.children.length > 0) { laser2.children[0].tint = 0xff0000; } lasers.push(laser2); game.addChild(laser2); player.shootCooldown = cooldown; LK.getSound('laser_shoot').play(); } else { // Normal single shot var laser = new Laser(); laser.x = player.x; laser.y = player.y - player.height / 2 + 10; if (player.powered && player.powerType === 'pierce') { laser.pierce = true; } // Set laser red if double shot is active if (doubleShotActive && laser.children && laser.children.length > 0) { laser.children[0].tint = 0xff0000; } lasers.push(laser); game.addChild(laser); player.shootCooldown = cooldown; LK.getSound('laser_shoot').play(); } } // Alien image pool for 4 types var ALIEN_IMAGES = ['alien', 'alien2', 'alien3', 'alien4']; // Helper: get alien image(s) for this wave function getAlienImagesForWave(wave) { // Every 3 waves, cycle to next image var idx = Math.floor((wave - 1) / 3) % ALIEN_IMAGES.length; // 30% chance to mix all images in this wave if (Math.random() < 0.3) { // Return all images for mixing return ALIEN_IMAGES.slice(); } // Otherwise, use only the current image for this 3-wave block return [ALIEN_IMAGES[idx]]; } // Track which images to use for this wave if (typeof currentWaveAlienImages === "undefined") { var currentWaveAlienImages = getAlienImagesForWave(wave); } // If wave changed, update currentWaveAlienImages if (typeof lastAlienWave === "undefined" || lastAlienWave !== wave) { currentWaveAlienImages = getAlienImagesForWave(wave); lastAlienWave = wave; } // Spawn aliens for current wave if (!bossActive && enemiesToSpawn > 0 && LK.ticks - lastAlienSpawnTick > 24) { // Pick a random image from currentWaveAlienImages var imgIdx = randInt(0, currentWaveAlienImages.length - 1); var alienImage = currentWaveAlienImages[imgIdx]; // Create a new Alien and set its image var alien = new Alien(); // Remove the default sprite and attach the correct one if (alien.children && alien.children.length > 0) { alien.removeChild(alien.children[0]); } var alienSprite = alien.attachAsset(alienImage, { anchorX: 0.5, anchorY: 0.5 }); alien.width = alienSprite.width; alien.height = alienSprite.height; // Pick a random road for the alien to spawn on (X position) var roadIdx = randInt(0, ROAD_X_POSITIONS.length - 1); alien.x = ROAD_X_POSITIONS[roadIdx]; alien.y = -alien.height / 2; alien.wave = wave; alien.speed = 2.5 + (wave - 1) * WAVE_SPEED_INC; alien.hp = 1 + Math.floor((wave - 1) * WAVE_HP_INC / 2); aliens.push(alien); game.addChild(alien); enemiesToSpawn--; lastAlienSpawnTick = LK.ticks; } };
===================================================================
--- original.js
+++ change.js
@@ -187,16 +187,16 @@
/****
* Game Code
****/
-// Game constants
-// Player
-// Alien (enemy)
-// Player bullet (laser)
-// Crystal (collectible)
-// Bonus box
-// Sound effects
// Music
+// Sound effects
+// Bonus box
+// Crystal (collectible)
+// Player bullet (laser)
+// Alien (enemy)
+// Player
+// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
// --- Starfield background ---
// Star color palette (cycle every 2 waves)
@@ -261,8 +261,11 @@
var aliens = [];
var lasers = [];
var crystals = [];
var bonuses = [];
+var boss = null;
+var bossActive = false;
+var bossDefeated = false;
var dragNode = null;
var dragOffsetX = 0;
var dragOffsetY = 0;
var lastMoveX = 0;
@@ -334,8 +337,15 @@
// Start first wave
function startWave(waveNum) {
wave = waveNum;
waveTxt.setText('Wave ' + wave);
+ // Remove previous boss if any
+ if (boss && boss.parent) {
+ boss.destroy();
+ }
+ boss = null;
+ bossActive = false;
+ bossDefeated = false;
// Set enemiesToSpawn to 30 for each wave, so wave increases every 30 aliens
enemiesToSpawn = 30;
enemiesLeft = enemiesToSpawn;
lastAlienSpawnTick = LK.ticks;
@@ -420,8 +430,36 @@
alien.destroy();
continue;
}
}
+ // Boss update
+ if (bossActive && boss && !boss.isDead) {
+ boss.update();
+ // If boss reaches bottom, game over
+ if (boss.y > GAME_HEIGHT + boss.height / 2) {
+ LK.effects.flashScreen(0xff0000, 1000);
+ LK.showGameOver();
+ gameOver = true;
+ return;
+ }
+ // If player has shield and collides with boss, destroy boss
+ if (player.powered && player.powerType === 'shield' && boss.intersects(player)) {
+ LK.getSound('alien_die').play();
+ LK.effects.flashObject(boss, 0x00eaff, 600);
+ boss.isDead = true;
+ bossActive = false;
+ bossDefeated = true;
+ boss.destroy();
+ // Drop multiple crystals
+ for (var c = 0; c < 3; c++) {
+ var crystal = new Crystal();
+ crystal.x = boss.x + randInt(-60, 60);
+ crystal.y = boss.y + randInt(-60, 60);
+ crystals.push(crystal);
+ game.addChild(crystal);
+ }
+ }
+ }
// Lasers update
for (var i = lasers.length - 1; i >= 0; i--) {
var laser = lasers[i];
laser.update();
@@ -455,18 +493,52 @@
enemiesKilled++;
aliensKilledThisWave++;
// Every 30 aliens, increase wave by 1 (only if all 30 were killed in this wave)
if (aliensKilledThisWave > 0 && aliensKilledThisWave % 30 === 0 && enemiesLeft === 0) {
- startWave(wave + 1);
- // Bonus box every BONUS_WAVE_INTERVAL after wave increment
- if ((wave + 1) % BONUS_WAVE_INTERVAL === 0) {
- var bonus = new BonusBox();
- bonus.x = randInt(leftLimit + 100, rightLimit - 100);
- bonus.y = randInt(ENEMY_START_Y_MIN + 100, ENEMY_START_Y_MAX - 100);
- bonus.type = randomPowerup();
- bonuses.push(bonus);
- game.addChild(bonus);
+ // If boss is not active, spawn boss for this wave
+ if (!bossActive && !bossDefeated) {
+ boss = new Boss();
+ boss.x = GAME_WIDTH / 2;
+ boss.y = -boss.height / 2;
+ boss.hp = 30 + (wave - 1) * 10;
+ boss.maxHp = boss.hp;
+ boss.speed = 2.2 + (wave - 1) * 0.12;
+ bossActive = true;
+ game.addChild(boss);
+ return; // Wait for boss to be defeated before starting next wave
}
+ // If boss was just defeated, start next wave
+ if (bossDefeated) {
+ // If boss is not active, spawn boss for this wave
+ if (!bossActive && !bossDefeated) {
+ boss = new Boss();
+ boss.x = GAME_WIDTH / 2;
+ boss.y = -boss.height / 2;
+ boss.hp = 30 + (wave - 1) * 10;
+ boss.maxHp = boss.hp;
+ boss.speed = 2.2 + (wave - 1) * 0.12;
+ bossActive = true;
+ game.addChild(boss);
+ return; // Wait for boss to be defeated before starting next wave
+ }
+ // If boss was just defeated, start next wave
+ if (bossDefeated) {
+ startWave(wave + 1);
+ // Bonus box every BONUS_WAVE_INTERVAL after wave increment
+ if ((wave + 1) % BONUS_WAVE_INTERVAL === 0) {
+ var bonus = new BonusBox();
+ bonus.x = randInt(leftLimit + 100, rightLimit - 100);
+ bonus.y = randInt(ENEMY_START_Y_MIN + 100, ENEMY_START_Y_MAX - 100);
+ bonus.type = randomPowerup();
+ bonuses.push(bonus);
+ game.addChild(bonus);
+ }
+ bossDefeated = false;
+ bossDefeated = false;
+ return; // Prevent double wave start if also enemiesLeft==0
+ }
+ return; // Prevent double wave start if also enemiesLeft==0
+ }
return; // Prevent double wave start if also enemiesLeft==0
}
// New wave?
if (enemiesLeft <= 0) {
@@ -476,8 +548,33 @@
hit = true;
if (!(player.powered && player.powerType === 'pierce')) break;
}
}
+ // Check collision with boss
+ if (bossActive && boss && !boss.isDead && laser.intersects(boss)) {
+ boss.hp -= player.powered && player.powerType === 'pierce' ? 2 : 1;
+ LK.effects.flashObject(boss, 0xff0000, 200);
+ if (boss.hp <= 0) {
+ LK.getSound('alien_die').play();
+ boss.isDead = true;
+ bossActive = false;
+ bossDefeated = true;
+ boss.destroy();
+ // Drop multiple crystals
+ for (var c = 0; c < 3; c++) {
+ var crystal = new Crystal();
+ crystal.x = boss.x + randInt(-60, 60);
+ crystal.y = boss.y + randInt(-60, 60);
+ crystals.push(crystal);
+ game.addChild(crystal);
+ }
+ }
+ hit = true;
+ if (!(player.powered && player.powerType === 'pierce')) {
+ lasers.splice(i, 1);
+ laser.destroy();
+ }
+ }
if (hit && !(player.powered && player.powerType === 'pierce')) {
lasers.splice(i, 1);
laser.destroy();
}
@@ -663,9 +760,9 @@
currentWaveAlienImages = getAlienImagesForWave(wave);
lastAlienWave = wave;
}
// Spawn aliens for current wave
- if (enemiesToSpawn > 0 && LK.ticks - lastAlienSpawnTick > 24) {
+ if (!bossActive && enemiesToSpawn > 0 && LK.ticks - lastAlienSpawnTick > 24) {
// Pick a random image from currentWaveAlienImages
var imgIdx = randInt(0, currentWaveAlienImages.length - 1);
var alienImage = currentWaveAlienImages[imgIdx];
// Create a new Alien and set its image
A triangular spaceship. In-Game asset. 2d. High contrast. No shadows
alien creature drawing. In-Game asset. 2d. High contrast. No shadows
alien creature drawing. In-Game asset. 2d. High contrast. No shadows
alien creature drawing. In-Game asset. 2d. High contrast. No shadows
alien creature drawing. In-Game asset. 2d. High contrast. No shadows
blue crystal. In-Game asset. 2d. High contrast. No shadows
draw thick long laser bullet. In-Game asset. 2d. High contrast. No shadows
remove bonus text
spaceship. In-Game asset. 2d. High contrast. No shadows