User prompt
Save the code please
User prompt
Make that each level gets harder and harder and make the powerups rare to drop
User prompt
Earth-monster has 20 hearts
User prompt
If you defeated the earth-monster you win
User prompt
At the end of the game that’s level 10 the earth-monster comes out it’s bullets shoots 5 times more bullets and 3 times stronger
User prompt
Bad-oil is the same as oil-food but takes 10 percent of oil away
User prompt
If you touch oil-food you gain 1 percent of oil
User prompt
If you don’t have any oil the game stops and you start with 20/40
User prompt
If you touch oil-food you get 1 percent of oil if you do not have any oil then it says enemy’s win then the game stops
User prompt
Make there be Ten Hearts and Also, if you hit a new enemy and an enemy you lose one heart, but you kill the
User prompt
Make the new-ast like the asteroid but if you touch it you lose comes at level 2
User prompt
Make it the new-enemy goes left and right only
User prompt
Now make new-enemy the same as enemy but it only a comes out at level 4
User prompt
Make a second enemy that only appears at level 10
User prompt
Please fix the bug: 'Timeout.tick error: tween.to is not a function. (In 'tween.to(instructionsTxt, { alpha: 0 }, 1000)', 'tween.to' is undefined)' in or related to this line: 'tween.to(instructionsTxt, {' Line Number: 494 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The bullet hits the asteroid, then the bullet breaks and disappears.
User prompt
You can't Shoot and destroy the asteroid, but you can only dodge it
Code edit (1 edits merged)
Please save this source code
User prompt
Galactic Defender: Space Shooter
Initial prompt
A space shooter game
/**** * 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