/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Asteroid = Container.expand(function () { var self = Container.call(this); var asteroidGraphics = self.attachAsset('asteroid', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); self.speed = 6; self.rotationSpeed = Math.random() * 0.05 - 0.025; self.scoreValue = 5; self.lastY = -100; // Track last position for collision detection self.update = function () { self.lastY = self.y; self.y += self.speed; self.rotation += self.rotationSpeed; // Add side-to-side movement to make dodging more challenging self.x += Math.sin(LK.ticks * 0.02) * 2; }; return self; }); var BadOil = Container.expand(function () { var self = Container.call(this); var badOilGraphics = self.attachAsset('Bad-oil', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); self.speed = 5; self.lastY = -100; self.update = function () { self.lastY = self.y; self.y += self.speed; // Add some side movement self.x += Math.sin(LK.ticks * 0.03) * 2; }; return self; }); var BossEnemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.5, scaleY: 2.5, tint: 0xff0000 }); self.speed = 2; self.health = 5; self.moveDirection = 1; // 1 for right, -1 for left self.shootChance = 0.03; // Higher chance to shoot than regular enemies self.scoreValue = 50; self.lastY = -100; self.update = function () { self.lastY = self.y; // Move down more slowly self.y += self.speed; // Move in a more complex pattern self.x += self.moveDirection * 3 * Math.sin(LK.ticks * 0.02); // Change direction at edges if (self.x < 200 || self.x > 2048 - 200) { self.moveDirection *= -1; } }; return self; }); var EarthMonster = Container.expand(function () { var self = Container.call(this); var monsterGraphics = self.attachAsset('Earth-monster', { anchorX: 0.5, anchorY: 0.5, scaleX: 3.0, scaleY: 3.0 }); self.speed = 1.5; self.health = 20; // Earth-monster has 20 hearts self.moveDirection = 1; // 1 for right, -1 for left self.shootChance = 0.05; // Higher chance to shoot than other enemies self.scoreValue = 200; self.lastY = -100; self.update = function () { self.lastY = self.y; // Move down more slowly self.y += self.speed; // Move in a complex pattern self.x += self.moveDirection * 2 * Math.sin(LK.ticks * 0.03); // Change direction at edges if (self.x < 300 || self.x > 2048 - 300) { self.moveDirection *= -1; } }; return self; }); var EarthMonsterBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5, tint: 0x00ffff }); self.speed = 12; // Faster than regular enemy bullets self.damage = 3; // Does 3x damage self.update = function () { self.y += self.speed; }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3; self.moveDirection = 1; // 1 for right, -1 for left self.shootChance = 0.01; // Chance to shoot per update self.scoreValue = 10; self.update = function () { // Move down self.y += self.speed; // Move side to side self.x += self.moveDirection * 2; // Change direction at edges if (self.x < 100 || self.x > 2048 - 100) { self.moveDirection *= -1; } }; return self; }); var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.update = function () { self.y += self.speed; }; return self; }); var Heart = Container.expand(function () { var self = Container.call(this); var heartGraphics = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, tint: 0xff0000, scaleX: 0.8, scaleY: 0.8 }); self.setActive = function (active) { heartGraphics.alpha = active ? 1 : 0.3; }; return self; }); var NewAsteroid = Container.expand(function () { var self = Container.call(this); var asteroidGraphics = self.attachAsset('New-ast', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); self.speed = 7; // Faster than regular asteroid self.rotationSpeed = Math.random() * 0.08 - 0.04; // Faster rotation self.scoreValue = 0; // No points for this one since it's deadly self.lastY = -100; // Track last position for collision detection self.update = function () { self.lastY = self.y; self.y += self.speed; self.rotation += self.rotationSpeed; // More erratic movement pattern self.x += Math.sin(LK.ticks * 0.03) * 3; }; return self; }); var NewEnemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('New-enemy', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; // Faster than regular enemy self.moveDirection = 1; // 1 for right, -1 for left self.shootChance = 0.02; // Higher chance to shoot than regular enemies self.scoreValue = 20; // Worth more points than regular enemies self.update = function () { // Only move left and right, no vertical movement // Move side to side more aggressively self.x += self.moveDirection * 3; // Change direction at edges if (self.x < 100 || self.x > 2048 - 100) { self.moveDirection *= -1; } }; return self; }); var OilFood = Container.expand(function () { var self = Container.call(this); var oilFoodGraphics = self.attachAsset('Oil-food', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); self.speed = 5; self.lastY = -100; self.update = function () { self.lastY = self.y; self.y += self.speed; // Add some side movement self.x += Math.sin(LK.ticks * 0.03) * 2; }; return self; }); var PlayerBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -15; self.update = function () { self.y += self.speed; }; return self; }); var PlayerShip = Container.expand(function () { var self = Container.call(this); var shipGraphics = self.attachAsset('playerShip', { anchorX: 0.5, anchorY: 0.5 }); self.shield = self.attachAsset('shield', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); self.hasShield = false; self.fireRate = 20; // Time between shots in ticks self.fireCooldown = 0; self.rapidFire = false; self.rapidFireTimer = 0; self.lives = 3; // Keep this for backward compatibility self.activateShield = function () { self.hasShield = true; self.shield.alpha = 0.5; }; self.deactivateShield = function () { self.hasShield = false; self.shield.alpha = 0; }; self.activateRapidFire = function () { self.rapidFire = true; self.rapidFireTimer = 300; // 5 seconds at 60 FPS }; self.canFire = function () { if (self.fireCooldown <= 0) { self.fireCooldown = self.rapidFire ? Math.floor(self.fireRate / 2) : self.fireRate; return true; } return false; }; self.hit = function () { if (self.hasShield) { self.deactivateShield(); return false; // Shield absorbed the hit } else { // Use the hearts system instead of lives if (currentHearts > 0) { currentHearts--; updateHearts(); LK.effects.flashObject(self, 0xff0000, 500); return true; // Ship took damage } return false; } }; self.update = function () { if (self.fireCooldown > 0) { self.fireCooldown--; } if (self.rapidFire && self.rapidFireTimer > 0) { self.rapidFireTimer--; if (self.rapidFireTimer <= 0) { self.rapidFire = false; } } }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3; self.type = Math.floor(Math.random() * 2); // 0 for shield, 1 for rapid fire // Set color based on type if (self.type === 0) { powerupGraphics.tint = 0x3498db; // Blue for shield } else { powerupGraphics.tint = 0xf39c12; // Orange for rapid fire } self.update = function () { self.y += self.speed; // Floating animation self.x += Math.sin(LK.ticks * 0.05) * 1; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Save the current game state function saveGame() { storage.set('saveSpace_level', gameLevel); storage.set('saveSpace_score', scoreValue); storage.set('saveSpace_hearts', currentHearts); storage.set('saveSpace_oil', oilPercentage); } // Load the saved game state function loadGame() { var savedLevel = storage.get('saveSpace_level', 1); var savedScore = storage.get('saveSpace_score', 0); var savedHearts = storage.get('saveSpace_hearts', 10); var savedOil = storage.get('saveSpace_oil', 20); gameLevel = savedLevel; scoreValue = savedScore; currentHearts = savedHearts; oilPercentage = savedOil; // Update UI elements levelTxt.setText('Level: ' + gameLevel); scoreTxt.setText('Score: ' + scoreValue); oilTxt.setText('Oil: ' + oilPercentage + '/' + maxOilPercentage); updateHearts(); // Set game difficulty based on loaded level difficultyMultiplier = 1.0 + gameLevel * 0.15; enemySpawnRate = Math.max(60, Math.floor(240 / difficultyMultiplier)); asteroidSpawnRate = Math.max(45, Math.floor(90 / difficultyMultiplier)); oilFoodSpawnRate = Math.min(600, Math.floor(360 * (1 + gameLevel * 0.1))); } // Auto-save every minute LK.setInterval(saveGame, 60000); // Save when player takes damage var originalHit = PlayerShip.prototype.hit; PlayerShip.prototype.hit = function () { var result = originalHit.apply(this, arguments); if (result) { saveGame(); } return result; }; // Save on level up var originalCheckLevelProgress = checkLevelProgress; checkLevelProgress = function checkLevelProgress() { var oldLevel = gameLevel; originalCheckLevelProgress.apply(this, arguments); if (gameLevel > oldLevel) { saveGame(); } }; // Try to load saved game at start loadGame(); game.setBackgroundColor(0x0c1445); // Game variables var player; var playerBullets = []; var enemies = []; var bossEnemies = []; // Track boss enemies separately var enemyBullets = []; var asteroids = []; var powerups = []; var hearts = []; var oilFoods = []; // Array to track oil foods var heartsContainer; var maxHearts = 10; var currentHearts = 10; var gameLevel = 1; var enemySpawnRate = 240; // Reduced enemy spawn rate to focus on dodging asteroids var asteroidSpawnRate = 90; // Increased asteroid spawn rate to create dodging challenge var powerupSpawnRate = 900; // Every 15 seconds - rarer powerups var bossSpawnRate = 600; // How often to check for boss spawn when at level 10 var newEnemySpawnRate = 180; // More frequent than regular enemies var oilFoodSpawnRate = 360; // Every 6 seconds - slightly rarer var gameState = "playing"; var scoreValue = 0; var oilPercentage = 20; // Track oil percentage, starting at 20 out of 40 var maxOilPercentage = 40; // Maximum oil percentage var powerupChance = 0.7; // 70% chance to actually spawn a powerup when the timer triggers var difficultyMultiplier = 1.0; // Base difficulty multiplier that increases with level // Setup score display var scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(scoreTxt); scoreTxt.x = -300; // Offset from right edge // Hearts display - text version as fallback var livesTxt = new Text2('Hearts: 10/10', { size: 60, fill: 0xFFFFFF }); livesTxt.anchor.set(0, 0); LK.gui.topRight.addChild(livesTxt); livesTxt.x = -300; livesTxt.y = 70; // Below score text // Function to update hearts display function updateHearts() { for (var i = 0; i < hearts.length; i++) { hearts[i].setActive(i < currentHearts); } livesTxt.setText('Hearts: ' + currentHearts + '/' + maxHearts); // Game over condition if (currentHearts <= 0) { gameState = "over"; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } } // Level display var levelTxt = new Text2('Level: 1', { size: 60, fill: 0xFFFFFF }); levelTxt.anchor.set(0, 0); LK.gui.topRight.addChild(levelTxt); levelTxt.x = -300; levelTxt.y = 140; // Below lives text // Oil percentage display var oilTxt = new Text2('Oil: 20/40', { size: 60, fill: 0xFFFFFF }); oilTxt.anchor.set(0, 0); LK.gui.topRight.addChild(oilTxt); oilTxt.x = -300; oilTxt.y = 210; // Below level text // Initialize player function initializePlayer() { player = new PlayerShip(); player.x = 2048 / 2; player.y = 2732 - 200; game.addChild(player); // Initialize hearts display initializeHearts(); } // Initialize hearts display function initializeHearts() { // Remove existing hearts if any if (heartsContainer) { heartsContainer.destroy(); hearts = []; } // Create container for hearts heartsContainer = new Container(); game.addChild(heartsContainer); heartsContainer.x = 100; heartsContainer.y = 100; // Create hearts currentHearts = maxHearts; for (var i = 0; i < maxHearts; i++) { var heart = new Heart(); heart.x = i % 5 * 40; heart.y = Math.floor(i / 5) * 40; heart.setActive(true); hearts.push(heart); heartsContainer.addChild(heart); } } // Spawn enemy function spawnEnemy() { var enemy = new Enemy(); enemy.x = Math.random() * (2048 - 200) + 100; enemy.y = -100; enemy.speed = 2 + gameLevel * 0.5 * difficultyMultiplier; // Scale with difficulty multiplier enemy.shootChance = Math.min(0.05, 0.01 + gameLevel * 0.004); // Increase shoot chance with level enemy.health = 1 + Math.floor(gameLevel / 5); // Tougher enemies at higher levels enemies.push(enemy); game.addChild(enemy); } // Spawn asteroid function spawnAsteroid() { // At level 2 and above, randomly spawn the deadly asteroid // Chance increases with level if (gameLevel >= 2 && Math.random() < 0.2 + gameLevel * 0.03) { var deadlyAsteroid = new NewAsteroid(); deadlyAsteroid.x = Math.random() * (2048 - 200) + 100; deadlyAsteroid.y = -100; deadlyAsteroid.speed = 7 + gameLevel * 0.4; // Faster with level asteroids.push(deadlyAsteroid); game.addChild(deadlyAsteroid); } else { var asteroid = new Asteroid(); asteroid.x = Math.random() * (2048 - 200) + 100; asteroid.y = -100; asteroid.speed = 3 + gameLevel * 0.3 * difficultyMultiplier; // Scale with difficulty multiplier asteroids.push(asteroid); game.addChild(asteroid); } } // Spawn power-up function spawnPowerUp() { // Only spawn powerup based on chance - gets rarer with higher levels if (Math.random() < powerupChance - gameLevel * 0.05) { var powerup = new PowerUp(); powerup.x = Math.random() * (2048 - 200) + 100; powerup.y = -100; powerups.push(powerup); game.addChild(powerup); } } // Spawn oil food function spawnOilFood() { var oilFood = new OilFood(); oilFood.x = Math.random() * (2048 - 200) + 100; oilFood.y = -100; oilFoods.push(oilFood); game.addChild(oilFood); } // Spawn bad oil function spawnBadOil() { var badOil = new BadOil(); badOil.x = Math.random() * (2048 - 200) + 100; badOil.y = -100; oilFoods.push(badOil); game.addChild(badOil); } // Spawn new enemy function spawnNewEnemy() { var newEnemy = new NewEnemy(); newEnemy.x = Math.random() * (2048 - 200) + 100; newEnemy.y = -100; newEnemy.speed = 3 + gameLevel * 0.5; // Increase speed with level enemies.push(newEnemy); game.addChild(newEnemy); } // Spawn boss enemy function spawnBossEnemy() { // At level 10, spawn Earth-monster instead of regular boss var boss; if (gameLevel >= 10) { boss = new EarthMonster(); // Create a special alert for Earth-monster var bossAlert = new Text2('EARTH-MONSTER INCOMING!', { size: 100, fill: 0x00FFFF }); } else { boss = new BossEnemy(); // Create a regular boss alert var bossAlert = new Text2('BOSS INCOMING!', { size: 100, fill: 0xFF0000 }); } boss.x = 2048 / 2; boss.y = -200; bossEnemies.push(boss); game.addChild(boss); bossAlert.anchor.set(0.5, 0.5); LK.gui.center.addChild(bossAlert); // Fade out the alert after 2 seconds LK.setTimeout(function () { tween(bossAlert, { alpha: 0 }, { duration: 1000, onComplete: function onComplete() { bossAlert.destroy(); } }); }, 2000); } // Fire player bullet function firePlayerBullet() { if (player && player.canFire()) { var bullet = new PlayerBullet(); bullet.x = player.x; bullet.y = player.y - 50; playerBullets.push(bullet); game.addChild(bullet); LK.getSound('laser').play(); } } // Fire enemy bullet function fireEnemyBullet(enemy) { // Check if enemy is Earth-monster to create special bullets if (enemy instanceof EarthMonster) { // Earth-monster fires 5 bullets at once in a spread pattern for (var i = 0; i < 5; i++) { var bullet = new EarthMonsterBullet(); // Position bullets in a spread pattern bullet.x = enemy.x + (i - 2) * 50; // -100, -50, 0, 50, 100 offset bullet.y = enemy.y + 50; enemyBullets.push(bullet); game.addChild(bullet); } } else { var bullet = new EnemyBullet(); bullet.x = enemy.x; bullet.y = enemy.y + 50; enemyBullets.push(bullet); game.addChild(bullet); } } // Update score function updateScore(points) { scoreValue += points; LK.setScore(scoreValue); scoreTxt.setText('Score: ' + scoreValue); } // Check level progression function checkLevelProgress() { if (scoreValue >= gameLevel * 100) { gameLevel++; levelTxt.setText('Level: ' + gameLevel); // Increase difficulty multiplier difficultyMultiplier = 1.0 + gameLevel * 0.15; // Make game more difficult enemySpawnRate = Math.max(60, Math.floor(240 / difficultyMultiplier)); asteroidSpawnRate = Math.max(45, Math.floor(90 / difficultyMultiplier)); // Decrease oil food spawn rate oilFoodSpawnRate = Math.min(600, Math.floor(360 * (1 + gameLevel * 0.1))); // Make enemies faster and stronger via game update loop // Show level up message var levelUpTxt = new Text2('LEVEL ' + gameLevel + '!', { size: 100, fill: 0xFFFF00 }); levelUpTxt.anchor.set(0.5, 0.5); LK.gui.center.addChild(levelUpTxt); // Fade out the message after 1.5 seconds LK.setTimeout(function () { tween(levelUpTxt, { alpha: 0 }, { duration: 800, onComplete: function onComplete() { levelUpTxt.destroy(); } }); }, 1500); } } // Drag handling var isDragging = false; function handleMove(x, y, obj) { if (isDragging && player) { // Constrain player to screen bounds player.x = Math.max(50, Math.min(2048 - 50, x)); player.y = Math.max(50, Math.min(2732 - 50, y)); } } game.move = handleMove; game.down = function (x, y, obj) { isDragging = true; handleMove(x, y, obj); // Auto-fire when touching firePlayerBullet(); }; game.up = function (x, y, obj) { isDragging = false; }; // Main game loop game.update = function () { if (gameState !== "playing") { return; } // Spawn enemies - spawn multiple based on level if (LK.ticks % enemySpawnRate === 0) { // At higher levels, spawn multiple enemies at once var enemiesToSpawn = 1 + Math.floor(gameLevel / 3); for (var i = 0; i < enemiesToSpawn && i < 4; i++) { // Cap at 4 enemies per spawn spawnEnemy(); } } // Spawn asteroids - more frequent at higher levels if (LK.ticks % asteroidSpawnRate === 0) { // At higher levels, spawn multiple asteroids var asteroidsToSpawn = 1 + Math.floor(gameLevel / 4); for (var i = 0; i < asteroidsToSpawn && i < 3; i++) { // Cap at 3 asteroids per spawn spawnAsteroid(); } } // Spawn powerups - rare chance based on level if (LK.ticks % powerupSpawnRate === 0) { spawnPowerUp(); } // Spawn oil food - less frequent at higher levels if (LK.ticks % oilFoodSpawnRate === 0) { spawnOilFood(); } // Spawn bad oil - more frequent at higher levels if (LK.ticks % Math.max(180, 360 - gameLevel * 15) === 0) { spawnBadOil(); } // Spawn boss enemies at level 5+ (earlier) and more frequently at level 10 if (gameLevel >= 5 && gameLevel < 10 && LK.ticks % bossSpawnRate === 0 && bossEnemies.length < 1 || gameLevel >= 10 && LK.ticks % (bossSpawnRate / 2) === 0 && bossEnemies.length < 1) { spawnBossEnemy(); } // Spawn new enemies at level 3 (earlier) if (gameLevel >= 3 && LK.ticks % Math.max(60, newEnemySpawnRate - gameLevel * 10) === 0) { spawnNewEnemy(); } // Auto fire for enemies, not asteroids if (player && LK.ticks % 15 === 0) { firePlayerBullet(); } // Update player bullets for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; // Remove bullets that go off screen if (bullet.y < -50) { bullet.destroy(); playerBullets.splice(i, 1); continue; } // Check collisions with enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { // Destroy enemy and bullet updateScore(enemy.scoreValue); LK.effects.flashObject(enemy, 0xff0000, 200); LK.getSound('explosion').play(); enemy.destroy(); enemies.splice(j, 1); bullet.destroy(); playerBullets.splice(i, 1); checkLevelProgress(); break; } } // Check collisions with boss enemies if (playerBullets[i]) { for (var j = bossEnemies.length - 1; j >= 0; j--) { var boss = bossEnemies[j]; if (bullet.intersects(boss)) { // Damage boss boss.health--; LK.effects.flashObject(boss, 0xff0000, 200); // Destroy bullet bullet.destroy(); playerBullets.splice(i, 1); // Check if boss is defeated if (boss.health <= 0) { updateScore(boss.scoreValue); LK.getSound('explosion').play(); boss.destroy(); bossEnemies.splice(j, 1); checkLevelProgress(); // If it's Earth-monster, player wins if (boss instanceof EarthMonster) { // Display victory message var victoryTxt = new Text2('YOU DEFEATED THE EARTH-MONSTER!', { size: 80, fill: 0x00FF00 }); victoryTxt.anchor.set(0.5, 0.5); LK.gui.center.addChild(victoryTxt); // Game won gameState = "won"; LK.effects.flashScreen(0x00FF00, 1000); LK.setTimeout(function () { LK.showYouWin(); }, 2000); } } break; } } } // Check bullet collisions with asteroids if (playerBullets[i]) { for (var k = asteroids.length - 1; k >= 0; k--) { if (playerBullets[i].intersects(asteroids[k])) { // Destroy only the bullet when it hits an asteroid LK.effects.flashObject(playerBullets[i], 0xff0000, 200); playerBullets[i].destroy(); playerBullets.splice(i, 1); break; } } } } // Update enemy bullets for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; // Remove bullets that go off screen if (bullet.y > 2732 + 50) { bullet.destroy(); enemyBullets.splice(i, 1); continue; } // Check collisions with player if (player && bullet.intersects(player)) { // Check if it's an Earth-monster bullet for 3x damage if (bullet instanceof EarthMonsterBullet) { // Apply damage three times for Earth-monster bullets for (var dmg = 0; dmg < 3; dmg++) { var hitSuccess = player.hit(); } LK.effects.flashObject(player, 0x00ffff, 700); // Special effect for Earth-monster hit } else { // Regular bullet damage var hitSuccess = player.hit(); } // Destroy bullet bullet.destroy(); enemyBullets.splice(i, 1); } } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; // Remove enemies that go off screen if (enemy.y > 2732 + 50) { enemy.destroy(); enemies.splice(i, 1); continue; } // Enemy shooting if (Math.random() < enemy.shootChance) { fireEnemyBullet(enemy); } // Check collisions with player if (player && enemy.intersects(player)) { // Player takes damage var hitSuccess = player.hit(); // New collision behavior - check if it's a NewEnemy if (enemy instanceof NewEnemy) { // Always lose one heart for NewEnemy currentHearts--; updateHearts(); } // Destroy enemy enemy.destroy(); enemies.splice(i, 1); LK.getSound('explosion').play(); } } // Update boss enemies for (var i = bossEnemies.length - 1; i >= 0; i--) { var boss = bossEnemies[i]; // Remove boss that go off screen if (boss.y > 2732 + 50) { boss.destroy(); bossEnemies.splice(i, 1); continue; } // Boss shooting (more frequent) if (Math.random() < boss.shootChance) { fireEnemyBullet(boss); // Boss shoots additional bullets in different directions if (Math.random() < 0.5) { var bulletLeft = new EnemyBullet(); bulletLeft.x = boss.x - 50; bulletLeft.y = boss.y + 50; enemyBullets.push(bulletLeft); game.addChild(bulletLeft); var bulletRight = new EnemyBullet(); bulletRight.x = boss.x + 50; bulletRight.y = boss.y + 50; enemyBullets.push(bulletRight); game.addChild(bulletRight); } } // Check collisions with player if (player && boss.intersects(player)) { // Player always takes damage from boss collision var hitSuccess = player.hit(); // Boss is not destroyed on collision, just damaged boss.health--; LK.effects.flashObject(boss, 0xff0000, 200); if (boss.health <= 0) { updateScore(boss.scoreValue); boss.destroy(); bossEnemies.splice(i, 1); LK.getSound('explosion').play(); } } } // Update asteroids for (var i = asteroids.length - 1; i >= 0; i--) { var asteroid = asteroids[i]; // Track if asteroid just passed the player if (asteroid.lastY < player.y - 100 && asteroid.y >= player.y - 100) { // Award points for successful dodge updateScore(10); checkLevelProgress(); } // Remove asteroids that go off screen if (asteroid.y > 2732 + 50) { asteroid.destroy(); asteroids.splice(i, 1); continue; } // Check collisions with player if (player && asteroid.intersects(player)) { // Check if it's a new deadly asteroid if (asteroid instanceof NewAsteroid) { // Game over immediately gameState = "over"; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } else { // Regular asteroid - player takes damage var hitSuccess = player.hit(); } // Destroy asteroid asteroid.destroy(); asteroids.splice(i, 1); LK.getSound('explosion').play(); } } // Update powerups for (var i = powerups.length - 1; i >= 0; i--) { var powerup = powerups[i]; // Remove powerups that go off screen if (powerup.y > 2732 + 50) { powerup.destroy(); powerups.splice(i, 1); continue; } // Check collisions with player if (player && powerup.intersects(player)) { // Apply powerup effect if (powerup.type === 0) { player.activateShield(); } else { player.activateRapidFire(); } // Destroy powerup powerup.destroy(); powerups.splice(i, 1); LK.getSound('powerupCollect').play(); updateScore(25); // Bonus points for collecting powerup } } // Update oil foods for (var i = oilFoods.length - 1; i >= 0; i--) { var oilFood = oilFoods[i]; // Remove oil foods that go off screen if (oilFood.y > 2732 + 50) { oilFood.destroy(); oilFoods.splice(i, 1); continue; } // Check collisions with player if (player && oilFood.intersects(player)) { // Check if it's a bad oil or good oil food if (oilFood instanceof BadOil) { // Decrease oil percentage by 10% oilPercentage -= 10; // Flash red to indicate bad effect LK.effects.flashObject(player, 0xff0000, 500); } else { // Increase oil percentage by 1% oilPercentage += 1; // Cap oil percentage at max value if (oilPercentage > maxOilPercentage) { oilPercentage = maxOilPercentage; } } oilTxt.setText('Oil: ' + oilPercentage + '/' + maxOilPercentage); // If player has no oil, enemies win if (oilPercentage <= 0) { // Display enemies win message var enemiesWinTxt = new Text2('ENEMIES WIN!', { size: 100, fill: 0xFF0000 }); enemiesWinTxt.anchor.set(0.5, 0.5); LK.gui.center.addChild(enemiesWinTxt); // Game over gameState = "over"; LK.effects.flashScreen(0xff0000, 1000); LK.setTimeout(function () { LK.showGameOver(); }, 2000); } // Destroy oil food oilFood.destroy(); oilFoods.splice(i, 1); } } }; // Create instructions text var instructionsTxt = new Text2('DODGE THE ASTEROIDS TO SURVIVE!', { size: 80, fill: 0xFFFFFF }); instructionsTxt.anchor.set(0.5, 0.5); LK.gui.center.addChild(instructionsTxt); instructionsTxt.y = -150; // Hide instructions after 5 seconds LK.setTimeout(function () { tween(instructionsTxt, { alpha: 0 }, { duration: 1000 }); }, 5000); // Initialize the game initializePlayer(); // Set initial oil text oilTxt.setText('Oil: ' + oilPercentage + '/' + maxOilPercentage); // Play background music LK.playMusic('bgmusic'); ;
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Asteroid = Container.expand(function () {
var self = Container.call(this);
var asteroidGraphics = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.speed = 6;
self.rotationSpeed = Math.random() * 0.05 - 0.025;
self.scoreValue = 5;
self.lastY = -100; // Track last position for collision detection
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
self.rotation += self.rotationSpeed;
// Add side-to-side movement to make dodging more challenging
self.x += Math.sin(LK.ticks * 0.02) * 2;
};
return self;
});
var BadOil = Container.expand(function () {
var self = Container.call(this);
var badOilGraphics = self.attachAsset('Bad-oil', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
self.speed = 5;
self.lastY = -100;
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
// Add some side movement
self.x += Math.sin(LK.ticks * 0.03) * 2;
};
return self;
});
var BossEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 2.5,
tint: 0xff0000
});
self.speed = 2;
self.health = 5;
self.moveDirection = 1; // 1 for right, -1 for left
self.shootChance = 0.03; // Higher chance to shoot than regular enemies
self.scoreValue = 50;
self.lastY = -100;
self.update = function () {
self.lastY = self.y;
// Move down more slowly
self.y += self.speed;
// Move in a more complex pattern
self.x += self.moveDirection * 3 * Math.sin(LK.ticks * 0.02);
// Change direction at edges
if (self.x < 200 || self.x > 2048 - 200) {
self.moveDirection *= -1;
}
};
return self;
});
var EarthMonster = Container.expand(function () {
var self = Container.call(this);
var monsterGraphics = self.attachAsset('Earth-monster', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.0,
scaleY: 3.0
});
self.speed = 1.5;
self.health = 20; // Earth-monster has 20 hearts
self.moveDirection = 1; // 1 for right, -1 for left
self.shootChance = 0.05; // Higher chance to shoot than other enemies
self.scoreValue = 200;
self.lastY = -100;
self.update = function () {
self.lastY = self.y;
// Move down more slowly
self.y += self.speed;
// Move in a complex pattern
self.x += self.moveDirection * 2 * Math.sin(LK.ticks * 0.03);
// Change direction at edges
if (self.x < 300 || self.x > 2048 - 300) {
self.moveDirection *= -1;
}
};
return self;
});
var EarthMonsterBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
tint: 0x00ffff
});
self.speed = 12; // Faster than regular enemy bullets
self.damage = 3; // Does 3x damage
self.update = function () {
self.y += self.speed;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.moveDirection = 1; // 1 for right, -1 for left
self.shootChance = 0.01; // Chance to shoot per update
self.scoreValue = 10;
self.update = function () {
// Move down
self.y += self.speed;
// Move side to side
self.x += self.moveDirection * 2;
// Change direction at edges
if (self.x < 100 || self.x > 2048 - 100) {
self.moveDirection *= -1;
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Heart = Container.expand(function () {
var self = Container.call(this);
var heartGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff0000,
scaleX: 0.8,
scaleY: 0.8
});
self.setActive = function (active) {
heartGraphics.alpha = active ? 1 : 0.3;
};
return self;
});
var NewAsteroid = Container.expand(function () {
var self = Container.call(this);
var asteroidGraphics = self.attachAsset('New-ast', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.speed = 7; // Faster than regular asteroid
self.rotationSpeed = Math.random() * 0.08 - 0.04; // Faster rotation
self.scoreValue = 0; // No points for this one since it's deadly
self.lastY = -100; // Track last position for collision detection
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
self.rotation += self.rotationSpeed;
// More erratic movement pattern
self.x += Math.sin(LK.ticks * 0.03) * 3;
};
return self;
});
var NewEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('New-enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4; // Faster than regular enemy
self.moveDirection = 1; // 1 for right, -1 for left
self.shootChance = 0.02; // Higher chance to shoot than regular enemies
self.scoreValue = 20; // Worth more points than regular enemies
self.update = function () {
// Only move left and right, no vertical movement
// Move side to side more aggressively
self.x += self.moveDirection * 3;
// Change direction at edges
if (self.x < 100 || self.x > 2048 - 100) {
self.moveDirection *= -1;
}
};
return self;
});
var OilFood = Container.expand(function () {
var self = Container.call(this);
var oilFoodGraphics = self.attachAsset('Oil-food', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
self.speed = 5;
self.lastY = -100;
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
// Add some side movement
self.x += Math.sin(LK.ticks * 0.03) * 2;
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -15;
self.update = function () {
self.y += self.speed;
};
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.shield = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.hasShield = false;
self.fireRate = 20; // Time between shots in ticks
self.fireCooldown = 0;
self.rapidFire = false;
self.rapidFireTimer = 0;
self.lives = 3; // Keep this for backward compatibility
self.activateShield = function () {
self.hasShield = true;
self.shield.alpha = 0.5;
};
self.deactivateShield = function () {
self.hasShield = false;
self.shield.alpha = 0;
};
self.activateRapidFire = function () {
self.rapidFire = true;
self.rapidFireTimer = 300; // 5 seconds at 60 FPS
};
self.canFire = function () {
if (self.fireCooldown <= 0) {
self.fireCooldown = self.rapidFire ? Math.floor(self.fireRate / 2) : self.fireRate;
return true;
}
return false;
};
self.hit = function () {
if (self.hasShield) {
self.deactivateShield();
return false; // Shield absorbed the hit
} else {
// Use the hearts system instead of lives
if (currentHearts > 0) {
currentHearts--;
updateHearts();
LK.effects.flashObject(self, 0xff0000, 500);
return true; // Ship took damage
}
return false;
}
};
self.update = function () {
if (self.fireCooldown > 0) {
self.fireCooldown--;
}
if (self.rapidFire && self.rapidFireTimer > 0) {
self.rapidFireTimer--;
if (self.rapidFireTimer <= 0) {
self.rapidFire = false;
}
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.type = Math.floor(Math.random() * 2); // 0 for shield, 1 for rapid fire
// Set color based on type
if (self.type === 0) {
powerupGraphics.tint = 0x3498db; // Blue for shield
} else {
powerupGraphics.tint = 0xf39c12; // Orange for rapid fire
}
self.update = function () {
self.y += self.speed;
// Floating animation
self.x += Math.sin(LK.ticks * 0.05) * 1;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Save the current game state
function saveGame() {
storage.set('saveSpace_level', gameLevel);
storage.set('saveSpace_score', scoreValue);
storage.set('saveSpace_hearts', currentHearts);
storage.set('saveSpace_oil', oilPercentage);
}
// Load the saved game state
function loadGame() {
var savedLevel = storage.get('saveSpace_level', 1);
var savedScore = storage.get('saveSpace_score', 0);
var savedHearts = storage.get('saveSpace_hearts', 10);
var savedOil = storage.get('saveSpace_oil', 20);
gameLevel = savedLevel;
scoreValue = savedScore;
currentHearts = savedHearts;
oilPercentage = savedOil;
// Update UI elements
levelTxt.setText('Level: ' + gameLevel);
scoreTxt.setText('Score: ' + scoreValue);
oilTxt.setText('Oil: ' + oilPercentage + '/' + maxOilPercentage);
updateHearts();
// Set game difficulty based on loaded level
difficultyMultiplier = 1.0 + gameLevel * 0.15;
enemySpawnRate = Math.max(60, Math.floor(240 / difficultyMultiplier));
asteroidSpawnRate = Math.max(45, Math.floor(90 / difficultyMultiplier));
oilFoodSpawnRate = Math.min(600, Math.floor(360 * (1 + gameLevel * 0.1)));
}
// Auto-save every minute
LK.setInterval(saveGame, 60000);
// Save when player takes damage
var originalHit = PlayerShip.prototype.hit;
PlayerShip.prototype.hit = function () {
var result = originalHit.apply(this, arguments);
if (result) {
saveGame();
}
return result;
};
// Save on level up
var originalCheckLevelProgress = checkLevelProgress;
checkLevelProgress = function checkLevelProgress() {
var oldLevel = gameLevel;
originalCheckLevelProgress.apply(this, arguments);
if (gameLevel > oldLevel) {
saveGame();
}
};
// Try to load saved game at start
loadGame();
game.setBackgroundColor(0x0c1445);
// Game variables
var player;
var playerBullets = [];
var enemies = [];
var bossEnemies = []; // Track boss enemies separately
var enemyBullets = [];
var asteroids = [];
var powerups = [];
var hearts = [];
var oilFoods = []; // Array to track oil foods
var heartsContainer;
var maxHearts = 10;
var currentHearts = 10;
var gameLevel = 1;
var enemySpawnRate = 240; // Reduced enemy spawn rate to focus on dodging asteroids
var asteroidSpawnRate = 90; // Increased asteroid spawn rate to create dodging challenge
var powerupSpawnRate = 900; // Every 15 seconds - rarer powerups
var bossSpawnRate = 600; // How often to check for boss spawn when at level 10
var newEnemySpawnRate = 180; // More frequent than regular enemies
var oilFoodSpawnRate = 360; // Every 6 seconds - slightly rarer
var gameState = "playing";
var scoreValue = 0;
var oilPercentage = 20; // Track oil percentage, starting at 20 out of 40
var maxOilPercentage = 40; // Maximum oil percentage
var powerupChance = 0.7; // 70% chance to actually spawn a powerup when the timer triggers
var difficultyMultiplier = 1.0; // Base difficulty multiplier that increases with level
// Setup score display
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -300; // Offset from right edge
// Hearts display - text version as fallback
var livesTxt = new Text2('Hearts: 10/10', {
size: 60,
fill: 0xFFFFFF
});
livesTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(livesTxt);
livesTxt.x = -300;
livesTxt.y = 70; // Below score text
// Function to update hearts display
function updateHearts() {
for (var i = 0; i < hearts.length; i++) {
hearts[i].setActive(i < currentHearts);
}
livesTxt.setText('Hearts: ' + currentHearts + '/' + maxHearts);
// Game over condition
if (currentHearts <= 0) {
gameState = "over";
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
// Level display
var levelTxt = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(levelTxt);
levelTxt.x = -300;
levelTxt.y = 140; // Below lives text
// Oil percentage display
var oilTxt = new Text2('Oil: 20/40', {
size: 60,
fill: 0xFFFFFF
});
oilTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(oilTxt);
oilTxt.x = -300;
oilTxt.y = 210; // Below level text
// Initialize player
function initializePlayer() {
player = new PlayerShip();
player.x = 2048 / 2;
player.y = 2732 - 200;
game.addChild(player);
// Initialize hearts display
initializeHearts();
}
// Initialize hearts display
function initializeHearts() {
// Remove existing hearts if any
if (heartsContainer) {
heartsContainer.destroy();
hearts = [];
}
// Create container for hearts
heartsContainer = new Container();
game.addChild(heartsContainer);
heartsContainer.x = 100;
heartsContainer.y = 100;
// Create hearts
currentHearts = maxHearts;
for (var i = 0; i < maxHearts; i++) {
var heart = new Heart();
heart.x = i % 5 * 40;
heart.y = Math.floor(i / 5) * 40;
heart.setActive(true);
hearts.push(heart);
heartsContainer.addChild(heart);
}
}
// Spawn enemy
function spawnEnemy() {
var enemy = new Enemy();
enemy.x = Math.random() * (2048 - 200) + 100;
enemy.y = -100;
enemy.speed = 2 + gameLevel * 0.5 * difficultyMultiplier; // Scale with difficulty multiplier
enemy.shootChance = Math.min(0.05, 0.01 + gameLevel * 0.004); // Increase shoot chance with level
enemy.health = 1 + Math.floor(gameLevel / 5); // Tougher enemies at higher levels
enemies.push(enemy);
game.addChild(enemy);
}
// Spawn asteroid
function spawnAsteroid() {
// At level 2 and above, randomly spawn the deadly asteroid
// Chance increases with level
if (gameLevel >= 2 && Math.random() < 0.2 + gameLevel * 0.03) {
var deadlyAsteroid = new NewAsteroid();
deadlyAsteroid.x = Math.random() * (2048 - 200) + 100;
deadlyAsteroid.y = -100;
deadlyAsteroid.speed = 7 + gameLevel * 0.4; // Faster with level
asteroids.push(deadlyAsteroid);
game.addChild(deadlyAsteroid);
} else {
var asteroid = new Asteroid();
asteroid.x = Math.random() * (2048 - 200) + 100;
asteroid.y = -100;
asteroid.speed = 3 + gameLevel * 0.3 * difficultyMultiplier; // Scale with difficulty multiplier
asteroids.push(asteroid);
game.addChild(asteroid);
}
}
// Spawn power-up
function spawnPowerUp() {
// Only spawn powerup based on chance - gets rarer with higher levels
if (Math.random() < powerupChance - gameLevel * 0.05) {
var powerup = new PowerUp();
powerup.x = Math.random() * (2048 - 200) + 100;
powerup.y = -100;
powerups.push(powerup);
game.addChild(powerup);
}
}
// Spawn oil food
function spawnOilFood() {
var oilFood = new OilFood();
oilFood.x = Math.random() * (2048 - 200) + 100;
oilFood.y = -100;
oilFoods.push(oilFood);
game.addChild(oilFood);
}
// Spawn bad oil
function spawnBadOil() {
var badOil = new BadOil();
badOil.x = Math.random() * (2048 - 200) + 100;
badOil.y = -100;
oilFoods.push(badOil);
game.addChild(badOil);
}
// Spawn new enemy
function spawnNewEnemy() {
var newEnemy = new NewEnemy();
newEnemy.x = Math.random() * (2048 - 200) + 100;
newEnemy.y = -100;
newEnemy.speed = 3 + gameLevel * 0.5; // Increase speed with level
enemies.push(newEnemy);
game.addChild(newEnemy);
}
// Spawn boss enemy
function spawnBossEnemy() {
// At level 10, spawn Earth-monster instead of regular boss
var boss;
if (gameLevel >= 10) {
boss = new EarthMonster();
// Create a special alert for Earth-monster
var bossAlert = new Text2('EARTH-MONSTER INCOMING!', {
size: 100,
fill: 0x00FFFF
});
} else {
boss = new BossEnemy();
// Create a regular boss alert
var bossAlert = new Text2('BOSS INCOMING!', {
size: 100,
fill: 0xFF0000
});
}
boss.x = 2048 / 2;
boss.y = -200;
bossEnemies.push(boss);
game.addChild(boss);
bossAlert.anchor.set(0.5, 0.5);
LK.gui.center.addChild(bossAlert);
// Fade out the alert after 2 seconds
LK.setTimeout(function () {
tween(bossAlert, {
alpha: 0
}, {
duration: 1000,
onComplete: function onComplete() {
bossAlert.destroy();
}
});
}, 2000);
}
// Fire player bullet
function firePlayerBullet() {
if (player && player.canFire()) {
var bullet = new PlayerBullet();
bullet.x = player.x;
bullet.y = player.y - 50;
playerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('laser').play();
}
}
// Fire enemy bullet
function fireEnemyBullet(enemy) {
// Check if enemy is Earth-monster to create special bullets
if (enemy instanceof EarthMonster) {
// Earth-monster fires 5 bullets at once in a spread pattern
for (var i = 0; i < 5; i++) {
var bullet = new EarthMonsterBullet();
// Position bullets in a spread pattern
bullet.x = enemy.x + (i - 2) * 50; // -100, -50, 0, 50, 100 offset
bullet.y = enemy.y + 50;
enemyBullets.push(bullet);
game.addChild(bullet);
}
} else {
var bullet = new EnemyBullet();
bullet.x = enemy.x;
bullet.y = enemy.y + 50;
enemyBullets.push(bullet);
game.addChild(bullet);
}
}
// Update score
function updateScore(points) {
scoreValue += points;
LK.setScore(scoreValue);
scoreTxt.setText('Score: ' + scoreValue);
}
// Check level progression
function checkLevelProgress() {
if (scoreValue >= gameLevel * 100) {
gameLevel++;
levelTxt.setText('Level: ' + gameLevel);
// Increase difficulty multiplier
difficultyMultiplier = 1.0 + gameLevel * 0.15;
// Make game more difficult
enemySpawnRate = Math.max(60, Math.floor(240 / difficultyMultiplier));
asteroidSpawnRate = Math.max(45, Math.floor(90 / difficultyMultiplier));
// Decrease oil food spawn rate
oilFoodSpawnRate = Math.min(600, Math.floor(360 * (1 + gameLevel * 0.1)));
// Make enemies faster and stronger via game update loop
// Show level up message
var levelUpTxt = new Text2('LEVEL ' + gameLevel + '!', {
size: 100,
fill: 0xFFFF00
});
levelUpTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(levelUpTxt);
// Fade out the message after 1.5 seconds
LK.setTimeout(function () {
tween(levelUpTxt, {
alpha: 0
}, {
duration: 800,
onComplete: function onComplete() {
levelUpTxt.destroy();
}
});
}, 1500);
}
}
// Drag handling
var isDragging = false;
function handleMove(x, y, obj) {
if (isDragging && player) {
// Constrain player to screen bounds
player.x = Math.max(50, Math.min(2048 - 50, x));
player.y = Math.max(50, Math.min(2732 - 50, y));
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
isDragging = true;
handleMove(x, y, obj);
// Auto-fire when touching
firePlayerBullet();
};
game.up = function (x, y, obj) {
isDragging = false;
};
// Main game loop
game.update = function () {
if (gameState !== "playing") {
return;
}
// Spawn enemies - spawn multiple based on level
if (LK.ticks % enemySpawnRate === 0) {
// At higher levels, spawn multiple enemies at once
var enemiesToSpawn = 1 + Math.floor(gameLevel / 3);
for (var i = 0; i < enemiesToSpawn && i < 4; i++) {
// Cap at 4 enemies per spawn
spawnEnemy();
}
}
// Spawn asteroids - more frequent at higher levels
if (LK.ticks % asteroidSpawnRate === 0) {
// At higher levels, spawn multiple asteroids
var asteroidsToSpawn = 1 + Math.floor(gameLevel / 4);
for (var i = 0; i < asteroidsToSpawn && i < 3; i++) {
// Cap at 3 asteroids per spawn
spawnAsteroid();
}
}
// Spawn powerups - rare chance based on level
if (LK.ticks % powerupSpawnRate === 0) {
spawnPowerUp();
}
// Spawn oil food - less frequent at higher levels
if (LK.ticks % oilFoodSpawnRate === 0) {
spawnOilFood();
}
// Spawn bad oil - more frequent at higher levels
if (LK.ticks % Math.max(180, 360 - gameLevel * 15) === 0) {
spawnBadOil();
}
// Spawn boss enemies at level 5+ (earlier) and more frequently at level 10
if (gameLevel >= 5 && gameLevel < 10 && LK.ticks % bossSpawnRate === 0 && bossEnemies.length < 1 || gameLevel >= 10 && LK.ticks % (bossSpawnRate / 2) === 0 && bossEnemies.length < 1) {
spawnBossEnemy();
}
// Spawn new enemies at level 3 (earlier)
if (gameLevel >= 3 && LK.ticks % Math.max(60, newEnemySpawnRate - gameLevel * 10) === 0) {
spawnNewEnemy();
}
// Auto fire for enemies, not asteroids
if (player && LK.ticks % 15 === 0) {
firePlayerBullet();
}
// Update player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
// Remove bullets that go off screen
if (bullet.y < -50) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check collisions with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
// Destroy enemy and bullet
updateScore(enemy.scoreValue);
LK.effects.flashObject(enemy, 0xff0000, 200);
LK.getSound('explosion').play();
enemy.destroy();
enemies.splice(j, 1);
bullet.destroy();
playerBullets.splice(i, 1);
checkLevelProgress();
break;
}
}
// Check collisions with boss enemies
if (playerBullets[i]) {
for (var j = bossEnemies.length - 1; j >= 0; j--) {
var boss = bossEnemies[j];
if (bullet.intersects(boss)) {
// Damage boss
boss.health--;
LK.effects.flashObject(boss, 0xff0000, 200);
// Destroy bullet
bullet.destroy();
playerBullets.splice(i, 1);
// Check if boss is defeated
if (boss.health <= 0) {
updateScore(boss.scoreValue);
LK.getSound('explosion').play();
boss.destroy();
bossEnemies.splice(j, 1);
checkLevelProgress();
// If it's Earth-monster, player wins
if (boss instanceof EarthMonster) {
// Display victory message
var victoryTxt = new Text2('YOU DEFEATED THE EARTH-MONSTER!', {
size: 80,
fill: 0x00FF00
});
victoryTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(victoryTxt);
// Game won
gameState = "won";
LK.effects.flashScreen(0x00FF00, 1000);
LK.setTimeout(function () {
LK.showYouWin();
}, 2000);
}
}
break;
}
}
}
// Check bullet collisions with asteroids
if (playerBullets[i]) {
for (var k = asteroids.length - 1; k >= 0; k--) {
if (playerBullets[i].intersects(asteroids[k])) {
// Destroy only the bullet when it hits an asteroid
LK.effects.flashObject(playerBullets[i], 0xff0000, 200);
playerBullets[i].destroy();
playerBullets.splice(i, 1);
break;
}
}
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
// Remove bullets that go off screen
if (bullet.y > 2732 + 50) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collisions with player
if (player && bullet.intersects(player)) {
// Check if it's an Earth-monster bullet for 3x damage
if (bullet instanceof EarthMonsterBullet) {
// Apply damage three times for Earth-monster bullets
for (var dmg = 0; dmg < 3; dmg++) {
var hitSuccess = player.hit();
}
LK.effects.flashObject(player, 0x00ffff, 700); // Special effect for Earth-monster hit
} else {
// Regular bullet damage
var hitSuccess = player.hit();
}
// Destroy bullet
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
// Remove enemies that go off screen
if (enemy.y > 2732 + 50) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Enemy shooting
if (Math.random() < enemy.shootChance) {
fireEnemyBullet(enemy);
}
// Check collisions with player
if (player && enemy.intersects(player)) {
// Player takes damage
var hitSuccess = player.hit();
// New collision behavior - check if it's a NewEnemy
if (enemy instanceof NewEnemy) {
// Always lose one heart for NewEnemy
currentHearts--;
updateHearts();
}
// Destroy enemy
enemy.destroy();
enemies.splice(i, 1);
LK.getSound('explosion').play();
}
}
// Update boss enemies
for (var i = bossEnemies.length - 1; i >= 0; i--) {
var boss = bossEnemies[i];
// Remove boss that go off screen
if (boss.y > 2732 + 50) {
boss.destroy();
bossEnemies.splice(i, 1);
continue;
}
// Boss shooting (more frequent)
if (Math.random() < boss.shootChance) {
fireEnemyBullet(boss);
// Boss shoots additional bullets in different directions
if (Math.random() < 0.5) {
var bulletLeft = new EnemyBullet();
bulletLeft.x = boss.x - 50;
bulletLeft.y = boss.y + 50;
enemyBullets.push(bulletLeft);
game.addChild(bulletLeft);
var bulletRight = new EnemyBullet();
bulletRight.x = boss.x + 50;
bulletRight.y = boss.y + 50;
enemyBullets.push(bulletRight);
game.addChild(bulletRight);
}
}
// Check collisions with player
if (player && boss.intersects(player)) {
// Player always takes damage from boss collision
var hitSuccess = player.hit();
// Boss is not destroyed on collision, just damaged
boss.health--;
LK.effects.flashObject(boss, 0xff0000, 200);
if (boss.health <= 0) {
updateScore(boss.scoreValue);
boss.destroy();
bossEnemies.splice(i, 1);
LK.getSound('explosion').play();
}
}
}
// Update asteroids
for (var i = asteroids.length - 1; i >= 0; i--) {
var asteroid = asteroids[i];
// Track if asteroid just passed the player
if (asteroid.lastY < player.y - 100 && asteroid.y >= player.y - 100) {
// Award points for successful dodge
updateScore(10);
checkLevelProgress();
}
// Remove asteroids that go off screen
if (asteroid.y > 2732 + 50) {
asteroid.destroy();
asteroids.splice(i, 1);
continue;
}
// Check collisions with player
if (player && asteroid.intersects(player)) {
// Check if it's a new deadly asteroid
if (asteroid instanceof NewAsteroid) {
// Game over immediately
gameState = "over";
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
} else {
// Regular asteroid - player takes damage
var hitSuccess = player.hit();
}
// Destroy asteroid
asteroid.destroy();
asteroids.splice(i, 1);
LK.getSound('explosion').play();
}
}
// Update powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
// Remove powerups that go off screen
if (powerup.y > 2732 + 50) {
powerup.destroy();
powerups.splice(i, 1);
continue;
}
// Check collisions with player
if (player && powerup.intersects(player)) {
// Apply powerup effect
if (powerup.type === 0) {
player.activateShield();
} else {
player.activateRapidFire();
}
// Destroy powerup
powerup.destroy();
powerups.splice(i, 1);
LK.getSound('powerupCollect').play();
updateScore(25); // Bonus points for collecting powerup
}
}
// Update oil foods
for (var i = oilFoods.length - 1; i >= 0; i--) {
var oilFood = oilFoods[i];
// Remove oil foods that go off screen
if (oilFood.y > 2732 + 50) {
oilFood.destroy();
oilFoods.splice(i, 1);
continue;
}
// Check collisions with player
if (player && oilFood.intersects(player)) {
// Check if it's a bad oil or good oil food
if (oilFood instanceof BadOil) {
// Decrease oil percentage by 10%
oilPercentage -= 10;
// Flash red to indicate bad effect
LK.effects.flashObject(player, 0xff0000, 500);
} else {
// Increase oil percentage by 1%
oilPercentage += 1;
// Cap oil percentage at max value
if (oilPercentage > maxOilPercentage) {
oilPercentage = maxOilPercentage;
}
}
oilTxt.setText('Oil: ' + oilPercentage + '/' + maxOilPercentage);
// If player has no oil, enemies win
if (oilPercentage <= 0) {
// Display enemies win message
var enemiesWinTxt = new Text2('ENEMIES WIN!', {
size: 100,
fill: 0xFF0000
});
enemiesWinTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(enemiesWinTxt);
// Game over
gameState = "over";
LK.effects.flashScreen(0xff0000, 1000);
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
}
// Destroy oil food
oilFood.destroy();
oilFoods.splice(i, 1);
}
}
};
// Create instructions text
var instructionsTxt = new Text2('DODGE THE ASTEROIDS TO SURVIVE!', {
size: 80,
fill: 0xFFFFFF
});
instructionsTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionsTxt);
instructionsTxt.y = -150;
// Hide instructions after 5 seconds
LK.setTimeout(function () {
tween(instructionsTxt, {
alpha: 0
}, {
duration: 1000
});
}, 5000);
// Initialize the game
initializePlayer();
// Set initial oil text
oilTxt.setText('Oil: ' + oilPercentage + '/' + maxOilPercentage);
// Play background music
LK.playMusic('bgmusic');
;
Rocky rock. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A space ship with guns. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A spaceship with weapons and four wings. Single Game Texture. In-Game asset. Blank background. High contrast. No shadows
A spaceship with engines at the back and lots of mini spaceships next to the big one. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Rocky green rock with green venom dripping off it. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Black oil dripping out a container. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Red oil floating in space with skulls flowing too. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Super scary earth with sharp teeth. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Energy ball. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows