Code edit (1 edits merged)
Please save this source code
User prompt
add sound for each event.
User prompt
write a small orange “Glaud” in a logical place on the screen.
User prompt
Make the text visible on the screen. The design should be good.
User prompt
Identify and solve some basic logic errors in the game.
User prompt
Identify and solve some basic logic errors in the game.
User prompt
Identify the features that will make it better and implement them in an optimized way, don't make any mistakes, it's clean and playable. Make it a user-friendly game. ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
User prompt
Identify the features that will make it better and implement them in an optimized way, don't make any mistakes, it's clean and playable. Make it a user-friendly game.
User prompt
Identify the features that will make it better and implement them in an optimized way, don't make any mistakes, it's clean and playable. Make it a user-friendly game. ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
User prompt
Identify the features that will make it better and implement them in an optimized way, don't make any mistakes, it's clean and playable. Make it a user-friendly game. ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Space Defender
Initial prompt
game
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0, level: 1 }); /**** * Classes ****/ var Asteroid = Container.expand(function () { var self = Container.call(this); // Random size asteroid var size = Math.random() * 0.7 + 0.7; // 0.7 to 1.4 var asteroidGraphics = self.attachAsset('asteroid', { anchorX: 0.5, anchorY: 0.5, scaleX: size, scaleY: size }); self.health = 30 * size; self.speed = 3 / size; // Bigger asteroids move slower self.rotationSpeed = (Math.random() - 0.5) * 0.05; self.points = Math.floor(50 * size); self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0x888888, 200); if (self.health <= 0) { self.onDestroyed(); } }; self.onDestroyed = function () { // Add points to score LK.setScore(LK.getScore() + self.points); // Create explosion var explosion = new Explosion(self.x, self.y, size); game.addChild(explosion); LK.getSound('explosion').play(); // Remove from game var index = asteroids.indexOf(self); if (index > -1) { asteroids.splice(index, 1); self.destroy(); } }; self.update = function () { self.y += self.speed; asteroidGraphics.rotation += self.rotationSpeed; // Check if asteroid is off-screen if (self.y > 2732 + 100) { var index = asteroids.indexOf(self); if (index > -1) { asteroids.splice(index, 1); self.destroy(); } } }; return self; }); var Boss = Container.expand(function () { var self = Container.call(this); var bossGraphics = self.attachAsset('boss', { anchorX: 0.5, anchorY: 0.5 }); self.health = 500; self.maxHealth = 500; self.speed = 2; self.points = 2000; self.active = false; self.phase = 1; self.directionX = 1; self.shootCooldown = 30; self.specialAttackCooldown = 300; // Health bar self.healthBar = self.attachAsset('healthBar', { anchorX: 0.5, anchorY: 0.5, y: -150 }); self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xff0000, 200); // Update health bar scale self.healthBar.scaleX = Math.max(0, self.health / self.maxHealth); // Phase transition at 50% health if (self.health <= self.maxHealth / 2 && self.phase === 1) { self.phase = 2; self.speed = 4; LK.effects.flashObject(self, 0xff00ff, 1000); // Purple flash for phase transition } if (self.health <= 0) { self.onDestroyed(); } }; self.onDestroyed = function () { // Add points to score LK.setScore(LK.getScore() + self.points); // Create multiple explosions for (var i = 0; i < 8; i++) { var explosionX = self.x + (Math.random() * 300 - 150); var explosionY = self.y + (Math.random() * 200 - 100); var explosion = new Explosion(explosionX, explosionY, 2); game.addChild(explosion); // Stagger the explosions (function (delay) { LK.setTimeout(function () { LK.getSound('explosion').play(); }, delay * 200); })(i); } // Complete level level++; if (level > storage.level) { storage.level = level; } // Check high score if (LK.getScore() > storage.highScore) { storage.highScore = LK.getScore(); } // Show win screen LK.showYouWin(); // Remove from game var index = bosses.indexOf(self); if (index > -1) { bosses.splice(index, 1); self.destroy(); } }; self.shoot = function () { // Basic attack - 3 bullets for (var i = -1; i <= 1; i++) { var bullet = new EnemyBullet(); bullet.x = self.x + i * 80; bullet.y = self.y + 100; game.addChild(bullet); enemyBullets.push(bullet); } LK.getSound('enemyShoot').play(); }; self.specialAttack = function () { // Special attack based on phase if (self.phase === 1) { // Phase 1: Circle of 8 bullets for (var i = 0; i < 8; i++) { var angle = i / 8 * Math.PI * 2; var bullet = new EnemyBullet(); bullet.x = self.x + Math.cos(angle) * 100; bullet.y = self.y + Math.sin(angle) * 100; bullet.directionX = Math.cos(angle); bullet.directionY = Math.sin(angle); game.addChild(bullet); enemyBullets.push(bullet); } } else { // Phase 2: Targeted volley at player for (var i = 0; i < 5; i++) { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y + 100; // Target the player var dx = player.x - bullet.x; var dy = player.y - bullet.y; var dist = Math.sqrt(dx * dx + dy * dy); bullet.directionX = dx / dist; bullet.directionY = dy / dist; bullet.speed = 8 + i; game.addChild(bullet); enemyBullets.push(bullet); // Stagger the bullets slightly (function (b, delay) { LK.setTimeout(function () { game.addChild(b); enemyBullets.push(b); }, delay * 100); })(bullet, i); } } LK.getSound('enemyShoot').play(); }; self.update = function () { if (!self.active) { return; } // Movement self.x += self.speed * self.directionX; // Bounce at screen edges if (self.x < 300) { self.x = 300; self.directionX = 1; } else if (self.x > 2048 - 300) { self.x = 2048 - 300; self.directionX = -1; } // Regular attacks self.shootCooldown--; if (self.shootCooldown <= 0) { self.shoot(); self.shootCooldown = self.phase === 1 ? 60 : 40; } // Special attacks self.specialAttackCooldown--; if (self.specialAttackCooldown <= 0) { self.specialAttack(); self.specialAttackCooldown = 300; } }; self.activate = function () { self.active = true; }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.health = 20; self.speed = 2; self.shootCooldown = Math.floor(Math.random() * 120) + 60; self.points = 100; self.movementPattern = "straight"; // Default movement pattern self.directionX = 0; self.directionChangeTimer = 0; self.takeDamage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xff0000, 200); if (self.health <= 0) { self.onDestroyed(); } }; self.onDestroyed = function () { // Add points to score LK.setScore(LK.getScore() + self.points); // Create explosion var explosion = new Explosion(self.x, self.y, 1); game.addChild(explosion); LK.getSound('explosion').play(); // Check if should drop powerup (20% chance) if (Math.random() < 0.2) { var powerup = new Powerup(); powerup.x = self.x; powerup.y = self.y; game.addChild(powerup); powerups.push(powerup); } // Remove from game var index = enemies.indexOf(self); if (index > -1) { enemies.splice(index, 1); self.destroy(); } }; self.shoot = function () { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y + 50; game.addChild(bullet); enemyBullets.push(bullet); LK.getSound('enemyShoot').play(); }; self.setMovementPattern = function (pattern) { self.movementPattern = pattern; if (pattern === "zigzag") { self.directionX = Math.random() < 0.5 ? -1 : 1; self.speed = 3; } else if (pattern === "circle") { self.angle = Math.random() * Math.PI * 2; self.centerX = self.x; self.centerY = self.y; self.radius = 100; self.speed = 0.02; } else if (pattern === "sine") { self.startX = self.x; self.amplitude = 150; self.frequency = 0.01; self.angle = Math.random() * Math.PI * 2; } }; self.update = function () { // Movement based on pattern if (self.movementPattern === "straight") { self.y += self.speed; } else if (self.movementPattern === "zigzag") { self.y += self.speed; self.x += self.speed * 2 * self.directionX; self.directionChangeTimer++; if (self.directionChangeTimer > 60) { self.directionX *= -1; self.directionChangeTimer = 0; } // Bounce off screen edges if (self.x < 50) { self.x = 50; self.directionX = 1; } else if (self.x > 2048 - 50) { self.x = 2048 - 50; self.directionX = -1; } } else if (self.movementPattern === "circle") { self.angle += self.speed; self.x = self.centerX + Math.cos(self.angle) * self.radius; self.y = self.centerY + Math.sin(self.angle) * self.radius + self.speed * 20; } else if (self.movementPattern === "sine") { self.y += self.speed * 2; self.angle += self.frequency; self.x = self.startX + Math.sin(self.angle) * self.amplitude; } // Shooting self.shootCooldown--; if (self.shootCooldown <= 0) { self.shoot(); self.shootCooldown = Math.floor(Math.random() * 120) + 120; } // Remove if off screen if (self.y > 2732 + 100) { var index = enemies.indexOf(self); if (index > -1) { enemies.splice(index, 1); self.destroy(); } } }; 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.damage = 10; self.directionX = 0; self.directionY = 1; self.update = function () { // Move based on direction self.x += self.directionX * self.speed; self.y += self.directionY * self.speed; // Check if bullet is off-screen if (self.y > 2732 + 50 || self.y < -50 || self.x < -50 || self.x > 2048 + 50) { self.removeFromGame(); } }; self.removeFromGame = function () { var index = enemyBullets.indexOf(self); if (index > -1) { enemyBullets.splice(index, 1); self.destroy(); } }; return self; }); var Explosion = Container.expand(function (x, y, size) { var self = Container.call(this); self.x = x; self.y = y; var explosionGraphics = self.attachAsset('explosion', { anchorX: 0.5, anchorY: 0.5, scaleX: size || 1, scaleY: size || 1, alpha: 0.9 }); // Animation for explosion self.duration = 30; // 0.5 seconds at 60fps self.timer = 0; self.update = function () { self.timer++; // Scale up and fade out var progress = self.timer / self.duration; explosionGraphics.scaleX = (size || 1) * (1 + progress); explosionGraphics.scaleY = (size || 1) * (1 + progress); explosionGraphics.alpha = 1 - progress; if (self.timer >= self.duration) { self.destroy(); } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.health = 100; self.speed = 15; self.shootCooldown = 0; self.invulnerable = false; self.powerupTimer = 0; self.powerupActive = false; self.takeDamage = function (amount) { if (self.invulnerable) { return; } self.health -= amount; if (self.health <= 0) { self.health = 0; self.onDestroyed(); } else { // Flash player when hit self.invulnerable = true; LK.effects.flashObject(self, 0xffffff, 500); LK.setTimeout(function () { self.invulnerable = false; }, 1000); } }; self.applyPowerup = function () { self.powerupActive = true; self.powerupTimer = 300; // 5 seconds at 60fps playerGraphics.tint = 0x00ff00; // Green tint for powered up LK.getSound('powerup').play(); }; self.shoot = function () { if (self.shootCooldown <= 0) { var bullet = new PlayerBullet(); bullet.x = self.x; bullet.y = self.y - 70; game.addChild(bullet); bullets.push(bullet); LK.getSound('playerShoot').play(); // If powered up, shoot 3 bullets instead of 1 if (self.powerupActive) { var bulletLeft = new PlayerBullet(); bulletLeft.x = self.x - 40; bulletLeft.y = self.y - 50; var bulletRight = new PlayerBullet(); bulletRight.x = self.x + 40; bulletRight.y = self.y - 50; game.addChild(bulletLeft); game.addChild(bulletRight); bullets.push(bulletLeft); bullets.push(bulletRight); } self.shootCooldown = self.powerupActive ? 10 : 15; } }; self.onDestroyed = function () { var explosion = new Explosion(self.x, self.y, 2); game.addChild(explosion); LK.getSound('explosion').play(); // Show game over LK.showGameOver(); }; self.update = function () { if (self.shootCooldown > 0) { self.shootCooldown--; } if (self.powerupActive) { self.powerupTimer--; if (self.powerupTimer <= 0) { self.powerupActive = false; playerGraphics.tint = 0xffffff; // Reset tint } } }; 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; // Move upwards self.damage = 10; self.update = function () { self.y += self.speed; // Check if bullet is off-screen if (self.y < -50) { self.removeFromGame(); } }; self.removeFromGame = function () { var index = bullets.indexOf(self); if (index > -1) { bullets.splice(index, 1); self.destroy(); } }; 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.pulsateTimer = 0; self.update = function () { self.y += self.speed; // Pulsate effect self.pulsateTimer += 0.05; var scale = 1 + Math.sin(self.pulsateTimer) * 0.2; powerupGraphics.scaleX = scale; powerupGraphics.scaleY = scale; // Remove if off screen if (self.y > 2732 + 50) { self.removeFromGame(); } }; self.removeFromGame = function () { var index = powerups.indexOf(self); if (index > -1) { powerups.splice(index, 1); self.destroy(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000011 // Deep space blue }); /**** * Game Code ****/ // Game state variables var player; var bullets = []; var enemies = []; var enemyBullets = []; var asteroids = []; var powerups = []; var bosses = []; var level = storage.level || 1; var enemySpawnTimer = 0; var asteroidSpawnTimer = 0; var bossSpawned = false; var gameStarted = false; var levelEnemiesRequired; var enemiesDefeated = 0; var dragNode = null; // Set up UI var scoreTxt = new Text2('Score: 0', { size: 70, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(scoreTxt); var levelTxt = new Text2('Level: ' + level, { size: 70, fill: 0xFFFFFF }); levelTxt.anchor.set(1, 0); LK.gui.topLeft.addChild(levelTxt); levelTxt.x = 250; // Make sure it's not in the top-left corner var healthBar = LK.getAsset('healthBar', { anchorX: 0, anchorY: 0.5, scaleX: 1, scaleY: 0.6 }); healthBar.x = 200; LK.gui.bottom.addChild(healthBar); var healthTxt = new Text2('Health', { size: 60, fill: 0xFFFFFF }); healthTxt.anchor.set(0.5, 0.5); healthTxt.x = 100; LK.gui.bottom.addChild(healthTxt); // Initialize player function initPlayer() { player = new Player(); player.x = 2048 / 2; player.y = 2732 - 200; game.addChild(player); } // Initialize level function initLevel() { // Clear any existing enemies and bullets for (var i = enemies.length - 1; i >= 0; i--) { enemies[i].destroy(); } for (var i = enemyBullets.length - 1; i >= 0; i--) { enemyBullets[i].destroy(); } for (var i = asteroids.length - 1; i >= 0; i--) { asteroids[i].destroy(); } for (var i = powerups.length - 1; i >= 0; i--) { powerups[i].destroy(); } for (var i = bosses.length - 1; i >= 0; i--) { bosses[i].destroy(); } enemies = []; enemyBullets = []; asteroids = []; powerups = []; bosses = []; bossSpawned = false; enemiesDefeated = 0; // Set level difficulty levelEnemiesRequired = level * 15; enemySpawnTimer = 60; asteroidSpawnTimer = 180; // Update UI levelTxt.setText('Level: ' + level); // Start music LK.playMusic('bgMusic'); } // Spawn enemy with random pattern function spawnEnemy() { var enemy = new Enemy(); // Random x position enemy.x = Math.random() * (2048 - 200) + 100; enemy.y = -100; // Set health and pattern based on level enemy.health = 20 + level * 5; // Choose movement pattern var patterns = ["straight", "zigzag", "sine"]; if (level >= 3) { patterns.push("circle"); } var pattern = patterns[Math.floor(Math.random() * patterns.length)]; enemy.setMovementPattern(pattern); game.addChild(enemy); enemies.push(enemy); } // Spawn asteroid function spawnAsteroid() { var asteroid = new Asteroid(); // Random x position asteroid.x = Math.random() * (2048 - 200) + 100; asteroid.y = -100; game.addChild(asteroid); asteroids.push(asteroid); } // Spawn boss function spawnBoss() { var boss = new Boss(); boss.x = 2048 / 2; boss.y = 300; // Adjust boss health based on level boss.health = 500 + level * 100; boss.maxHealth = boss.health; game.addChild(boss); bosses.push(boss); // Activate boss after entrance animation tween(boss, { y: 300 }, { duration: 2000, easing: tween.easeOutBack, onFinish: function onFinish() { boss.activate(); } }); } // Check collisions function checkCollisions() { // Player bullets vs enemies for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; // Check against enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { enemy.takeDamage(bullet.damage); bullet.removeFromGame(); break; } } // Check against asteroids for (var j = asteroids.length - 1; j >= 0; j--) { var asteroid = asteroids[j]; if (bullet.intersects(asteroid)) { asteroid.takeDamage(bullet.damage); bullet.removeFromGame(); break; } } // Check against bosses for (var j = bosses.length - 1; j >= 0; j--) { var boss = bosses[j]; if (bullet.intersects(boss) && boss.active) { boss.takeDamage(bullet.damage); bullet.removeFromGame(); break; } } } // Enemy bullets vs player for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; if (bullet.intersects(player)) { player.takeDamage(bullet.damage); bullet.removeFromGame(); } } // Player vs enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (player.intersects(enemy)) { player.takeDamage(20); enemy.takeDamage(enemy.health); // Destroy enemy } } // Player vs asteroids for (var i = asteroids.length - 1; i >= 0; i--) { var asteroid = asteroids[i]; if (player.intersects(asteroid)) { player.takeDamage(30); asteroid.takeDamage(asteroid.health); // Destroy asteroid } } // Player vs powerups for (var i = powerups.length - 1; i >= 0; i--) { var powerup = powerups[i]; if (player.intersects(powerup)) { player.applyPowerup(); powerup.removeFromGame(); } } } // Handle player movement function handleDrag(x, y) { if (dragNode) { dragNode.x = x; dragNode.y = y; // Constrain player to screen bounds if (dragNode.x < 50) { dragNode.x = 50; } if (dragNode.x > 2048 - 50) { dragNode.x = 2048 - 50; } if (dragNode.y < 50) { dragNode.y = 50; } if (dragNode.y > 2732 - 50) { dragNode.y = 2732 - 50; } } } // Event handlers game.down = function (x, y, obj) { // Only set drag if we're started if (gameStarted) { dragNode = player; handleDrag(x, y); } else { // Start game on first touch gameStarted = true; initPlayer(); initLevel(); } }; game.up = function (x, y, obj) { dragNode = null; }; game.move = function (x, y, obj) { handleDrag(x, y); }; // Main game update loop game.update = function () { if (!gameStarted) { // Show start screen text if (!game.startText) { game.startText = new Text2('Tap to Start\nSpace Defender', { size: 150, fill: 0xFFFFFF }); game.startText.anchor.set(0.5, 0.5); game.startText.x = 2048 / 2; game.startText.y = 2732 / 2; game.addChild(game.startText); } return; } else if (game.startText) { game.startText.destroy(); game.startText = null; } // Update UI scoreTxt.setText('Score: ' + LK.getScore()); if (player) { // Update health bar healthBar.scaleX = Math.max(0, player.health / 100); // Auto-fire player.shoot(); } // Spawn enemies if (!bossSpawned) { enemySpawnTimer--; if (enemySpawnTimer <= 0) { spawnEnemy(); // Spawn rate increases with level enemySpawnTimer = Math.max(20, 100 - level * 10); } // Spawn asteroids asteroidSpawnTimer--; if (asteroidSpawnTimer <= 0) { spawnAsteroid(); asteroidSpawnTimer = Math.max(60, 300 - level * 20); } // Check if we should spawn boss if (enemiesDefeated >= levelEnemiesRequired) { bossSpawned = true; spawnBoss(); } } // Update all game objects for (var i = bullets.length - 1; i >= 0; i--) { bullets[i].update(); } for (var i = enemies.length - 1; i >= 0; i--) { enemies[i].update(); } for (var i = enemyBullets.length - 1; i >= 0; i--) { enemyBullets[i].update(); } for (var i = asteroids.length - 1; i >= 0; i--) { asteroids[i].update(); } for (var i = powerups.length - 1; i >= 0; i--) { powerups[i].update(); } for (var i = bosses.length - 1; i >= 0; i--) { bosses[i].update(); } // Check for collisions checkCollisions(); }; // Start game music LK.playMusic('bgMusic', { fade: { start: 0, end: 0.3, duration: 1000 } });
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,843 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1", {
+ highScore: 0,
+ level: 1
+});
+
+/****
+* Classes
+****/
+var Asteroid = Container.expand(function () {
+ var self = Container.call(this);
+ // Random size asteroid
+ var size = Math.random() * 0.7 + 0.7; // 0.7 to 1.4
+ var asteroidGraphics = self.attachAsset('asteroid', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: size,
+ scaleY: size
+ });
+ self.health = 30 * size;
+ self.speed = 3 / size; // Bigger asteroids move slower
+ self.rotationSpeed = (Math.random() - 0.5) * 0.05;
+ self.points = Math.floor(50 * size);
+ self.takeDamage = function (amount) {
+ self.health -= amount;
+ LK.effects.flashObject(self, 0x888888, 200);
+ if (self.health <= 0) {
+ self.onDestroyed();
+ }
+ };
+ self.onDestroyed = function () {
+ // Add points to score
+ LK.setScore(LK.getScore() + self.points);
+ // Create explosion
+ var explosion = new Explosion(self.x, self.y, size);
+ game.addChild(explosion);
+ LK.getSound('explosion').play();
+ // Remove from game
+ var index = asteroids.indexOf(self);
+ if (index > -1) {
+ asteroids.splice(index, 1);
+ self.destroy();
+ }
+ };
+ self.update = function () {
+ self.y += self.speed;
+ asteroidGraphics.rotation += self.rotationSpeed;
+ // Check if asteroid is off-screen
+ if (self.y > 2732 + 100) {
+ var index = asteroids.indexOf(self);
+ if (index > -1) {
+ asteroids.splice(index, 1);
+ self.destroy();
+ }
+ }
+ };
+ return self;
+});
+var Boss = Container.expand(function () {
+ var self = Container.call(this);
+ var bossGraphics = self.attachAsset('boss', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.health = 500;
+ self.maxHealth = 500;
+ self.speed = 2;
+ self.points = 2000;
+ self.active = false;
+ self.phase = 1;
+ self.directionX = 1;
+ self.shootCooldown = 30;
+ self.specialAttackCooldown = 300;
+ // Health bar
+ self.healthBar = self.attachAsset('healthBar', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ y: -150
+ });
+ self.takeDamage = function (amount) {
+ self.health -= amount;
+ LK.effects.flashObject(self, 0xff0000, 200);
+ // Update health bar scale
+ self.healthBar.scaleX = Math.max(0, self.health / self.maxHealth);
+ // Phase transition at 50% health
+ if (self.health <= self.maxHealth / 2 && self.phase === 1) {
+ self.phase = 2;
+ self.speed = 4;
+ LK.effects.flashObject(self, 0xff00ff, 1000); // Purple flash for phase transition
+ }
+ if (self.health <= 0) {
+ self.onDestroyed();
+ }
+ };
+ self.onDestroyed = function () {
+ // Add points to score
+ LK.setScore(LK.getScore() + self.points);
+ // Create multiple explosions
+ for (var i = 0; i < 8; i++) {
+ var explosionX = self.x + (Math.random() * 300 - 150);
+ var explosionY = self.y + (Math.random() * 200 - 100);
+ var explosion = new Explosion(explosionX, explosionY, 2);
+ game.addChild(explosion);
+ // Stagger the explosions
+ (function (delay) {
+ LK.setTimeout(function () {
+ LK.getSound('explosion').play();
+ }, delay * 200);
+ })(i);
+ }
+ // Complete level
+ level++;
+ if (level > storage.level) {
+ storage.level = level;
+ }
+ // Check high score
+ if (LK.getScore() > storage.highScore) {
+ storage.highScore = LK.getScore();
+ }
+ // Show win screen
+ LK.showYouWin();
+ // Remove from game
+ var index = bosses.indexOf(self);
+ if (index > -1) {
+ bosses.splice(index, 1);
+ self.destroy();
+ }
+ };
+ self.shoot = function () {
+ // Basic attack - 3 bullets
+ for (var i = -1; i <= 1; i++) {
+ var bullet = new EnemyBullet();
+ bullet.x = self.x + i * 80;
+ bullet.y = self.y + 100;
+ game.addChild(bullet);
+ enemyBullets.push(bullet);
+ }
+ LK.getSound('enemyShoot').play();
+ };
+ self.specialAttack = function () {
+ // Special attack based on phase
+ if (self.phase === 1) {
+ // Phase 1: Circle of 8 bullets
+ for (var i = 0; i < 8; i++) {
+ var angle = i / 8 * Math.PI * 2;
+ var bullet = new EnemyBullet();
+ bullet.x = self.x + Math.cos(angle) * 100;
+ bullet.y = self.y + Math.sin(angle) * 100;
+ bullet.directionX = Math.cos(angle);
+ bullet.directionY = Math.sin(angle);
+ game.addChild(bullet);
+ enemyBullets.push(bullet);
+ }
+ } else {
+ // Phase 2: Targeted volley at player
+ for (var i = 0; i < 5; i++) {
+ var bullet = new EnemyBullet();
+ bullet.x = self.x;
+ bullet.y = self.y + 100;
+ // Target the player
+ var dx = player.x - bullet.x;
+ var dy = player.y - bullet.y;
+ var dist = Math.sqrt(dx * dx + dy * dy);
+ bullet.directionX = dx / dist;
+ bullet.directionY = dy / dist;
+ bullet.speed = 8 + i;
+ game.addChild(bullet);
+ enemyBullets.push(bullet);
+ // Stagger the bullets slightly
+ (function (b, delay) {
+ LK.setTimeout(function () {
+ game.addChild(b);
+ enemyBullets.push(b);
+ }, delay * 100);
+ })(bullet, i);
+ }
+ }
+ LK.getSound('enemyShoot').play();
+ };
+ self.update = function () {
+ if (!self.active) {
+ return;
+ }
+ // Movement
+ self.x += self.speed * self.directionX;
+ // Bounce at screen edges
+ if (self.x < 300) {
+ self.x = 300;
+ self.directionX = 1;
+ } else if (self.x > 2048 - 300) {
+ self.x = 2048 - 300;
+ self.directionX = -1;
+ }
+ // Regular attacks
+ self.shootCooldown--;
+ if (self.shootCooldown <= 0) {
+ self.shoot();
+ self.shootCooldown = self.phase === 1 ? 60 : 40;
+ }
+ // Special attacks
+ self.specialAttackCooldown--;
+ if (self.specialAttackCooldown <= 0) {
+ self.specialAttack();
+ self.specialAttackCooldown = 300;
+ }
+ };
+ self.activate = function () {
+ self.active = true;
+ };
+ return self;
+});
+var Enemy = Container.expand(function () {
+ var self = Container.call(this);
+ var enemyGraphics = self.attachAsset('enemy', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.health = 20;
+ self.speed = 2;
+ self.shootCooldown = Math.floor(Math.random() * 120) + 60;
+ self.points = 100;
+ self.movementPattern = "straight"; // Default movement pattern
+ self.directionX = 0;
+ self.directionChangeTimer = 0;
+ self.takeDamage = function (amount) {
+ self.health -= amount;
+ LK.effects.flashObject(self, 0xff0000, 200);
+ if (self.health <= 0) {
+ self.onDestroyed();
+ }
+ };
+ self.onDestroyed = function () {
+ // Add points to score
+ LK.setScore(LK.getScore() + self.points);
+ // Create explosion
+ var explosion = new Explosion(self.x, self.y, 1);
+ game.addChild(explosion);
+ LK.getSound('explosion').play();
+ // Check if should drop powerup (20% chance)
+ if (Math.random() < 0.2) {
+ var powerup = new Powerup();
+ powerup.x = self.x;
+ powerup.y = self.y;
+ game.addChild(powerup);
+ powerups.push(powerup);
+ }
+ // Remove from game
+ var index = enemies.indexOf(self);
+ if (index > -1) {
+ enemies.splice(index, 1);
+ self.destroy();
+ }
+ };
+ self.shoot = function () {
+ var bullet = new EnemyBullet();
+ bullet.x = self.x;
+ bullet.y = self.y + 50;
+ game.addChild(bullet);
+ enemyBullets.push(bullet);
+ LK.getSound('enemyShoot').play();
+ };
+ self.setMovementPattern = function (pattern) {
+ self.movementPattern = pattern;
+ if (pattern === "zigzag") {
+ self.directionX = Math.random() < 0.5 ? -1 : 1;
+ self.speed = 3;
+ } else if (pattern === "circle") {
+ self.angle = Math.random() * Math.PI * 2;
+ self.centerX = self.x;
+ self.centerY = self.y;
+ self.radius = 100;
+ self.speed = 0.02;
+ } else if (pattern === "sine") {
+ self.startX = self.x;
+ self.amplitude = 150;
+ self.frequency = 0.01;
+ self.angle = Math.random() * Math.PI * 2;
+ }
+ };
+ self.update = function () {
+ // Movement based on pattern
+ if (self.movementPattern === "straight") {
+ self.y += self.speed;
+ } else if (self.movementPattern === "zigzag") {
+ self.y += self.speed;
+ self.x += self.speed * 2 * self.directionX;
+ self.directionChangeTimer++;
+ if (self.directionChangeTimer > 60) {
+ self.directionX *= -1;
+ self.directionChangeTimer = 0;
+ }
+ // Bounce off screen edges
+ if (self.x < 50) {
+ self.x = 50;
+ self.directionX = 1;
+ } else if (self.x > 2048 - 50) {
+ self.x = 2048 - 50;
+ self.directionX = -1;
+ }
+ } else if (self.movementPattern === "circle") {
+ self.angle += self.speed;
+ self.x = self.centerX + Math.cos(self.angle) * self.radius;
+ self.y = self.centerY + Math.sin(self.angle) * self.radius + self.speed * 20;
+ } else if (self.movementPattern === "sine") {
+ self.y += self.speed * 2;
+ self.angle += self.frequency;
+ self.x = self.startX + Math.sin(self.angle) * self.amplitude;
+ }
+ // Shooting
+ self.shootCooldown--;
+ if (self.shootCooldown <= 0) {
+ self.shoot();
+ self.shootCooldown = Math.floor(Math.random() * 120) + 120;
+ }
+ // Remove if off screen
+ if (self.y > 2732 + 100) {
+ var index = enemies.indexOf(self);
+ if (index > -1) {
+ enemies.splice(index, 1);
+ self.destroy();
+ }
+ }
+ };
+ 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.damage = 10;
+ self.directionX = 0;
+ self.directionY = 1;
+ self.update = function () {
+ // Move based on direction
+ self.x += self.directionX * self.speed;
+ self.y += self.directionY * self.speed;
+ // Check if bullet is off-screen
+ if (self.y > 2732 + 50 || self.y < -50 || self.x < -50 || self.x > 2048 + 50) {
+ self.removeFromGame();
+ }
+ };
+ self.removeFromGame = function () {
+ var index = enemyBullets.indexOf(self);
+ if (index > -1) {
+ enemyBullets.splice(index, 1);
+ self.destroy();
+ }
+ };
+ return self;
+});
+var Explosion = Container.expand(function (x, y, size) {
+ var self = Container.call(this);
+ self.x = x;
+ self.y = y;
+ var explosionGraphics = self.attachAsset('explosion', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: size || 1,
+ scaleY: size || 1,
+ alpha: 0.9
+ });
+ // Animation for explosion
+ self.duration = 30; // 0.5 seconds at 60fps
+ self.timer = 0;
+ self.update = function () {
+ self.timer++;
+ // Scale up and fade out
+ var progress = self.timer / self.duration;
+ explosionGraphics.scaleX = (size || 1) * (1 + progress);
+ explosionGraphics.scaleY = (size || 1) * (1 + progress);
+ explosionGraphics.alpha = 1 - progress;
+ if (self.timer >= self.duration) {
+ self.destroy();
+ }
+ };
+ return self;
+});
+var Player = Container.expand(function () {
+ var self = Container.call(this);
+ var playerGraphics = self.attachAsset('player', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.health = 100;
+ self.speed = 15;
+ self.shootCooldown = 0;
+ self.invulnerable = false;
+ self.powerupTimer = 0;
+ self.powerupActive = false;
+ self.takeDamage = function (amount) {
+ if (self.invulnerable) {
+ return;
+ }
+ self.health -= amount;
+ if (self.health <= 0) {
+ self.health = 0;
+ self.onDestroyed();
+ } else {
+ // Flash player when hit
+ self.invulnerable = true;
+ LK.effects.flashObject(self, 0xffffff, 500);
+ LK.setTimeout(function () {
+ self.invulnerable = false;
+ }, 1000);
+ }
+ };
+ self.applyPowerup = function () {
+ self.powerupActive = true;
+ self.powerupTimer = 300; // 5 seconds at 60fps
+ playerGraphics.tint = 0x00ff00; // Green tint for powered up
+ LK.getSound('powerup').play();
+ };
+ self.shoot = function () {
+ if (self.shootCooldown <= 0) {
+ var bullet = new PlayerBullet();
+ bullet.x = self.x;
+ bullet.y = self.y - 70;
+ game.addChild(bullet);
+ bullets.push(bullet);
+ LK.getSound('playerShoot').play();
+ // If powered up, shoot 3 bullets instead of 1
+ if (self.powerupActive) {
+ var bulletLeft = new PlayerBullet();
+ bulletLeft.x = self.x - 40;
+ bulletLeft.y = self.y - 50;
+ var bulletRight = new PlayerBullet();
+ bulletRight.x = self.x + 40;
+ bulletRight.y = self.y - 50;
+ game.addChild(bulletLeft);
+ game.addChild(bulletRight);
+ bullets.push(bulletLeft);
+ bullets.push(bulletRight);
+ }
+ self.shootCooldown = self.powerupActive ? 10 : 15;
+ }
+ };
+ self.onDestroyed = function () {
+ var explosion = new Explosion(self.x, self.y, 2);
+ game.addChild(explosion);
+ LK.getSound('explosion').play();
+ // Show game over
+ LK.showGameOver();
+ };
+ self.update = function () {
+ if (self.shootCooldown > 0) {
+ self.shootCooldown--;
+ }
+ if (self.powerupActive) {
+ self.powerupTimer--;
+ if (self.powerupTimer <= 0) {
+ self.powerupActive = false;
+ playerGraphics.tint = 0xffffff; // Reset tint
+ }
+ }
+ };
+ 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; // Move upwards
+ self.damage = 10;
+ self.update = function () {
+ self.y += self.speed;
+ // Check if bullet is off-screen
+ if (self.y < -50) {
+ self.removeFromGame();
+ }
+ };
+ self.removeFromGame = function () {
+ var index = bullets.indexOf(self);
+ if (index > -1) {
+ bullets.splice(index, 1);
+ self.destroy();
+ }
+ };
+ 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.pulsateTimer = 0;
+ self.update = function () {
+ self.y += self.speed;
+ // Pulsate effect
+ self.pulsateTimer += 0.05;
+ var scale = 1 + Math.sin(self.pulsateTimer) * 0.2;
+ powerupGraphics.scaleX = scale;
+ powerupGraphics.scaleY = scale;
+ // Remove if off screen
+ if (self.y > 2732 + 50) {
+ self.removeFromGame();
+ }
+ };
+ self.removeFromGame = function () {
+ var index = powerups.indexOf(self);
+ if (index > -1) {
+ powerups.splice(index, 1);
+ self.destroy();
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
+ backgroundColor: 0x000011 // Deep space blue
+});
+
+/****
+* Game Code
+****/
+// Game state variables
+var player;
+var bullets = [];
+var enemies = [];
+var enemyBullets = [];
+var asteroids = [];
+var powerups = [];
+var bosses = [];
+var level = storage.level || 1;
+var enemySpawnTimer = 0;
+var asteroidSpawnTimer = 0;
+var bossSpawned = false;
+var gameStarted = false;
+var levelEnemiesRequired;
+var enemiesDefeated = 0;
+var dragNode = null;
+// Set up UI
+var scoreTxt = new Text2('Score: 0', {
+ size: 70,
+ fill: 0xFFFFFF
+});
+scoreTxt.anchor.set(0, 0);
+LK.gui.topRight.addChild(scoreTxt);
+var levelTxt = new Text2('Level: ' + level, {
+ size: 70,
+ fill: 0xFFFFFF
+});
+levelTxt.anchor.set(1, 0);
+LK.gui.topLeft.addChild(levelTxt);
+levelTxt.x = 250; // Make sure it's not in the top-left corner
+var healthBar = LK.getAsset('healthBar', {
+ anchorX: 0,
+ anchorY: 0.5,
+ scaleX: 1,
+ scaleY: 0.6
+});
+healthBar.x = 200;
+LK.gui.bottom.addChild(healthBar);
+var healthTxt = new Text2('Health', {
+ size: 60,
+ fill: 0xFFFFFF
+});
+healthTxt.anchor.set(0.5, 0.5);
+healthTxt.x = 100;
+LK.gui.bottom.addChild(healthTxt);
+// Initialize player
+function initPlayer() {
+ player = new Player();
+ player.x = 2048 / 2;
+ player.y = 2732 - 200;
+ game.addChild(player);
+}
+// Initialize level
+function initLevel() {
+ // Clear any existing enemies and bullets
+ for (var i = enemies.length - 1; i >= 0; i--) {
+ enemies[i].destroy();
+ }
+ for (var i = enemyBullets.length - 1; i >= 0; i--) {
+ enemyBullets[i].destroy();
+ }
+ for (var i = asteroids.length - 1; i >= 0; i--) {
+ asteroids[i].destroy();
+ }
+ for (var i = powerups.length - 1; i >= 0; i--) {
+ powerups[i].destroy();
+ }
+ for (var i = bosses.length - 1; i >= 0; i--) {
+ bosses[i].destroy();
+ }
+ enemies = [];
+ enemyBullets = [];
+ asteroids = [];
+ powerups = [];
+ bosses = [];
+ bossSpawned = false;
+ enemiesDefeated = 0;
+ // Set level difficulty
+ levelEnemiesRequired = level * 15;
+ enemySpawnTimer = 60;
+ asteroidSpawnTimer = 180;
+ // Update UI
+ levelTxt.setText('Level: ' + level);
+ // Start music
+ LK.playMusic('bgMusic');
+}
+// Spawn enemy with random pattern
+function spawnEnemy() {
+ var enemy = new Enemy();
+ // Random x position
+ enemy.x = Math.random() * (2048 - 200) + 100;
+ enemy.y = -100;
+ // Set health and pattern based on level
+ enemy.health = 20 + level * 5;
+ // Choose movement pattern
+ var patterns = ["straight", "zigzag", "sine"];
+ if (level >= 3) {
+ patterns.push("circle");
+ }
+ var pattern = patterns[Math.floor(Math.random() * patterns.length)];
+ enemy.setMovementPattern(pattern);
+ game.addChild(enemy);
+ enemies.push(enemy);
+}
+// Spawn asteroid
+function spawnAsteroid() {
+ var asteroid = new Asteroid();
+ // Random x position
+ asteroid.x = Math.random() * (2048 - 200) + 100;
+ asteroid.y = -100;
+ game.addChild(asteroid);
+ asteroids.push(asteroid);
+}
+// Spawn boss
+function spawnBoss() {
+ var boss = new Boss();
+ boss.x = 2048 / 2;
+ boss.y = 300;
+ // Adjust boss health based on level
+ boss.health = 500 + level * 100;
+ boss.maxHealth = boss.health;
+ game.addChild(boss);
+ bosses.push(boss);
+ // Activate boss after entrance animation
+ tween(boss, {
+ y: 300
+ }, {
+ duration: 2000,
+ easing: tween.easeOutBack,
+ onFinish: function onFinish() {
+ boss.activate();
+ }
+ });
+}
+// Check collisions
+function checkCollisions() {
+ // Player bullets vs enemies
+ for (var i = bullets.length - 1; i >= 0; i--) {
+ var bullet = bullets[i];
+ // Check against enemies
+ for (var j = enemies.length - 1; j >= 0; j--) {
+ var enemy = enemies[j];
+ if (bullet.intersects(enemy)) {
+ enemy.takeDamage(bullet.damage);
+ bullet.removeFromGame();
+ break;
+ }
+ }
+ // Check against asteroids
+ for (var j = asteroids.length - 1; j >= 0; j--) {
+ var asteroid = asteroids[j];
+ if (bullet.intersects(asteroid)) {
+ asteroid.takeDamage(bullet.damage);
+ bullet.removeFromGame();
+ break;
+ }
+ }
+ // Check against bosses
+ for (var j = bosses.length - 1; j >= 0; j--) {
+ var boss = bosses[j];
+ if (bullet.intersects(boss) && boss.active) {
+ boss.takeDamage(bullet.damage);
+ bullet.removeFromGame();
+ break;
+ }
+ }
+ }
+ // Enemy bullets vs player
+ for (var i = enemyBullets.length - 1; i >= 0; i--) {
+ var bullet = enemyBullets[i];
+ if (bullet.intersects(player)) {
+ player.takeDamage(bullet.damage);
+ bullet.removeFromGame();
+ }
+ }
+ // Player vs enemies
+ for (var i = enemies.length - 1; i >= 0; i--) {
+ var enemy = enemies[i];
+ if (player.intersects(enemy)) {
+ player.takeDamage(20);
+ enemy.takeDamage(enemy.health); // Destroy enemy
+ }
+ }
+ // Player vs asteroids
+ for (var i = asteroids.length - 1; i >= 0; i--) {
+ var asteroid = asteroids[i];
+ if (player.intersects(asteroid)) {
+ player.takeDamage(30);
+ asteroid.takeDamage(asteroid.health); // Destroy asteroid
+ }
+ }
+ // Player vs powerups
+ for (var i = powerups.length - 1; i >= 0; i--) {
+ var powerup = powerups[i];
+ if (player.intersects(powerup)) {
+ player.applyPowerup();
+ powerup.removeFromGame();
+ }
+ }
+}
+// Handle player movement
+function handleDrag(x, y) {
+ if (dragNode) {
+ dragNode.x = x;
+ dragNode.y = y;
+ // Constrain player to screen bounds
+ if (dragNode.x < 50) {
+ dragNode.x = 50;
+ }
+ if (dragNode.x > 2048 - 50) {
+ dragNode.x = 2048 - 50;
+ }
+ if (dragNode.y < 50) {
+ dragNode.y = 50;
+ }
+ if (dragNode.y > 2732 - 50) {
+ dragNode.y = 2732 - 50;
+ }
+ }
+}
+// Event handlers
+game.down = function (x, y, obj) {
+ // Only set drag if we're started
+ if (gameStarted) {
+ dragNode = player;
+ handleDrag(x, y);
+ } else {
+ // Start game on first touch
+ gameStarted = true;
+ initPlayer();
+ initLevel();
+ }
+};
+game.up = function (x, y, obj) {
+ dragNode = null;
+};
+game.move = function (x, y, obj) {
+ handleDrag(x, y);
+};
+// Main game update loop
+game.update = function () {
+ if (!gameStarted) {
+ // Show start screen text
+ if (!game.startText) {
+ game.startText = new Text2('Tap to Start\nSpace Defender', {
+ size: 150,
+ fill: 0xFFFFFF
+ });
+ game.startText.anchor.set(0.5, 0.5);
+ game.startText.x = 2048 / 2;
+ game.startText.y = 2732 / 2;
+ game.addChild(game.startText);
+ }
+ return;
+ } else if (game.startText) {
+ game.startText.destroy();
+ game.startText = null;
+ }
+ // Update UI
+ scoreTxt.setText('Score: ' + LK.getScore());
+ if (player) {
+ // Update health bar
+ healthBar.scaleX = Math.max(0, player.health / 100);
+ // Auto-fire
+ player.shoot();
+ }
+ // Spawn enemies
+ if (!bossSpawned) {
+ enemySpawnTimer--;
+ if (enemySpawnTimer <= 0) {
+ spawnEnemy();
+ // Spawn rate increases with level
+ enemySpawnTimer = Math.max(20, 100 - level * 10);
+ }
+ // Spawn asteroids
+ asteroidSpawnTimer--;
+ if (asteroidSpawnTimer <= 0) {
+ spawnAsteroid();
+ asteroidSpawnTimer = Math.max(60, 300 - level * 20);
+ }
+ // Check if we should spawn boss
+ if (enemiesDefeated >= levelEnemiesRequired) {
+ bossSpawned = true;
+ spawnBoss();
+ }
+ }
+ // Update all game objects
+ for (var i = bullets.length - 1; i >= 0; i--) {
+ bullets[i].update();
+ }
+ for (var i = enemies.length - 1; i >= 0; i--) {
+ enemies[i].update();
+ }
+ for (var i = enemyBullets.length - 1; i >= 0; i--) {
+ enemyBullets[i].update();
+ }
+ for (var i = asteroids.length - 1; i >= 0; i--) {
+ asteroids[i].update();
+ }
+ for (var i = powerups.length - 1; i >= 0; i--) {
+ powerups[i].update();
+ }
+ for (var i = bosses.length - 1; i >= 0; i--) {
+ bosses[i].update();
+ }
+ // Check for collisions
+ checkCollisions();
+};
+// Start game music
+LK.playMusic('bgMusic', {
+ fade: {
+ start: 0,
+ end: 0.3,
+ duration: 1000
+ }
});
\ No newline at end of file
asteroid. In-Game asset. 2d. High contrast. No shadows
spaceship enemy. In-Game asset. 2d. High contrast. No shadows
enemyBullet. In-Game asset. 2d. High contrast. No shadows
playerBullet. In-Game asset. 2d. High contrast. No shadows
explosion. In-Game asset. 2d. High contrast. No shadows
powerup. In-Game asset. 2d. High contrast. No shadows
boss spaceship. In-Game asset. 2d. High contrast. No shadows