User prompt
it doesntttttt
User prompt
Fix health bar initialization to ensure it's green at the start
User prompt
bug : tha bar is not green
User prompt
Update player health bar initialization to show full health at start
User prompt
when starting, the bar should be fully green
User prompt
make that player is full health while starting the game and he have 3 stats of health : Green (full) yellow and red, after red he dies and when player obteins a heart, his health changes to the next stat ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
when we start, the health bar should be full and green and when we touch a laser we loose health and when no health it's game over
User prompt
remove shields after using them
User prompt
make less enemies spawn on a wave
User prompt
make player shoot less lasers per sec
User prompt
add a health bar on the player and a heart that restore a part of the health, it can be obtained while killing a boss
User prompt
bug : level 16-30 should be the enemyCat2 not enemyCat
User prompt
1-15 was GrumpyCat, 16-30 is Maxwell (enemyCat2) and new bosses r boss2. Make 16-30 levels harder than 1-15
User prompt
make the game harder
User prompt
make that boss move slowly to players position and make it throw less lasers
User prompt
make that some enemies throw lasers and boss too and make the first boss has 50 HP and the last one 100HP ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
bug : some enemies doesnt fall
User prompt
When boss comes, play boss music
Code edit (1 edits merged)
Please save this source code
User prompt
Meme Cat Invasion
Initial prompt
Game Title: Meme Cat Invasion Description: A hilarious and slightly terrifying game where you fend off an army of meme cats threatening to take over the world. Can you stop them before it’s too late?
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemyCat', { anchorX: 0.5, anchorY: 0.5 }); self.type = 'basic'; self.health = 1; self.speed = 6; self.pointValue = 10; self.isActive = true; self.movePattern = 'straight'; self.movementTime = 0; self.direction = 1; // 1 right, -1 left self.update = function () { if (self.isActive) { self.movementTime += 2; // Move based on pattern if (self.movePattern === 'straight') { self.y += self.speed; } else if (self.movePattern === 'zigzag') { self.y += self.speed; self.x += Math.sin(self.movementTime * 0.05) * 3; } else if (self.movePattern === 'teleport') { // Always move down self.y += self.speed; // And occasionally teleport horizontally if (self.movementTime % 120 === 0) { // Teleport every 2 seconds self.x = 100 + Math.random() * (2048 - 200); LK.effects.flashObject(self, 0xffffff, 300); } } // Advanced enemies occasionally shoot lasers with increasing frequency in higher waves var shootChance = 0.01; // Base chance if (wave > 10) { shootChance = 0.015 + (wave - 10) * 0.001; // Increases with each wave after 10 shootChance = Math.min(shootChance, 0.03); // Cap at 3% } if ((self.type === 'zigzag' || self.type === 'teleport') && Math.random() < shootChance) { var laser = new EnemyLaser(); // Adjust laser speed based on wave if (wave > 10) { laser.speed = 10 + Math.min(5, Math.floor((wave - 10) / 3)); } laser.x = self.x; laser.y = self.y + 30; enemyLasers.push(laser); game.addChild(laser); } // Remove enemy when it goes off screen if (self.y > 2732 + 50) { self.isActive = false; // Decrease lives when enemy passes bottom of screen if (livesCount > 0 && self.type !== 'boss' && self.type !== 'boss2') { livesCount--; livesText.setText('Lives: ' + livesCount); // Flash the lives text red to indicate loss tween(livesText, { tint: 0xff0000 }, { duration: 300, onFinish: function onFinish() { tween(livesText, { tint: 0xffffff }, { duration: 300 }); } }); // Game over if lives reach zero if (livesCount <= 0) { gameActive = false; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } } } } }; self.takeDamage = function (damage) { self.health -= damage; // Flash the enemy red when hit LK.effects.flashObject(self, 0xff0000, 300); if (self.health <= 0) { // Play explosion sound LK.getSound('explosion').play(); // Create explosion effect var explosion = new Explosion(); explosion.x = self.x; explosion.y = self.y; game.addChild(explosion); // Create particles for more dramatic effect for (var i = 0; i < 6; i++) { var particle = new Explosion(); particle.x = self.x + Math.random() * 60 - 30; particle.y = self.y + Math.random() * 60 - 30; particle.duration = 20 + Math.random() * 10; game.addChild(particle); } // Chance to drop power-up (15%) if (Math.random() < 0.15) { var powerUp = new PowerUp(); powerUp.x = self.x; powerUp.y = self.y; // Randomly choose power-up type var powerType = Math.random(); if (powerType < 0.5) { powerUp.setType('spreadshot'); } else if (powerType < 0.8) { powerUp.setType('shield'); } else { powerUp.setType('bomb'); } powerUps.push(powerUp); game.addChild(powerUp); } self.isActive = false; } }; self.setType = function (newType) { self.type = newType; // Get wave-based difficulty multiplier (increases after wave 10) var difficultyMult = wave > 10 ? 1.5 : 1; // First remove any existing graphics self.removeChildren(); // Add the appropriate graphic based on the wave var assetType = wave > 10 ? 'enemyCat2' : 'enemyCat'; var enemyGraphics = self.attachAsset(assetType, { anchorX: 0.5, anchorY: 0.5 }); // For enemyCat2, apply scaling since it's smaller by default if (wave > 10) { enemyGraphics.scale.set(3, 3); } if (newType === 'basic') { enemyGraphics.tint = 0xffcc00; self.health = Math.ceil(2 * difficultyMult); self.speed = Math.min(5, 3 * difficultyMult); self.pointValue = Math.ceil(10 * difficultyMult); self.movePattern = 'straight'; } else if (newType === 'fast') { enemyGraphics.tint = 0xff9900; self.health = Math.ceil(2 * difficultyMult); self.speed = Math.min(7, 5 * difficultyMult); self.pointValue = Math.ceil(15 * difficultyMult); self.movePattern = 'straight'; } else if (newType === 'zigzag') { enemyGraphics.tint = 0x66cc00; self.health = Math.ceil(3 * difficultyMult); self.speed = Math.min(5, 3 * difficultyMult); self.pointValue = Math.ceil(20 * difficultyMult); self.movePattern = 'zigzag'; } else if (newType === 'teleport') { enemyGraphics.tint = 0xcc33ff; self.health = Math.ceil(4 * difficultyMult); self.speed = Math.min(4, 2 * difficultyMult); self.pointValue = Math.ceil(30 * difficultyMult); self.movePattern = 'teleport'; } }; return self; }); var BossCat = Enemy.expand(function () { var self = Enemy.call(this); // Remove the previous graphic and add boss graphic self.removeChildren(); var bossGraphics = self.attachAsset('bossCat', { anchorX: 0.5, anchorY: 0.5 }); self.type = 'boss'; self.health = 80; // First boss has 80 HP (increased from 50) self.speed = 1; self.pointValue = 200; self.movePattern = 'boss'; self.phase = 0; self.shootCooldown = 0; self.isFinalBoss = false; // Track if this is the final boss // Override update method self.update = function () { if (self.isActive) { self.movementTime++; // Boss movement pattern if (self.phase === 0) { // Move down to position self.y += self.speed; if (self.y >= 300) { self.phase = 1; self.movementTime = 0; } } else if (self.phase === 1) { // Move slowly towards player's position if (player && player.x) { // Calculate direction to player var directionX = player.x - self.x; // Move slowly towards player (0.5% of the distance per frame) self.x += directionX * 0.005; } // Add slight vertical movement self.y += Math.sin(self.movementTime * 0.01) * 1; // Phase transition based on health percentage var healthPercent = self.isFinalBoss ? self.health / 100 : self.health / 50; if (healthPercent <= 0.5 && self.phase < 2) { self.phase = 2; self.speed = 1.5; LK.effects.flashObject(self, 0xff0000, 1000); } } else if (self.phase === 2) { // Move towards player faster in aggressive phase if (player && player.x) { var directionX = player.x - self.x; // Move faster towards player (1% of the distance per frame) self.x += directionX * 0.01; } // Add some vertical movement self.y += Math.sin(self.movementTime * 0.02) * 2; } // Boss shooting logic self.shootCooldown--; if (self.shootCooldown <= 0) { // Shoot pattern based on phase if (self.phase === 1) { // Single shot during phase 1, less frequent self.shootLaser(); self.shootCooldown = 180; // 3 seconds (doubled from original) } else if (self.phase === 2) { // Double shot during phase 2, less frequent self.shootLaser(); self.shootLaser(-30, 0.3); self.shootCooldown = 120; // 2 seconds (doubled from original) } } } }; // Boss shooting method self.shootLaser = function (offsetX, rotation) { offsetX = offsetX || 0; rotation = rotation || 0; var laser = new EnemyLaser(); laser.x = self.x + offsetX; laser.y = self.y + 100; if (rotation !== 0) { laser.rotation = rotation; } enemyLasers.push(laser); game.addChild(laser); }; // Set boss as final boss self.setAsFinalBoss = function () { self.isFinalBoss = true; self.health = 150; // Final boss has 150 HP (increased from 100) self.pointValue = 500; tween(bossGraphics, { tint: 0xff0000 }, { duration: 1000 }); }; // Override takeDamage to show health var originalTakeDamage = self.takeDamage; self.takeDamage = function (damage) { originalTakeDamage.call(self, damage); // Update boss health display if (bossHealthText) { bossHealthText.setText("Boss HP: " + self.health); } // Drop heart power-up when boss is defeated if (self.health <= 0) { // 100% chance to drop heart from boss var heart = new PowerUp(); heart.x = self.x; heart.y = self.y; heart.setType('heart'); powerUps.push(heart); game.addChild(heart); } }; return self; }); var Boss2 = BossCat.expand(function () { var self = BossCat.call(this); // Replace boss graphic with new boss self.removeChildren(); var bossGraphics = self.attachAsset('enemyCat2', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3 }); self.type = 'boss2'; self.health = 200; // Second boss has 200 HP by default self.speed = 1.5; self.pointValue = 300; self.movementTime = 0; self.attackPattern = 0; self.attackTimer = 0; // Override update method var originalUpdate = self.update; self.update = function () { if (self.isActive) { self.movementTime++; self.attackTimer++; // Boss2 movement pattern if (self.phase === 0) { // Move down to position self.y += self.speed; if (self.y >= 350) { self.phase = 1; self.movementTime = 0; } } else if (self.phase === 1) { // More complex movement self.x += Math.sin(self.movementTime * 0.02) * 3; self.y += Math.cos(self.movementTime * 0.01) * 2; // Phase transition based on health percentage var healthPercent = self.isFinalBoss ? self.health / 250 : self.health / 200; if (healthPercent <= 0.5 && self.phase < 2) { self.phase = 2; self.speed = 2; self.attackPattern = 1; LK.effects.flashObject(self, 0xff0000, 1000); } } else if (self.phase === 2) { // More aggressive pattern self.x += Math.sin(self.movementTime * 0.03) * 5; self.y += Math.sin(self.movementTime * 0.02) * 3; // Occasionally teleport if (self.movementTime % 180 === 0) { self.x = 400 + Math.random() * (2048 - 800); LK.effects.flashObject(self, 0xffffff, 300); } } // Boss2 shooting logic self.shootCooldown--; if (self.shootCooldown <= 0) { if (self.phase === 1) { // Triple shot pattern self.shootLaser(); self.shootLaser(-50, -0.2); self.shootLaser(50, 0.2); self.shootCooldown = 150; } else if (self.phase === 2) { // More complex attack patterns if (self.attackPattern === 0) { // Spiral pattern for (var i = 0; i < 6; i++) { var angle = self.attackTimer * 0.01 + i * Math.PI / 3; var offsetX = Math.cos(angle) * 80; var offsetY = Math.sin(angle) * 80; self.shootLaser(offsetX, angle * 0.2); } self.shootCooldown = 240; self.attackPattern = 1; } else { // Targeted shots if (player && player.x) { var directionX = player.x - self.x; var angle = Math.atan2(player.y - self.y, directionX); self.shootLaser(0, angle * 0.3); self.shootLaser(-30, angle * 0.25); self.shootLaser(30, angle * 0.35); } self.shootCooldown = 180; self.attackPattern = 0; } } } } }; // Set boss as final boss self.setAsFinalBoss = function () { self.isFinalBoss = true; self.health = 250; // Final boss2 has 250 HP self.pointValue = 800; tween(bossGraphics, { tint: 0xff3300 }, { duration: 1000 }); }; // Override takeDamage to drop heart var originalTakeDamage = self.takeDamage; self.takeDamage = function (damage) { originalTakeDamage.call(self, damage); // Drop heart power-up when boss is defeated if (self.health <= 0) { // 100% chance to drop heart from boss var heart = new PowerUp(); heart.x = self.x; heart.y = self.y; heart.setType('heart'); powerUps.push(heart); game.addChild(heart); } }; return self; }); var EnemyLaser = Container.expand(function () { var self = Container.call(this); var laserGraphics = self.attachAsset('laser', { anchorX: 0.5, anchorY: 0.5, tint: 0xff6600 }); self.speed = 20; // Increased from 8 self.damage = 1; self.isActive = true; self.update = function () { if (self.isActive) { self.y += self.speed; // Remove laser when it goes off screen if (self.y > 2732 + 50) { self.isActive = false; } } }; return self; }); var Explosion = Container.expand(function () { var self = Container.call(this); // Create the explosion frames (will be hidden at first except frame 1) var frame1 = self.attachAsset('explosionFrame1', { anchorX: 0.5, anchorY: 0.5 }); var frame2 = self.attachAsset('explosionFrame2', { anchorX: 0.5, anchorY: 0.5, visible: false }); var frame3 = self.attachAsset('explosionFrame3', { anchorX: 0.5, anchorY: 0.5, visible: false }); var frame4 = self.attachAsset('explosionFrame4', { anchorX: 0.5, anchorY: 0.5, visible: false }); self.isActive = true; self.duration = 40; // Duration increased slightly self.timer = 0; self.currentFrame = 1; self.frames = [frame1, frame2, frame3, frame4]; self.update = function () { if (self.isActive) { self.timer++; // Animation frame timing (10 frames per explosion frame) var frameIndex = Math.floor(self.timer / 10); if (frameIndex >= 0 && frameIndex < 4 && frameIndex !== self.currentFrame - 1) { // Hide all frames self.frames.forEach(function (frame) { frame.visible = false; }); // Show current frame self.currentFrame = frameIndex + 1; self.frames[frameIndex].visible = true; // Apply scale and rotation effects to current frame var progress = self.timer / self.duration; var currentScale = 1 + progress; self.frames[frameIndex].scale.set(currentScale, currentScale); self.frames[frameIndex].rotation = progress * Math.PI * 0.5; } // Remove when animation complete if (self.timer >= self.duration) { self.isActive = false; } } }; return self; }); var Laser = Container.expand(function () { var self = Container.call(this); var laserGraphics = self.attachAsset('laser', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -30; self.damage = 1; self.isActive = true; self.update = function () { if (self.isActive) { self.y += self.speed; // Remove laser when it goes off screen if (self.y < -50) { self.isActive = false; } } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.shootCooldown = 0; self.cooldownTime = 30; // Frames between shots (increased from 15) self.hasShield = false; self.hasSpreadshot = false; self.spreadDuration = 0; self.shield = null; self.maxHealth = 100; self.health = self.maxHealth; // Starting with full health // Define health state thresholds self.healthStateThresholds = { green: 0.66, // Above 66% is green (full health) yellow: 0.33 // Above 33% is yellow, below is red }; self.update = function () { // Decrease cooldown if (self.shootCooldown > 0) { self.shootCooldown--; } // Decrease spreadshot duration if (self.hasSpreadshot) { self.spreadDuration--; if (self.spreadDuration <= 0) { self.hasSpreadshot = false; } } // Update health bar directly on player healthBarFill.scale.x = self.health / self.maxHealth; // Update health text if (healthText) { healthText.setText(Math.ceil(self.health) + "/" + self.maxHealth); } }; self.shoot = function () { if (self.shootCooldown <= 0) { if (self.hasSpreadshot) { // Create spread shot (3 lasers) var centerLaser = new Laser(); centerLaser.x = self.x; centerLaser.y = self.y - 60; lasers.push(centerLaser); game.addChild(centerLaser); var leftLaser = new Laser(); leftLaser.x = self.x - 40; leftLaser.y = self.y - 60; leftLaser.rotation = -0.3; lasers.push(leftLaser); game.addChild(leftLaser); var rightLaser = new Laser(); rightLaser.x = self.x + 40; rightLaser.y = self.y - 60; rightLaser.rotation = 0.3; lasers.push(rightLaser); game.addChild(rightLaser); } else { // Create single laser var laser = new Laser(); laser.x = self.x; laser.y = self.y - 40; lasers.push(laser); game.addChild(laser); } LK.getSound('shoot').play(); self.shootCooldown = self.cooldownTime; } }; self.activateShield = function () { // Remove existing shield if there is one if (self.shield && self.shield.isActive) { self.shield.isActive = false; game.removeChild(self.shield); } // Create new shield self.hasShield = true; self.shield = new Shield(); self.shield.x = self.x; self.shield.y = self.y; game.addChild(self.shield); return self.shield; }; self.activateSpreadshot = function () { self.hasSpreadshot = true; self.spreadDuration = 600; // 3 seconds at 60fps (reduced from 5 seconds) }; self.activateBomb = function () { // Destroy all enemies on screen for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.isActive) { enemy.takeDamage(999); // Instant kill LK.setScore(LK.getScore() + enemy.pointValue); } } // Visual effect for bomb LK.effects.flashScreen(0xff0000, 500); }; self.takeDamage = function (damage) { // Store previous health percentage to detect state transitions var prevHealthPercent = self.health / self.maxHealth; self.health -= damage; // Play hit sound LK.getSound('hitSound').play(); // Change player graphic to hit animation self.removeChildren(); self.attachAsset('playerHit', { anchorX: 0.5, anchorY: 0.5 }); // Add health bar and text back self.addChild(healthBarFill); self.addChild(healthText); // Return to normal graphic after a short delay LK.setTimeout(function () { self.removeChildren(); playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // Add health bar and text back again self.addChild(healthBarFill); self.addChild(healthText); }, 300); // Flash the player red when hit LK.effects.flashObject(self, 0xff0000, 300); // Update health bar if (healthBarFill) { healthBarFill.scale.x = Math.max(0, self.health / self.maxHealth); // Get new health percentage var healthPercent = self.health / self.maxHealth; // Change health bar color based on percentage if (healthPercent >= 0.66) { healthBarFill.tint = 0x00ff00; // Green for high health } else if (healthPercent >= 0.33) { healthBarFill.tint = 0xffcc00; // Yellow/orange for medium health } else { healthBarFill.tint = 0xff0000; // Red for low health } // Check for transition between health states if (prevHealthPercent > 0.66 && healthPercent <= 0.66 || prevHealthPercent > 0.33 && healthPercent <= 0.33) { // Visual effect for health state degradation tween(healthBarFill, { alpha: 0.2 }, { duration: 300, onFinish: function onFinish() { tween(healthBarFill, { alpha: 1 }, { duration: 300 }); } }); } } // Check if player is dead if (self.health <= 0) { gameActive = false; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } return self.health <= 0; // Return true if player died }; self.heal = function (amount) { // Store previous health percentage to detect state transitions var prevHealthPercent = self.health / self.maxHealth; self.health = Math.min(self.maxHealth, self.health + amount); // Update health bar if (healthBarFill) { healthBarFill.scale.x = self.health / self.maxHealth; // Get new health percentage var healthPercent = self.health / self.maxHealth; // Change health bar color based on percentage if (healthPercent >= 0.66) { healthBarFill.tint = 0x00ff00; // Green for high health } else if (healthPercent >= 0.33) { healthBarFill.tint = 0xffcc00; // Yellow/orange for medium health } else { healthBarFill.tint = 0xff0000; // Red for low health } // Check for transition between health states if (prevHealthPercent <= 0.33 && healthPercent > 0.33 || prevHealthPercent <= 0.66 && healthPercent > 0.66) { // Visual effect for health state improvement tween(healthBarFill, { alpha: 0.2 }, { duration: 300, onFinish: function onFinish() { tween(healthBarFill, { alpha: 1 }, { duration: 300 }); } }); } } // Visual healing effect LK.effects.flashObject(self, 0x00ff00, 300); }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerUpGraphics = self.attachAsset('powerUp', { anchorX: 0.5, anchorY: 0.5 }); self.type = 'spreadshot'; // Default type self.speed = 6; self.isActive = true; self.update = function () { if (self.isActive) { self.y += self.speed; // Rotate the power-up for visual effect powerUpGraphics.rotation += 0.05; // Remove power-up when it goes off screen if (self.y > 2732 + 50) { self.isActive = false; } } }; self.setType = function (newType) { self.type = newType; // Remove previous graphics self.removeChildren(); // Change appearance based on type if (newType === 'spreadshot') { powerUpGraphics = self.attachAsset('powerUp', { anchorX: 0.5, anchorY: 0.5 }); } else if (newType === 'shield') { powerUpGraphics = self.attachAsset('powerUpShield', { anchorX: 0.5, anchorY: 0.5 }); } else if (newType === 'bomb') { powerUpGraphics = self.attachAsset('powerUpBomb', { anchorX: 0.5, anchorY: 0.5 }); } else if (newType === 'heart') { powerUpGraphics = self.attachAsset('heart', { anchorX: 0.5, anchorY: 0.5 }); } }; return self; }); var Shield = Container.expand(function () { var self = Container.call(this); var shieldGraphics = self.attachAsset('shield', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); self.duration = 6000; // Shield lasts 3 seconds (reduced from 5) self.timeLeft = self.duration; self.isActive = true; self.update = function () { if (self.isActive) { self.timeLeft -= 1000 / 60; // Decrease time left (60 fps) // Fade out as shield expires shieldGraphics.alpha = 0.2 + self.timeLeft / self.duration * 0.5; // Rotate the shield for visual effect shieldGraphics.rotation += 0.01; // Deactivate shield when time runs out if (self.timeLeft <= 0) { self.isActive = false; // Remove shield reference from player if (player) { player.hasShield = false; player.shield = null; } // Remove this shield from the game when it expires game.removeChild(self); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000033 }); /**** * Game Code ****/ // Game state variables function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) { throw o; } } } }; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) { return _arrayLikeToArray(r, a); } var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) { n[e] = r[e]; } return n; } var player; var lasers = []; var enemyLasers = []; var enemies = []; var powerUps = []; var wave = 1; var enemiesInWave = 5; var enemiesSpawned = 0; var spawnCooldown = 0; var gameActive = true; var bossWave = false; var bossHealthText; var healthBar; var healthBarBg; var healthBarFill; var livesCount = 10; var livesText; // UI elements var scoreTxt = new Text2('Score\r\n0', { size: 100, fill: 0xFFFFFF, dropShadow: true, align: 'center' }); scoreTxt.setText("Score\r\n" + LK.getScore()); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var waveTxt = new Text2('Wave\r\n1', { size: 80, fill: 0xFFFFFF, dropShadow: true, align: 'center' }); waveTxt.anchor.set(1.0, 0); LK.gui.topRight.addChild(waveTxt); // Position it away from the top left corner (reserved for menu icon) waveTxt.x = 0; // Lives counter display livesText = new Text2('Lives: ' + livesCount, { size: 80, fill: 0xFFFFFF }); livesText.anchor.set(0.5, 0); LK.gui.bottom.addChild(livesText); // Add background image var background = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, width: 2048, height: 2732 }); background.x = 2048 / 2; background.y = 2732 / 2; game.addChild(background); // Create background clone first to ensure it's below the player if (!game.backgroundClone) { // Create a clone of the background game.backgroundClone = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, width: 2048, height: 2732 }); // Position the clone directly above the original background game.backgroundClone.x = background.x; game.backgroundClone.y = background.y - background.height; game.addChild(game.backgroundClone); } // Create player after all background elements player = new Player(); player.x = 2048 / 2; player.y = 2732 - 200; player.cooldownTime = 10; // Reduced cooldown between shots (from 30) // Add player last so it appears on top of all background elements game.addChild(player); // Create health bar - directly attached to player healthBarFill = LK.getAsset('baseBox', { anchorX: 0, // Anchor at the left edge for scaling from left to right anchorY: 0.5, tint: 0x00ff00, // Set tint to green for full health explicitly in creation scaleX: 10, scaleY: 0.5 // Base height scale factor (visual size) }); // Ensure bar scale correctly represents 100% health at the start healthBarFill.scale.x = player.health / player.maxHealth; // Set scale based on current health percentage // Create health text display var healthText = new Text2('100/100', { size: 40, fill: 0xFFFFFF }); healthText.anchor.set(0.5, 0); healthText.y = 0; // Position below health bar // Attach directly to player player.addChild(healthBarFill); player.addChild(healthText); // Position relative to player - higher placement healthBarFill.y = -70; healthBarFill.x = -50; // Position health text above health bar healthText.y = -120; // Set initial animation for health bar to draw player's attention tween(healthBarFill, { alpha: 0.5 }, { duration: 500, onFinish: function onFinish() { tween(healthBarFill, { alpha: 1 }, { duration: 500 }); } }); // Start background music with fade in effect LK.playMusic('gameMusic', { fade: { start: 0, end: 1, duration: 1000 } }); // Game input handlers game.down = function (x, y, obj) { // Shoot when tapping anywhere player.shoot(); }; game.move = function (x, y, obj) { // Move player horizontally (keep vertical position fixed) if (gameActive) { player.x = x; // Keep player within game bounds if (player.x < 75) { player.x = 75; } if (player.x > 2048 - 75) { player.x = 2048 - 75; } // Update shield position if active if (player.hasShield && player.shield && player.shield.isActive) { player.shield.x = player.x; player.shield.y = player.y; } } }; // Spawn enemies function spawnEnemy() { var enemy; if (bossWave) { // Use Boss2 for waves 15 and 20 if (wave >= 15 && wave % 5 === 0) { enemy = new Boss2(); enemy.x = 2048 / 2; enemy.y = -200; // If this is the final boss (wave 20), set it to have higher HP if (wave === 20) { enemy.setAsFinalBoss(); } } else { enemy = new BossCat(); enemy.x = 2048 / 2; enemy.y = -200; // If this is the final boss of the first stage (wave 10), set it to have higher HP if (wave === 10) { enemy.setAsFinalBoss(); } } // Create boss health display bossHealthText = new Text2("Boss HP: " + enemy.health, { size: 60, fill: 0xFF6600 }); bossHealthText.anchor.set(0.5, 0); bossHealthText.y = 150; LK.gui.top.addChild(bossHealthText); } else { enemy = new Enemy(); enemy.x = 100 + Math.random() * (2048 - 200); enemy.y = -100; // Set random enemy type based on current wave var typeRoll = Math.random(); if (wave <= 2) { // Waves 1-2: Only basic enemies enemy.setType('basic'); } else if (wave <= 4) { // Waves 3-4: Basic and fast enemies if (typeRoll < 0.6) { enemy.setType('basic'); } else { enemy.setType('fast'); } } else if (wave <= 6) { // Waves 5-6: Add zigzag enemies if (typeRoll < 0.4) { enemy.setType('basic'); } else if (typeRoll < 0.7) { enemy.setType('fast'); } else { enemy.setType('zigzag'); } } else if (wave <= 10) { // Waves 7-10: All enemy types if (typeRoll < 0.3) { enemy.setType('basic'); } else if (typeRoll < 0.5) { enemy.setType('fast'); } else if (typeRoll < 0.8) { enemy.setType('zigzag'); } else { enemy.setType('teleport'); } } else { // Waves 11-20: Harder distribution with fewer basic enemies if (typeRoll < 0.15) { enemy.setType('basic'); } else if (typeRoll < 0.4) { enemy.setType('fast'); } else if (typeRoll < 0.7) { enemy.setType('zigzag'); } else { enemy.setType('teleport'); } } } enemies.push(enemy); game.addChild(enemy); enemiesSpawned++; } // Main game update loop game.update = function () { if (!gameActive) { return; } // Track and update explosions var explosions = []; var _iterator = _createForOfIteratorHelper(game.children), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var child = _step.value; if (child instanceof Explosion) { explosions.push(child); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } for (var i = explosions.length - 1; i >= 0; i--) { var explosion = explosions[i]; //explosion.update(); if (!explosion.isActive) { game.removeChild(explosion); } } // Set up background scrolling with two identical backgrounds side by side if (!game.backgroundClone) { // Create a clone of the background game.backgroundClone = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, width: 2048, height: 2732 }); // Position the clone directly above the original background game.backgroundClone.x = background.x; game.backgroundClone.y = background.y - background.height; game.addChild(game.backgroundClone); } // Scroll both backgrounds background.y += 5; // Increased scroll speed game.backgroundClone.y += 5; // Same increased speed for clone // If original background goes completely off screen, move it above the clone if (background.y - background.height / 2 > 2732) { background.y = game.backgroundClone.y - background.height; } // If clone background goes completely off screen, move it above the original if (game.backgroundClone.y - game.backgroundClone.height / 2 > 2732) { game.backgroundClone.y = background.y - background.height; } // Update player //player.update(); // Update shield if active if (player.hasShield && player.shield) { //player.shield.update(); if (player.shield && !player.shield.isActive) { player.hasShield = false; game.removeChild(player.shield); player.shield = null; } } // Handle enemy spawning if (spawnCooldown <= 0) { if (enemiesSpawned < enemiesInWave) { spawnEnemy(); // Cooldown between spawns if (bossWave) { spawnCooldown = 1; // Boss spawns immediately } else { spawnCooldown = 60; // 1 second between normal enemy spawns } } } else { spawnCooldown--; } // Update lasers and check for collisions for (var i = lasers.length - 1; i >= 0; i--) { var laser = lasers[i]; //laser.update(); if (!laser.isActive) { game.removeChild(laser); lasers.splice(i, 1); continue; } // Check for collisions with enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (enemy.isActive && laser.isActive && laser.intersects(enemy)) { enemy.takeDamage(laser.damage); laser.isActive = false; if (!enemy.isActive) { LK.setScore(LK.getScore() + enemy.pointValue); scoreTxt.setText("Score\r\n" + LK.getScore()); game.removeChild(enemy); enemies.splice(j, 1); } break; } } } // Update enemy lasers and check for collisions with player for (var el = enemyLasers.length - 1; el >= 0; el--) { var enemyLaser = enemyLasers[el]; //enemyLaser.update(); if (!enemyLaser.isActive) { game.removeChild(enemyLaser); enemyLasers.splice(el, 1); continue; } // Check for collision with player if (enemyLaser.intersects(player)) { // If player has shield, block the laser if (player.hasShield) { enemyLaser.isActive = false; game.removeChild(enemyLaser); enemyLasers.splice(el, 1); // Flash shield to show impact if (player.shield) { LK.effects.flashObject(player.shield, 0xffff00, 300); } } else { // Player takes damage from laser - only one point of health var laserDamage = 1; player.takeDamage(laserDamage); enemyLaser.isActive = false; game.removeChild(enemyLaser); enemyLasers.splice(el, 1); if (!gameActive) { return; } // Return if player died } } } // Update enemies var activeEnemies = 0; for (var k = enemies.length - 1; k >= 0; k--) { var enemy = enemies[k]; //enemy.update(); if (!enemy.isActive) { game.removeChild(enemy); enemies.splice(k, 1); continue; } activeEnemies++; // Check collision with player if (enemy.intersects(player)) { // Initialize lastDamageTime if not set if (enemy.lastDamageTime === undefined) { enemy.lastDamageTime = 0; } // Check if 3 seconds (180 frames at 60fps) have passed since last damage var currentTime = LK.ticks; var damageInterval = 180; // 3 seconds at 60fps if (player.hasShield) { // Shield absorbs collision damage if (player.shield) { LK.effects.flashObject(player.shield, 0xffff00, 300); } } else { // Player takes damage from collision only every 3 seconds var collisionDamage = 10; // Apply damage only if enough time has passed if (currentTime - enemy.lastDamageTime >= damageInterval) { player.takeDamage(collisionDamage); enemy.lastDamageTime = currentTime; // Visual feedback that damage was applied LK.effects.flashObject(enemy, 0xff0000, 300); } if (!gameActive) { return; } // Return if player died } } } // Update power-ups for (var l = powerUps.length - 1; l >= 0; l--) { var powerUp = powerUps[l]; //powerUp.update(); if (!powerUp.isActive) { game.removeChild(powerUp); powerUps.splice(l, 1); continue; } // Check collision with player if (powerUp.intersects(player)) { // Apply power-up effect if (powerUp.type === 'spreadshot') { player.activateSpreadshot(); } else if (powerUp.type === 'shield') { player.activateShield(); } else if (powerUp.type === 'bomb') { player.activateBomb(); } else if (powerUp.type === 'heart') { player.heal(50); // Restore 50 health points } LK.getSound('powerup').play(); powerUp.isActive = false; game.removeChild(powerUp); powerUps.splice(l, 1); } } // Check if wave is complete if (enemiesSpawned >= enemiesInWave && activeEnemies === 0) { // Wave complete, start next wave wave++; waveTxt.setText("Wave\r\n" + wave); // Every 5th wave is a boss wave if (wave % 5 === 0) { bossWave = true; enemiesInWave = 1; } else { bossWave = false; // Reduced enemies per wave to make the game easier enemiesInWave = 5 + Math.floor(wave * 1.5); // Remove boss health display if it exists if (bossHealthText) { LK.gui.top.removeChild(bossHealthText); bossHealthText = null; } } enemiesSpawned = 0; spawnCooldown = 120; // 2 second delay between waves // Check for music changes between levels 1-10 and 11-20 if (wave == 11) { // Change to gameMusic2 for levels 11-20 LK.playMusic('gameMusic2', { fade: { start: 0, end: 1, duration: 1000 } }); } else if (wave == 1) { // Change back to gameMusic for levels 1-10 LK.playMusic('gameMusic', { fade: { start: 0, end: 1, duration: 1000 } }); } // Win condition - player has survived 20 waves if (wave > 20) { LK.showYouWin(); return; } } // Auto fire if player holds down finger (increased frequency) if (LK.ticks % 10 === 0) { player.shoot(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemyCat', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = 'basic';
self.health = 1;
self.speed = 6;
self.pointValue = 10;
self.isActive = true;
self.movePattern = 'straight';
self.movementTime = 0;
self.direction = 1; // 1 right, -1 left
self.update = function () {
if (self.isActive) {
self.movementTime += 2;
// Move based on pattern
if (self.movePattern === 'straight') {
self.y += self.speed;
} else if (self.movePattern === 'zigzag') {
self.y += self.speed;
self.x += Math.sin(self.movementTime * 0.05) * 3;
} else if (self.movePattern === 'teleport') {
// Always move down
self.y += self.speed;
// And occasionally teleport horizontally
if (self.movementTime % 120 === 0) {
// Teleport every 2 seconds
self.x = 100 + Math.random() * (2048 - 200);
LK.effects.flashObject(self, 0xffffff, 300);
}
}
// Advanced enemies occasionally shoot lasers with increasing frequency in higher waves
var shootChance = 0.01; // Base chance
if (wave > 10) {
shootChance = 0.015 + (wave - 10) * 0.001; // Increases with each wave after 10
shootChance = Math.min(shootChance, 0.03); // Cap at 3%
}
if ((self.type === 'zigzag' || self.type === 'teleport') && Math.random() < shootChance) {
var laser = new EnemyLaser();
// Adjust laser speed based on wave
if (wave > 10) {
laser.speed = 10 + Math.min(5, Math.floor((wave - 10) / 3));
}
laser.x = self.x;
laser.y = self.y + 30;
enemyLasers.push(laser);
game.addChild(laser);
}
// Remove enemy when it goes off screen
if (self.y > 2732 + 50) {
self.isActive = false;
// Decrease lives when enemy passes bottom of screen
if (livesCount > 0 && self.type !== 'boss' && self.type !== 'boss2') {
livesCount--;
livesText.setText('Lives: ' + livesCount);
// Flash the lives text red to indicate loss
tween(livesText, {
tint: 0xff0000
}, {
duration: 300,
onFinish: function onFinish() {
tween(livesText, {
tint: 0xffffff
}, {
duration: 300
});
}
});
// Game over if lives reach zero
if (livesCount <= 0) {
gameActive = false;
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
// Flash the enemy red when hit
LK.effects.flashObject(self, 0xff0000, 300);
if (self.health <= 0) {
// Play explosion sound
LK.getSound('explosion').play();
// Create explosion effect
var explosion = new Explosion();
explosion.x = self.x;
explosion.y = self.y;
game.addChild(explosion);
// Create particles for more dramatic effect
for (var i = 0; i < 6; i++) {
var particle = new Explosion();
particle.x = self.x + Math.random() * 60 - 30;
particle.y = self.y + Math.random() * 60 - 30;
particle.duration = 20 + Math.random() * 10;
game.addChild(particle);
}
// Chance to drop power-up (15%)
if (Math.random() < 0.15) {
var powerUp = new PowerUp();
powerUp.x = self.x;
powerUp.y = self.y;
// Randomly choose power-up type
var powerType = Math.random();
if (powerType < 0.5) {
powerUp.setType('spreadshot');
} else if (powerType < 0.8) {
powerUp.setType('shield');
} else {
powerUp.setType('bomb');
}
powerUps.push(powerUp);
game.addChild(powerUp);
}
self.isActive = false;
}
};
self.setType = function (newType) {
self.type = newType;
// Get wave-based difficulty multiplier (increases after wave 10)
var difficultyMult = wave > 10 ? 1.5 : 1;
// First remove any existing graphics
self.removeChildren();
// Add the appropriate graphic based on the wave
var assetType = wave > 10 ? 'enemyCat2' : 'enemyCat';
var enemyGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
// For enemyCat2, apply scaling since it's smaller by default
if (wave > 10) {
enemyGraphics.scale.set(3, 3);
}
if (newType === 'basic') {
enemyGraphics.tint = 0xffcc00;
self.health = Math.ceil(2 * difficultyMult);
self.speed = Math.min(5, 3 * difficultyMult);
self.pointValue = Math.ceil(10 * difficultyMult);
self.movePattern = 'straight';
} else if (newType === 'fast') {
enemyGraphics.tint = 0xff9900;
self.health = Math.ceil(2 * difficultyMult);
self.speed = Math.min(7, 5 * difficultyMult);
self.pointValue = Math.ceil(15 * difficultyMult);
self.movePattern = 'straight';
} else if (newType === 'zigzag') {
enemyGraphics.tint = 0x66cc00;
self.health = Math.ceil(3 * difficultyMult);
self.speed = Math.min(5, 3 * difficultyMult);
self.pointValue = Math.ceil(20 * difficultyMult);
self.movePattern = 'zigzag';
} else if (newType === 'teleport') {
enemyGraphics.tint = 0xcc33ff;
self.health = Math.ceil(4 * difficultyMult);
self.speed = Math.min(4, 2 * difficultyMult);
self.pointValue = Math.ceil(30 * difficultyMult);
self.movePattern = 'teleport';
}
};
return self;
});
var BossCat = Enemy.expand(function () {
var self = Enemy.call(this);
// Remove the previous graphic and add boss graphic
self.removeChildren();
var bossGraphics = self.attachAsset('bossCat', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = 'boss';
self.health = 80; // First boss has 80 HP (increased from 50)
self.speed = 1;
self.pointValue = 200;
self.movePattern = 'boss';
self.phase = 0;
self.shootCooldown = 0;
self.isFinalBoss = false; // Track if this is the final boss
// Override update method
self.update = function () {
if (self.isActive) {
self.movementTime++;
// Boss movement pattern
if (self.phase === 0) {
// Move down to position
self.y += self.speed;
if (self.y >= 300) {
self.phase = 1;
self.movementTime = 0;
}
} else if (self.phase === 1) {
// Move slowly towards player's position
if (player && player.x) {
// Calculate direction to player
var directionX = player.x - self.x;
// Move slowly towards player (0.5% of the distance per frame)
self.x += directionX * 0.005;
}
// Add slight vertical movement
self.y += Math.sin(self.movementTime * 0.01) * 1;
// Phase transition based on health percentage
var healthPercent = self.isFinalBoss ? self.health / 100 : self.health / 50;
if (healthPercent <= 0.5 && self.phase < 2) {
self.phase = 2;
self.speed = 1.5;
LK.effects.flashObject(self, 0xff0000, 1000);
}
} else if (self.phase === 2) {
// Move towards player faster in aggressive phase
if (player && player.x) {
var directionX = player.x - self.x;
// Move faster towards player (1% of the distance per frame)
self.x += directionX * 0.01;
}
// Add some vertical movement
self.y += Math.sin(self.movementTime * 0.02) * 2;
}
// Boss shooting logic
self.shootCooldown--;
if (self.shootCooldown <= 0) {
// Shoot pattern based on phase
if (self.phase === 1) {
// Single shot during phase 1, less frequent
self.shootLaser();
self.shootCooldown = 180; // 3 seconds (doubled from original)
} else if (self.phase === 2) {
// Double shot during phase 2, less frequent
self.shootLaser();
self.shootLaser(-30, 0.3);
self.shootCooldown = 120; // 2 seconds (doubled from original)
}
}
}
};
// Boss shooting method
self.shootLaser = function (offsetX, rotation) {
offsetX = offsetX || 0;
rotation = rotation || 0;
var laser = new EnemyLaser();
laser.x = self.x + offsetX;
laser.y = self.y + 100;
if (rotation !== 0) {
laser.rotation = rotation;
}
enemyLasers.push(laser);
game.addChild(laser);
};
// Set boss as final boss
self.setAsFinalBoss = function () {
self.isFinalBoss = true;
self.health = 150; // Final boss has 150 HP (increased from 100)
self.pointValue = 500;
tween(bossGraphics, {
tint: 0xff0000
}, {
duration: 1000
});
};
// Override takeDamage to show health
var originalTakeDamage = self.takeDamage;
self.takeDamage = function (damage) {
originalTakeDamage.call(self, damage);
// Update boss health display
if (bossHealthText) {
bossHealthText.setText("Boss HP: " + self.health);
}
// Drop heart power-up when boss is defeated
if (self.health <= 0) {
// 100% chance to drop heart from boss
var heart = new PowerUp();
heart.x = self.x;
heart.y = self.y;
heart.setType('heart');
powerUps.push(heart);
game.addChild(heart);
}
};
return self;
});
var Boss2 = BossCat.expand(function () {
var self = BossCat.call(this);
// Replace boss graphic with new boss
self.removeChildren();
var bossGraphics = self.attachAsset('enemyCat2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 3
});
self.type = 'boss2';
self.health = 200; // Second boss has 200 HP by default
self.speed = 1.5;
self.pointValue = 300;
self.movementTime = 0;
self.attackPattern = 0;
self.attackTimer = 0;
// Override update method
var originalUpdate = self.update;
self.update = function () {
if (self.isActive) {
self.movementTime++;
self.attackTimer++;
// Boss2 movement pattern
if (self.phase === 0) {
// Move down to position
self.y += self.speed;
if (self.y >= 350) {
self.phase = 1;
self.movementTime = 0;
}
} else if (self.phase === 1) {
// More complex movement
self.x += Math.sin(self.movementTime * 0.02) * 3;
self.y += Math.cos(self.movementTime * 0.01) * 2;
// Phase transition based on health percentage
var healthPercent = self.isFinalBoss ? self.health / 250 : self.health / 200;
if (healthPercent <= 0.5 && self.phase < 2) {
self.phase = 2;
self.speed = 2;
self.attackPattern = 1;
LK.effects.flashObject(self, 0xff0000, 1000);
}
} else if (self.phase === 2) {
// More aggressive pattern
self.x += Math.sin(self.movementTime * 0.03) * 5;
self.y += Math.sin(self.movementTime * 0.02) * 3;
// Occasionally teleport
if (self.movementTime % 180 === 0) {
self.x = 400 + Math.random() * (2048 - 800);
LK.effects.flashObject(self, 0xffffff, 300);
}
}
// Boss2 shooting logic
self.shootCooldown--;
if (self.shootCooldown <= 0) {
if (self.phase === 1) {
// Triple shot pattern
self.shootLaser();
self.shootLaser(-50, -0.2);
self.shootLaser(50, 0.2);
self.shootCooldown = 150;
} else if (self.phase === 2) {
// More complex attack patterns
if (self.attackPattern === 0) {
// Spiral pattern
for (var i = 0; i < 6; i++) {
var angle = self.attackTimer * 0.01 + i * Math.PI / 3;
var offsetX = Math.cos(angle) * 80;
var offsetY = Math.sin(angle) * 80;
self.shootLaser(offsetX, angle * 0.2);
}
self.shootCooldown = 240;
self.attackPattern = 1;
} else {
// Targeted shots
if (player && player.x) {
var directionX = player.x - self.x;
var angle = Math.atan2(player.y - self.y, directionX);
self.shootLaser(0, angle * 0.3);
self.shootLaser(-30, angle * 0.25);
self.shootLaser(30, angle * 0.35);
}
self.shootCooldown = 180;
self.attackPattern = 0;
}
}
}
}
};
// Set boss as final boss
self.setAsFinalBoss = function () {
self.isFinalBoss = true;
self.health = 250; // Final boss2 has 250 HP
self.pointValue = 800;
tween(bossGraphics, {
tint: 0xff3300
}, {
duration: 1000
});
};
// Override takeDamage to drop heart
var originalTakeDamage = self.takeDamage;
self.takeDamage = function (damage) {
originalTakeDamage.call(self, damage);
// Drop heart power-up when boss is defeated
if (self.health <= 0) {
// 100% chance to drop heart from boss
var heart = new PowerUp();
heart.x = self.x;
heart.y = self.y;
heart.setType('heart');
powerUps.push(heart);
game.addChild(heart);
}
};
return self;
});
var EnemyLaser = Container.expand(function () {
var self = Container.call(this);
var laserGraphics = self.attachAsset('laser', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff6600
});
self.speed = 20; // Increased from 8
self.damage = 1;
self.isActive = true;
self.update = function () {
if (self.isActive) {
self.y += self.speed;
// Remove laser when it goes off screen
if (self.y > 2732 + 50) {
self.isActive = false;
}
}
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
// Create the explosion frames (will be hidden at first except frame 1)
var frame1 = self.attachAsset('explosionFrame1', {
anchorX: 0.5,
anchorY: 0.5
});
var frame2 = self.attachAsset('explosionFrame2', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
var frame3 = self.attachAsset('explosionFrame3', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
var frame4 = self.attachAsset('explosionFrame4', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
self.isActive = true;
self.duration = 40; // Duration increased slightly
self.timer = 0;
self.currentFrame = 1;
self.frames = [frame1, frame2, frame3, frame4];
self.update = function () {
if (self.isActive) {
self.timer++;
// Animation frame timing (10 frames per explosion frame)
var frameIndex = Math.floor(self.timer / 10);
if (frameIndex >= 0 && frameIndex < 4 && frameIndex !== self.currentFrame - 1) {
// Hide all frames
self.frames.forEach(function (frame) {
frame.visible = false;
});
// Show current frame
self.currentFrame = frameIndex + 1;
self.frames[frameIndex].visible = true;
// Apply scale and rotation effects to current frame
var progress = self.timer / self.duration;
var currentScale = 1 + progress;
self.frames[frameIndex].scale.set(currentScale, currentScale);
self.frames[frameIndex].rotation = progress * Math.PI * 0.5;
}
// Remove when animation complete
if (self.timer >= self.duration) {
self.isActive = false;
}
}
};
return self;
});
var Laser = Container.expand(function () {
var self = Container.call(this);
var laserGraphics = self.attachAsset('laser', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -30;
self.damage = 1;
self.isActive = true;
self.update = function () {
if (self.isActive) {
self.y += self.speed;
// Remove laser when it goes off screen
if (self.y < -50) {
self.isActive = false;
}
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.shootCooldown = 0;
self.cooldownTime = 30; // Frames between shots (increased from 15)
self.hasShield = false;
self.hasSpreadshot = false;
self.spreadDuration = 0;
self.shield = null;
self.maxHealth = 100;
self.health = self.maxHealth; // Starting with full health
// Define health state thresholds
self.healthStateThresholds = {
green: 0.66,
// Above 66% is green (full health)
yellow: 0.33 // Above 33% is yellow, below is red
};
self.update = function () {
// Decrease cooldown
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
// Decrease spreadshot duration
if (self.hasSpreadshot) {
self.spreadDuration--;
if (self.spreadDuration <= 0) {
self.hasSpreadshot = false;
}
}
// Update health bar directly on player
healthBarFill.scale.x = self.health / self.maxHealth;
// Update health text
if (healthText) {
healthText.setText(Math.ceil(self.health) + "/" + self.maxHealth);
}
};
self.shoot = function () {
if (self.shootCooldown <= 0) {
if (self.hasSpreadshot) {
// Create spread shot (3 lasers)
var centerLaser = new Laser();
centerLaser.x = self.x;
centerLaser.y = self.y - 60;
lasers.push(centerLaser);
game.addChild(centerLaser);
var leftLaser = new Laser();
leftLaser.x = self.x - 40;
leftLaser.y = self.y - 60;
leftLaser.rotation = -0.3;
lasers.push(leftLaser);
game.addChild(leftLaser);
var rightLaser = new Laser();
rightLaser.x = self.x + 40;
rightLaser.y = self.y - 60;
rightLaser.rotation = 0.3;
lasers.push(rightLaser);
game.addChild(rightLaser);
} else {
// Create single laser
var laser = new Laser();
laser.x = self.x;
laser.y = self.y - 40;
lasers.push(laser);
game.addChild(laser);
}
LK.getSound('shoot').play();
self.shootCooldown = self.cooldownTime;
}
};
self.activateShield = function () {
// Remove existing shield if there is one
if (self.shield && self.shield.isActive) {
self.shield.isActive = false;
game.removeChild(self.shield);
}
// Create new shield
self.hasShield = true;
self.shield = new Shield();
self.shield.x = self.x;
self.shield.y = self.y;
game.addChild(self.shield);
return self.shield;
};
self.activateSpreadshot = function () {
self.hasSpreadshot = true;
self.spreadDuration = 600; // 3 seconds at 60fps (reduced from 5 seconds)
};
self.activateBomb = function () {
// Destroy all enemies on screen
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.isActive) {
enemy.takeDamage(999); // Instant kill
LK.setScore(LK.getScore() + enemy.pointValue);
}
}
// Visual effect for bomb
LK.effects.flashScreen(0xff0000, 500);
};
self.takeDamage = function (damage) {
// Store previous health percentage to detect state transitions
var prevHealthPercent = self.health / self.maxHealth;
self.health -= damage;
// Play hit sound
LK.getSound('hitSound').play();
// Change player graphic to hit animation
self.removeChildren();
self.attachAsset('playerHit', {
anchorX: 0.5,
anchorY: 0.5
});
// Add health bar and text back
self.addChild(healthBarFill);
self.addChild(healthText);
// Return to normal graphic after a short delay
LK.setTimeout(function () {
self.removeChildren();
playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Add health bar and text back again
self.addChild(healthBarFill);
self.addChild(healthText);
}, 300);
// Flash the player red when hit
LK.effects.flashObject(self, 0xff0000, 300);
// Update health bar
if (healthBarFill) {
healthBarFill.scale.x = Math.max(0, self.health / self.maxHealth);
// Get new health percentage
var healthPercent = self.health / self.maxHealth;
// Change health bar color based on percentage
if (healthPercent >= 0.66) {
healthBarFill.tint = 0x00ff00; // Green for high health
} else if (healthPercent >= 0.33) {
healthBarFill.tint = 0xffcc00; // Yellow/orange for medium health
} else {
healthBarFill.tint = 0xff0000; // Red for low health
}
// Check for transition between health states
if (prevHealthPercent > 0.66 && healthPercent <= 0.66 || prevHealthPercent > 0.33 && healthPercent <= 0.33) {
// Visual effect for health state degradation
tween(healthBarFill, {
alpha: 0.2
}, {
duration: 300,
onFinish: function onFinish() {
tween(healthBarFill, {
alpha: 1
}, {
duration: 300
});
}
});
}
}
// Check if player is dead
if (self.health <= 0) {
gameActive = false;
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
return self.health <= 0; // Return true if player died
};
self.heal = function (amount) {
// Store previous health percentage to detect state transitions
var prevHealthPercent = self.health / self.maxHealth;
self.health = Math.min(self.maxHealth, self.health + amount);
// Update health bar
if (healthBarFill) {
healthBarFill.scale.x = self.health / self.maxHealth;
// Get new health percentage
var healthPercent = self.health / self.maxHealth;
// Change health bar color based on percentage
if (healthPercent >= 0.66) {
healthBarFill.tint = 0x00ff00; // Green for high health
} else if (healthPercent >= 0.33) {
healthBarFill.tint = 0xffcc00; // Yellow/orange for medium health
} else {
healthBarFill.tint = 0xff0000; // Red for low health
}
// Check for transition between health states
if (prevHealthPercent <= 0.33 && healthPercent > 0.33 || prevHealthPercent <= 0.66 && healthPercent > 0.66) {
// Visual effect for health state improvement
tween(healthBarFill, {
alpha: 0.2
}, {
duration: 300,
onFinish: function onFinish() {
tween(healthBarFill, {
alpha: 1
}, {
duration: 300
});
}
});
}
}
// Visual healing effect
LK.effects.flashObject(self, 0x00ff00, 300);
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = 'spreadshot'; // Default type
self.speed = 6;
self.isActive = true;
self.update = function () {
if (self.isActive) {
self.y += self.speed;
// Rotate the power-up for visual effect
powerUpGraphics.rotation += 0.05;
// Remove power-up when it goes off screen
if (self.y > 2732 + 50) {
self.isActive = false;
}
}
};
self.setType = function (newType) {
self.type = newType;
// Remove previous graphics
self.removeChildren();
// Change appearance based on type
if (newType === 'spreadshot') {
powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (newType === 'shield') {
powerUpGraphics = self.attachAsset('powerUpShield', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (newType === 'bomb') {
powerUpGraphics = self.attachAsset('powerUpBomb', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (newType === 'heart') {
powerUpGraphics = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
}
};
return self;
});
var Shield = Container.expand(function () {
var self = Container.call(this);
var shieldGraphics = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
self.duration = 6000; // Shield lasts 3 seconds (reduced from 5)
self.timeLeft = self.duration;
self.isActive = true;
self.update = function () {
if (self.isActive) {
self.timeLeft -= 1000 / 60; // Decrease time left (60 fps)
// Fade out as shield expires
shieldGraphics.alpha = 0.2 + self.timeLeft / self.duration * 0.5;
// Rotate the shield for visual effect
shieldGraphics.rotation += 0.01;
// Deactivate shield when time runs out
if (self.timeLeft <= 0) {
self.isActive = false;
// Remove shield reference from player
if (player) {
player.hasShield = false;
player.shield = null;
}
// Remove this shield from the game when it expires
game.removeChild(self);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000033
});
/****
* Game Code
****/
// Game state variables
function _createForOfIteratorHelper(r, e) {
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (!t) {
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
t && (r = t);
var _n = 0,
F = function F() {};
return {
s: F,
n: function n() {
return _n >= r.length ? {
done: !0
} : {
done: !1,
value: r[_n++]
};
},
e: function e(r) {
throw r;
},
f: F
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var o,
a = !0,
u = !1;
return {
s: function s() {
t = t.call(r);
},
n: function n() {
var r = t.next();
return a = r.done, r;
},
e: function e(r) {
u = !0, o = r;
},
f: function f() {
try {
a || null == t["return"] || t["return"]();
} finally {
if (u) {
throw o;
}
}
}
};
}
function _unsupportedIterableToArray(r, a) {
if (r) {
if ("string" == typeof r) {
return _arrayLikeToArray(r, a);
}
var t = {}.toString.call(r).slice(8, -1);
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
}
}
function _arrayLikeToArray(r, a) {
(null == a || a > r.length) && (a = r.length);
for (var e = 0, n = Array(a); e < a; e++) {
n[e] = r[e];
}
return n;
}
var player;
var lasers = [];
var enemyLasers = [];
var enemies = [];
var powerUps = [];
var wave = 1;
var enemiesInWave = 5;
var enemiesSpawned = 0;
var spawnCooldown = 0;
var gameActive = true;
var bossWave = false;
var bossHealthText;
var healthBar;
var healthBarBg;
var healthBarFill;
var livesCount = 10;
var livesText;
// UI elements
var scoreTxt = new Text2('Score\r\n0', {
size: 100,
fill: 0xFFFFFF,
dropShadow: true,
align: 'center'
});
scoreTxt.setText("Score\r\n" + LK.getScore());
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var waveTxt = new Text2('Wave\r\n1', {
size: 80,
fill: 0xFFFFFF,
dropShadow: true,
align: 'center'
});
waveTxt.anchor.set(1.0, 0);
LK.gui.topRight.addChild(waveTxt);
// Position it away from the top left corner (reserved for menu icon)
waveTxt.x = 0;
// Lives counter display
livesText = new Text2('Lives: ' + livesCount, {
size: 80,
fill: 0xFFFFFF
});
livesText.anchor.set(0.5, 0);
LK.gui.bottom.addChild(livesText);
// Add background image
var background = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: 2048,
height: 2732
});
background.x = 2048 / 2;
background.y = 2732 / 2;
game.addChild(background);
// Create background clone first to ensure it's below the player
if (!game.backgroundClone) {
// Create a clone of the background
game.backgroundClone = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: 2048,
height: 2732
});
// Position the clone directly above the original background
game.backgroundClone.x = background.x;
game.backgroundClone.y = background.y - background.height;
game.addChild(game.backgroundClone);
}
// Create player after all background elements
player = new Player();
player.x = 2048 / 2;
player.y = 2732 - 200;
player.cooldownTime = 10; // Reduced cooldown between shots (from 30)
// Add player last so it appears on top of all background elements
game.addChild(player);
// Create health bar - directly attached to player
healthBarFill = LK.getAsset('baseBox', {
anchorX: 0,
// Anchor at the left edge for scaling from left to right
anchorY: 0.5,
tint: 0x00ff00,
// Set tint to green for full health explicitly in creation
scaleX: 10,
scaleY: 0.5 // Base height scale factor (visual size)
});
// Ensure bar scale correctly represents 100% health at the start
healthBarFill.scale.x = player.health / player.maxHealth; // Set scale based on current health percentage
// Create health text display
var healthText = new Text2('100/100', {
size: 40,
fill: 0xFFFFFF
});
healthText.anchor.set(0.5, 0);
healthText.y = 0; // Position below health bar
// Attach directly to player
player.addChild(healthBarFill);
player.addChild(healthText);
// Position relative to player - higher placement
healthBarFill.y = -70;
healthBarFill.x = -50;
// Position health text above health bar
healthText.y = -120;
// Set initial animation for health bar to draw player's attention
tween(healthBarFill, {
alpha: 0.5
}, {
duration: 500,
onFinish: function onFinish() {
tween(healthBarFill, {
alpha: 1
}, {
duration: 500
});
}
});
// Start background music with fade in effect
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 1,
duration: 1000
}
});
// Game input handlers
game.down = function (x, y, obj) {
// Shoot when tapping anywhere
player.shoot();
};
game.move = function (x, y, obj) {
// Move player horizontally (keep vertical position fixed)
if (gameActive) {
player.x = x;
// Keep player within game bounds
if (player.x < 75) {
player.x = 75;
}
if (player.x > 2048 - 75) {
player.x = 2048 - 75;
}
// Update shield position if active
if (player.hasShield && player.shield && player.shield.isActive) {
player.shield.x = player.x;
player.shield.y = player.y;
}
}
};
// Spawn enemies
function spawnEnemy() {
var enemy;
if (bossWave) {
// Use Boss2 for waves 15 and 20
if (wave >= 15 && wave % 5 === 0) {
enemy = new Boss2();
enemy.x = 2048 / 2;
enemy.y = -200;
// If this is the final boss (wave 20), set it to have higher HP
if (wave === 20) {
enemy.setAsFinalBoss();
}
} else {
enemy = new BossCat();
enemy.x = 2048 / 2;
enemy.y = -200;
// If this is the final boss of the first stage (wave 10), set it to have higher HP
if (wave === 10) {
enemy.setAsFinalBoss();
}
}
// Create boss health display
bossHealthText = new Text2("Boss HP: " + enemy.health, {
size: 60,
fill: 0xFF6600
});
bossHealthText.anchor.set(0.5, 0);
bossHealthText.y = 150;
LK.gui.top.addChild(bossHealthText);
} else {
enemy = new Enemy();
enemy.x = 100 + Math.random() * (2048 - 200);
enemy.y = -100;
// Set random enemy type based on current wave
var typeRoll = Math.random();
if (wave <= 2) {
// Waves 1-2: Only basic enemies
enemy.setType('basic');
} else if (wave <= 4) {
// Waves 3-4: Basic and fast enemies
if (typeRoll < 0.6) {
enemy.setType('basic');
} else {
enemy.setType('fast');
}
} else if (wave <= 6) {
// Waves 5-6: Add zigzag enemies
if (typeRoll < 0.4) {
enemy.setType('basic');
} else if (typeRoll < 0.7) {
enemy.setType('fast');
} else {
enemy.setType('zigzag');
}
} else if (wave <= 10) {
// Waves 7-10: All enemy types
if (typeRoll < 0.3) {
enemy.setType('basic');
} else if (typeRoll < 0.5) {
enemy.setType('fast');
} else if (typeRoll < 0.8) {
enemy.setType('zigzag');
} else {
enemy.setType('teleport');
}
} else {
// Waves 11-20: Harder distribution with fewer basic enemies
if (typeRoll < 0.15) {
enemy.setType('basic');
} else if (typeRoll < 0.4) {
enemy.setType('fast');
} else if (typeRoll < 0.7) {
enemy.setType('zigzag');
} else {
enemy.setType('teleport');
}
}
}
enemies.push(enemy);
game.addChild(enemy);
enemiesSpawned++;
}
// Main game update loop
game.update = function () {
if (!gameActive) {
return;
}
// Track and update explosions
var explosions = [];
var _iterator = _createForOfIteratorHelper(game.children),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var child = _step.value;
if (child instanceof Explosion) {
explosions.push(child);
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
for (var i = explosions.length - 1; i >= 0; i--) {
var explosion = explosions[i];
//explosion.update();
if (!explosion.isActive) {
game.removeChild(explosion);
}
}
// Set up background scrolling with two identical backgrounds side by side
if (!game.backgroundClone) {
// Create a clone of the background
game.backgroundClone = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
width: 2048,
height: 2732
});
// Position the clone directly above the original background
game.backgroundClone.x = background.x;
game.backgroundClone.y = background.y - background.height;
game.addChild(game.backgroundClone);
}
// Scroll both backgrounds
background.y += 5; // Increased scroll speed
game.backgroundClone.y += 5; // Same increased speed for clone
// If original background goes completely off screen, move it above the clone
if (background.y - background.height / 2 > 2732) {
background.y = game.backgroundClone.y - background.height;
}
// If clone background goes completely off screen, move it above the original
if (game.backgroundClone.y - game.backgroundClone.height / 2 > 2732) {
game.backgroundClone.y = background.y - background.height;
}
// Update player
//player.update();
// Update shield if active
if (player.hasShield && player.shield) {
//player.shield.update();
if (player.shield && !player.shield.isActive) {
player.hasShield = false;
game.removeChild(player.shield);
player.shield = null;
}
}
// Handle enemy spawning
if (spawnCooldown <= 0) {
if (enemiesSpawned < enemiesInWave) {
spawnEnemy();
// Cooldown between spawns
if (bossWave) {
spawnCooldown = 1; // Boss spawns immediately
} else {
spawnCooldown = 60; // 1 second between normal enemy spawns
}
}
} else {
spawnCooldown--;
}
// Update lasers and check for collisions
for (var i = lasers.length - 1; i >= 0; i--) {
var laser = lasers[i];
//laser.update();
if (!laser.isActive) {
game.removeChild(laser);
lasers.splice(i, 1);
continue;
}
// Check for collisions with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (enemy.isActive && laser.isActive && laser.intersects(enemy)) {
enemy.takeDamage(laser.damage);
laser.isActive = false;
if (!enemy.isActive) {
LK.setScore(LK.getScore() + enemy.pointValue);
scoreTxt.setText("Score\r\n" + LK.getScore());
game.removeChild(enemy);
enemies.splice(j, 1);
}
break;
}
}
}
// Update enemy lasers and check for collisions with player
for (var el = enemyLasers.length - 1; el >= 0; el--) {
var enemyLaser = enemyLasers[el];
//enemyLaser.update();
if (!enemyLaser.isActive) {
game.removeChild(enemyLaser);
enemyLasers.splice(el, 1);
continue;
}
// Check for collision with player
if (enemyLaser.intersects(player)) {
// If player has shield, block the laser
if (player.hasShield) {
enemyLaser.isActive = false;
game.removeChild(enemyLaser);
enemyLasers.splice(el, 1);
// Flash shield to show impact
if (player.shield) {
LK.effects.flashObject(player.shield, 0xffff00, 300);
}
} else {
// Player takes damage from laser - only one point of health
var laserDamage = 1;
player.takeDamage(laserDamage);
enemyLaser.isActive = false;
game.removeChild(enemyLaser);
enemyLasers.splice(el, 1);
if (!gameActive) {
return;
} // Return if player died
}
}
}
// Update enemies
var activeEnemies = 0;
for (var k = enemies.length - 1; k >= 0; k--) {
var enemy = enemies[k];
//enemy.update();
if (!enemy.isActive) {
game.removeChild(enemy);
enemies.splice(k, 1);
continue;
}
activeEnemies++;
// Check collision with player
if (enemy.intersects(player)) {
// Initialize lastDamageTime if not set
if (enemy.lastDamageTime === undefined) {
enemy.lastDamageTime = 0;
}
// Check if 3 seconds (180 frames at 60fps) have passed since last damage
var currentTime = LK.ticks;
var damageInterval = 180; // 3 seconds at 60fps
if (player.hasShield) {
// Shield absorbs collision damage
if (player.shield) {
LK.effects.flashObject(player.shield, 0xffff00, 300);
}
} else {
// Player takes damage from collision only every 3 seconds
var collisionDamage = 10;
// Apply damage only if enough time has passed
if (currentTime - enemy.lastDamageTime >= damageInterval) {
player.takeDamage(collisionDamage);
enemy.lastDamageTime = currentTime;
// Visual feedback that damage was applied
LK.effects.flashObject(enemy, 0xff0000, 300);
}
if (!gameActive) {
return;
} // Return if player died
}
}
}
// Update power-ups
for (var l = powerUps.length - 1; l >= 0; l--) {
var powerUp = powerUps[l];
//powerUp.update();
if (!powerUp.isActive) {
game.removeChild(powerUp);
powerUps.splice(l, 1);
continue;
}
// Check collision with player
if (powerUp.intersects(player)) {
// Apply power-up effect
if (powerUp.type === 'spreadshot') {
player.activateSpreadshot();
} else if (powerUp.type === 'shield') {
player.activateShield();
} else if (powerUp.type === 'bomb') {
player.activateBomb();
} else if (powerUp.type === 'heart') {
player.heal(50); // Restore 50 health points
}
LK.getSound('powerup').play();
powerUp.isActive = false;
game.removeChild(powerUp);
powerUps.splice(l, 1);
}
}
// Check if wave is complete
if (enemiesSpawned >= enemiesInWave && activeEnemies === 0) {
// Wave complete, start next wave
wave++;
waveTxt.setText("Wave\r\n" + wave);
// Every 5th wave is a boss wave
if (wave % 5 === 0) {
bossWave = true;
enemiesInWave = 1;
} else {
bossWave = false;
// Reduced enemies per wave to make the game easier
enemiesInWave = 5 + Math.floor(wave * 1.5);
// Remove boss health display if it exists
if (bossHealthText) {
LK.gui.top.removeChild(bossHealthText);
bossHealthText = null;
}
}
enemiesSpawned = 0;
spawnCooldown = 120; // 2 second delay between waves
// Check for music changes between levels 1-10 and 11-20
if (wave == 11) {
// Change to gameMusic2 for levels 11-20
LK.playMusic('gameMusic2', {
fade: {
start: 0,
end: 1,
duration: 1000
}
});
} else if (wave == 1) {
// Change back to gameMusic for levels 1-10
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 1,
duration: 1000
}
});
}
// Win condition - player has survived 20 waves
if (wave > 20) {
LK.showYouWin();
return;
}
}
// Auto fire if player holds down finger (increased frequency)
if (LK.ticks % 10 === 0) {
player.shoot();
}
};
explosion 💥. In-Game asset. 2d. High contrast. No shadows
a cat head. In-Game asset. 2d. High contrast
make this cat expression goes silly but angry
2 cucumbers inside a glass bubble. In-Game asset. 2d. High contrast. No shadows
a shield inside a glass bubble. In-Game asset. 2d. High contrast. No shadows
an explosion inside a glass bubble. In-Game asset. 2d. High contrast. No shadows
a heart inside a glass bubble. In-Game asset. 2d. High contrast. No shadows