/**** * 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, scaleY: 1 }); self.speed = 5; self.rotationSpeed = (Math.random() - 0.5) * 0.1; self.active = true; self.size = 1; self.health = 1; self.value = 10; self.setup = function (size) { self.size = size || 1; if (self.size === 2) { asteroidGraphics.scale.set(1.5); self.health = 2; self.value = 20; } else if (self.size === 3) { asteroidGraphics.scale.set(2); self.health = 3; self.value = 30; } }; self.hit = function () { self.health -= 1; LK.effects.flashObject(self, 0xff0000, 200); if (self.health <= 0) { self.active = false; return true; } return false; }; self.update = function () { self.y += self.speed; self.rotation += self.rotationSpeed; // Off-screen check (below screen) if (self.y > 2732 + 100) { self.active = false; } }; return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -15; self.active = true; self.update = function () { self.y += self.speed; // Off-screen check if (self.y < -50) { self.active = false; } }; return self; }); var Earth = Container.expand(function () { var self = Container.call(this); var earthGraphics = self.attachAsset('earth', { anchorX: 0.5, anchorY: 0.5 }); self.health = 100; self.damage = function (amount) { self.health -= amount; if (self.health < 0) { self.health = 0; } // Flash earth red when damaged LK.effects.flashObject(self, 0xff0000, 300); return self.health <= 0; }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var shipGraphics = self.attachAsset('playerShip', { anchorX: 0.5, anchorY: 0.5 }); var shieldGraphics = self.attachAsset('shield', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); self.lives = 3; self.shieldActive = false; self.invulnerable = false; self.multishot = false; self.multishotDuration = 0; self.shieldDuration = 0; self.activateShield = function () { self.shieldActive = true; self.shieldDuration = 300; // 5 seconds (60 fps * 5) shieldGraphics.alpha = 0.6; tween(shieldGraphics, { alpha: 0.6 }, { duration: 300, easing: tween.easeOut }); }; self.deactivateShield = function () { self.shieldActive = false; tween(shieldGraphics, { alpha: 0 }, { duration: 300, easing: tween.easeIn }); }; self.activateMultishot = function () { self.multishot = true; self.multishotDuration = 300; // 5 seconds // Visual indicator - make ship blink red var flashInterval = LK.setInterval(function () { shipGraphics.tint = shipGraphics.tint === 0xFFFFFF ? 0xff9999 : 0xFFFFFF; }, 200); LK.setTimeout(function () { LK.clearInterval(flashInterval); shipGraphics.tint = 0xFFFFFF; }, 5000); }; self.hit = function () { if (self.shieldActive) { self.deactivateShield(); return false; } if (!self.invulnerable) { self.lives--; self.invulnerable = true; // Flash effect LK.effects.flashObject(self, 0xff0000, 500); // Make player semi-transparent while invulnerable shipGraphics.alpha = 0.5; // Make player vulnerable again after 2 seconds LK.setTimeout(function () { self.invulnerable = false; shipGraphics.alpha = 1; }, 2000); return true; } return false; }; self.update = function () { // Update shield duration if (self.shieldActive) { self.shieldDuration--; if (self.shieldDuration <= 0) { self.deactivateShield(); } } // Update multishot duration if (self.multishot) { self.multishotDuration--; if (self.multishotDuration <= 0) { self.multishot = false; } } }; self.down = function (x, y, obj) { // This is handled in game down handler }; 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.active = true; self.type = "shield"; // Default type self.setup = function (type) { self.type = type || "shield"; // Change color based on type if (self.type === "shield") { powerupGraphics.tint = 0x3498db; // Blue } else if (self.type === "multishot") { powerupGraphics.tint = 0xe74c3c; // Red } else if (self.type === "bomb") { powerupGraphics.tint = 0xf1c40f; // Yellow } }; self.update = function () { self.y += self.speed; // Make it pulse slightly if (LK.ticks % 10 === 0) { tween(powerupGraphics.scale, { x: 1.1, y: 1.1 }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { tween(powerupGraphics.scale, { x: 1, y: 1 }, { duration: 300, easing: tween.easeInOut }); } }); } // Off-screen check if (self.y > 2732 + 50) { self.active = false; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var WAVE_DELAY = 180; // 3 seconds between waves var MAX_ASTEROIDS = 10; // Maximum number of asteroids on screen at once var ASTEROID_SPAWN_CHANCE = 0.02; // Chance to spawn a new asteroid each frame when below max var POWERUP_CHANCE = 0.002; // Chance to spawn a powerup each frame // Game variables var player; var earth; var bullets = []; var asteroids = []; var powerups = []; var waveNumber = 1; var waveDelay = 0; var score = 0; var combo = 0; var comboTimer = 0; var dragMode = false; var gameStarted = false; var gameOver = false; // UI elements var scoreTxt; var waveText; var livesText; var earthHealthText; var comboText; var startText; // Initialize game function initGame() { // Set background to space game.setBackgroundColor(0x000033); // Create earth (at bottom center) earth = new Earth(); earth.x = GAME_WIDTH / 2; earth.y = GAME_HEIGHT - 250; game.addChild(earth); // Create player player = new Player(); player.x = GAME_WIDTH / 2; player.y = GAME_HEIGHT - 500; game.addChild(player); // Reset game variables bullets = []; asteroids = []; powerups = []; waveNumber = 1; waveDelay = 120; // 2 second delay before first wave score = 0; combo = 0; comboTimer = 0; // Update LK score LK.setScore(0); // Create score text scoreTxt = new Text2("SCORE: 0", { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(scoreTxt); // Create wave text waveText = new Text2("WAVE: 1", { size: 80, fill: 0xFFFFFF }); waveText.anchor.set(1, 0); LK.gui.topLeft.addChild(waveText); // Create lives text livesText = new Text2("SHIELDS: 3", { size: 80, fill: 0xFFFFFF }); livesText.anchor.set(0.5, 0); LK.gui.top.addChild(livesText); // Create earth health text earthHealthText = new Text2("EARTH: 100%", { size: 80, fill: 0xFFFFFF }); earthHealthText.anchor.set(0.5, 0); LK.gui.bottom.addChild(earthHealthText); // Create combo text (initially invisible) comboText = new Text2("COMBO: x1", { size: 100, fill: 0xFFFF00 }); comboText.anchor.set(0.5, 0.5); comboText.x = GAME_WIDTH / 2; comboText.y = GAME_HEIGHT / 2; comboText.alpha = 0; game.addChild(comboText); // Create start text startText = new Text2("TAP TO START", { size: 120, fill: 0xFFFFFF }); startText.anchor.set(0.5, 0.5); LK.gui.center.addChild(startText); // Animate start text pulseStartText(); gameStarted = false; gameOver = false; // Play music LK.playMusic('gameMusic', { fade: { start: 0, end: 0.3, duration: 1000 } }); } function pulseStartText() { tween(startText.scale, { x: 1.1, y: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(startText.scale, { x: 1, y: 1 }, { duration: 800, easing: tween.easeInOut, onFinish: pulseStartText }); } }); } function startGame() { gameStarted = true; // Hide start text tween(startText, { alpha: 0 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { LK.gui.center.removeChild(startText); } }); } // Spawn a new wave of asteroids function spawnWave() { var asteroidCount = Math.min(5 + waveNumber, MAX_ASTEROIDS); var speed = Math.min(4 + waveNumber * 0.5, 12); for (var i = 0; i < asteroidCount; i++) { var size = 1; var random = Math.random(); // Higher chance of larger asteroids in later waves if (waveNumber > 3 && random > 0.7) { size = 2; } if (waveNumber > 7 && random > 0.9) { size = 3; } spawnAsteroid(size, speed); } // Show wave number waveText.setText("WAVE: " + waveNumber); var waveAnnouncement = new Text2("WAVE " + waveNumber, { size: 150, fill: 0xFFFF00 }); waveAnnouncement.anchor.set(0.5, 0.5); waveAnnouncement.x = GAME_WIDTH / 2; waveAnnouncement.y = GAME_HEIGHT / 2; game.addChild(waveAnnouncement); // Animate wave announcement tween(waveAnnouncement.scale, { x: 1.5, y: 1.5 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { tween(waveAnnouncement, { alpha: 0 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { game.removeChild(waveAnnouncement); } }); } }); waveNumber++; } // Spawn a single asteroid function spawnAsteroid(size, speed) { var asteroid = new Asteroid(); asteroid.x = Math.random() * (GAME_WIDTH - 100) + 50; asteroid.y = -100; asteroid.speed = speed || 4 + Math.random() * 3; asteroid.setup(size || 1); asteroids.push(asteroid); game.addChild(asteroid); return asteroid; } // Spawn a power-up function spawnPowerup() { var powerup = new PowerUp(); powerup.x = Math.random() * (GAME_WIDTH - 100) + 50; powerup.y = -100; // Choose random power-up type var random = Math.random(); if (random < 0.4) { powerup.setup("shield"); } else if (random < 0.8) { powerup.setup("multishot"); } else { powerup.setup("bomb"); } powerups.push(powerup); game.addChild(powerup); } // Fire bullets from player function fireBullet() { if (!gameStarted || gameOver) { return; } // Play sound LK.getSound('shoot').play(); if (player.multishot) { // Fire 3 bullets in a spread for (var i = -1; i <= 1; i++) { var bullet = new Bullet(); bullet.x = player.x + i * 40; bullet.y = player.y - 50; bullets.push(bullet); game.addChild(bullet); } } else { // Fire single bullet var bullet = new Bullet(); bullet.x = player.x; bullet.y = player.y - 50; bullets.push(bullet); game.addChild(bullet); } } // Check collisions between game objects function checkCollisions() { // Check bullet-asteroid collisions for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; if (!bullet.active) { continue; } for (var j = asteroids.length - 1; j >= 0; j--) { var asteroid = asteroids[j]; if (!asteroid.active) { continue; } if (bullet.intersects(asteroid)) { bullet.active = false; // Asteroid hit logic if (asteroid.hit()) { // Asteroid destroyed LK.getSound('explosion').play(); // Create explosion effect createExplosion(asteroid.x, asteroid.y); // Update score updateScore(asteroid.value); // Remove asteroid asteroid.active = false; } break; } } } // Check player-asteroid collisions if (!player.invulnerable) { for (var j = asteroids.length - 1; j >= 0; j--) { var asteroid = asteroids[j]; if (!asteroid.active) { continue; } if (player.intersects(asteroid)) { // Player hit if (player.hit()) { // Update lives display livesText.setText("SHIELDS: " + player.lives); // Check game over if (player.lives <= 0) { endGame(); return; } } // Create explosion effect createExplosion(asteroid.x, asteroid.y); // Remove asteroid asteroid.active = false; // Reset combo combo = 0; comboTimer = 0; comboText.alpha = 0; } } } // Check earth-asteroid collisions for (var j = asteroids.length - 1; j >= 0; j--) { var asteroid = asteroids[j]; if (!asteroid.active) { continue; } if (asteroid.intersects(earth)) { // Earth hit var damage = asteroid.size * 5; if (earth.damage(damage)) { // Game over if earth health reaches 0 endGame(); return; } // Update earth health display earthHealthText.setText("EARTH: " + earth.health + "%"); // Create explosion effect createExplosion(asteroid.x, asteroid.y); // Remove asteroid asteroid.active = false; // Reset combo combo = 0; comboTimer = 0; comboText.alpha = 0; } } // Check player-powerup collisions for (var j = powerups.length - 1; j >= 0; j--) { var powerup = powerups[j]; if (!powerup.active) { continue; } if (player.intersects(powerup)) { // Collect powerup LK.getSound('powerup').play(); if (powerup.type === "shield") { player.activateShield(); } else if (powerup.type === "multishot") { player.activateMultishot(); } else if (powerup.type === "bomb") { // Clear all asteroids for (var k = asteroids.length - 1; k >= 0; k--) { var asteroid = asteroids[k]; createExplosion(asteroid.x, asteroid.y); asteroid.active = false; updateScore(asteroid.value / 2); // Half points for bomb kills } // Screen flash LK.effects.flashScreen(0xffff00, 500); } // Remove powerup powerup.active = false; } } } // Create explosion effect function createExplosion(x, y) { var explosion = LK.getAsset('asteroid', { anchorX: 0.5, anchorY: 0.5, x: x, y: y, alpha: 0.8, tint: 0xff9900 }); game.addChild(explosion); // Animate explosion tween(explosion.scale, { x: 3, y: 3 }, { duration: 500, easing: tween.easeOut }); tween(explosion, { alpha: 0 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(explosion); } }); } // Update score with combo multiplier function updateScore(value) { // Update combo combo++; comboTimer = 180; // 3 seconds to maintain combo // Calculate score with combo var multiplier = Math.min(Math.floor(combo / 3) + 1, 5); var points = value * multiplier; score += points; LK.setScore(score); // Update score display scoreTxt.setText("SCORE: " + score); // Show combo text if multiplier > 1 if (multiplier > 1) { comboText.setText("COMBO: x" + multiplier); comboText.alpha = 1; // Make combo text pulse tween.stop(comboText.scale); comboText.scale.set(1); tween(comboText.scale, { x: 1.5, y: 1.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(comboText.scale, { x: 1, y: 1 }, { duration: 200, easing: tween.easeIn }); } }); } // Show floating score text var pointText = new Text2("+" + points, { size: 60, fill: 0xFFFF00 }); pointText.anchor.set(0.5, 0.5); pointText.x = player.x; pointText.y = player.y - 100; game.addChild(pointText); // Animate score text tween(pointText, { y: pointText.y - 100, alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { game.removeChild(pointText); } }); } // End the game function endGame() { gameOver = true; // Show game over text var gameOverText = new Text2("GAME OVER", { size: 200, fill: 0xFF0000 }); gameOverText.anchor.set(0.5, 0.5); LK.gui.center.addChild(gameOverText); // Animate game over text tween(gameOverText.scale, { x: 1.5, y: 1.5 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { // Show final score var finalScoreText = new Text2("FINAL SCORE: " + score, { size: 100, fill: 0xFFFFFF }); finalScoreText.anchor.set(0.5, 0.5); finalScoreText.y = 150; LK.gui.center.addChild(finalScoreText); // Show game over after a delay LK.setTimeout(function () { LK.showGameOver(); }, 3000); } }); // Stop music with fade out LK.playMusic('gameMusic', { fade: { start: 0.3, end: 0, duration: 2000 } }); } // Handle drag movement for player ship function handleMove(x, y, obj) { if (dragMode && gameStarted && !gameOver) { player.x = x; // Keep player within bounds if (player.x < 75) { player.x = 75; } if (player.x > GAME_WIDTH - 75) { player.x = GAME_WIDTH - 75; } } } // Initialize game initGame(); // Game mouse/touch events game.down = function (x, y, obj) { if (!gameStarted) { startGame(); return; } if (gameOver) { return; } dragMode = true; player.x = x; // Keep player within bounds if (player.x < 75) { player.x = 75; } if (player.x > GAME_WIDTH - 75) { player.x = GAME_WIDTH - 75; } // Fire bullet on touch fireBullet(); }; game.up = function (x, y, obj) { dragMode = false; }; game.move = handleMove; // Game update loop game.update = function () { if (!gameStarted) { return; } if (gameOver) { return; } // Update player player.update(); // Fire automatically every 15 frames (4 times per second) if (LK.ticks % 15 === 0) { fireBullet(); } // Update combo timer if (combo > 0) { comboTimer--; if (comboTimer <= 0) { combo = 0; tween(comboText, { alpha: 0 }, { duration: 500, easing: tween.easeOut }); } } // Update wave delay if (waveDelay > 0) { waveDelay--; if (waveDelay <= 0) { spawnWave(); waveDelay = WAVE_DELAY; } } // Random asteroid spawn between waves (with increasing chance based on wave) if (asteroids.length < MAX_ASTEROIDS && Math.random() < ASTEROID_SPAWN_CHANCE * (1 + waveNumber * 0.1)) { spawnAsteroid(); } // Random powerup spawn if (Math.random() < POWERUP_CHANCE) { spawnPowerup(); } // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { bullets[i].update(); if (!bullets[i].active) { game.removeChild(bullets[i]); bullets.splice(i, 1); } } // Update asteroids for (var i = asteroids.length - 1; i >= 0; i--) { asteroids[i].update(); if (!asteroids[i].active) { game.removeChild(asteroids[i]); asteroids.splice(i, 1); } } // Update powerups for (var i = powerups.length - 1; i >= 0; i--) { powerups[i].update(); if (!powerups[i].active) { game.removeChild(powerups[i]); powerups.splice(i, 1); } } // Check collisions checkCollisions(); };
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,833 @@
-/****
+/****
+* 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,
+ scaleY: 1
+ });
+ self.speed = 5;
+ self.rotationSpeed = (Math.random() - 0.5) * 0.1;
+ self.active = true;
+ self.size = 1;
+ self.health = 1;
+ self.value = 10;
+ self.setup = function (size) {
+ self.size = size || 1;
+ if (self.size === 2) {
+ asteroidGraphics.scale.set(1.5);
+ self.health = 2;
+ self.value = 20;
+ } else if (self.size === 3) {
+ asteroidGraphics.scale.set(2);
+ self.health = 3;
+ self.value = 30;
+ }
+ };
+ self.hit = function () {
+ self.health -= 1;
+ LK.effects.flashObject(self, 0xff0000, 200);
+ if (self.health <= 0) {
+ self.active = false;
+ return true;
+ }
+ return false;
+ };
+ self.update = function () {
+ self.y += self.speed;
+ self.rotation += self.rotationSpeed;
+ // Off-screen check (below screen)
+ if (self.y > 2732 + 100) {
+ self.active = false;
+ }
+ };
+ return self;
+});
+var Bullet = Container.expand(function () {
+ var self = Container.call(this);
+ var bulletGraphics = self.attachAsset('bullet', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = -15;
+ self.active = true;
+ self.update = function () {
+ self.y += self.speed;
+ // Off-screen check
+ if (self.y < -50) {
+ self.active = false;
+ }
+ };
+ return self;
+});
+var Earth = Container.expand(function () {
+ var self = Container.call(this);
+ var earthGraphics = self.attachAsset('earth', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.health = 100;
+ self.damage = function (amount) {
+ self.health -= amount;
+ if (self.health < 0) {
+ self.health = 0;
+ }
+ // Flash earth red when damaged
+ LK.effects.flashObject(self, 0xff0000, 300);
+ return self.health <= 0;
+ };
+ return self;
+});
+var Player = Container.expand(function () {
+ var self = Container.call(this);
+ var shipGraphics = self.attachAsset('playerShip', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ var shieldGraphics = self.attachAsset('shield', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0
+ });
+ self.lives = 3;
+ self.shieldActive = false;
+ self.invulnerable = false;
+ self.multishot = false;
+ self.multishotDuration = 0;
+ self.shieldDuration = 0;
+ self.activateShield = function () {
+ self.shieldActive = true;
+ self.shieldDuration = 300; // 5 seconds (60 fps * 5)
+ shieldGraphics.alpha = 0.6;
+ tween(shieldGraphics, {
+ alpha: 0.6
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ };
+ self.deactivateShield = function () {
+ self.shieldActive = false;
+ tween(shieldGraphics, {
+ alpha: 0
+ }, {
+ duration: 300,
+ easing: tween.easeIn
+ });
+ };
+ self.activateMultishot = function () {
+ self.multishot = true;
+ self.multishotDuration = 300; // 5 seconds
+ // Visual indicator - make ship blink red
+ var flashInterval = LK.setInterval(function () {
+ shipGraphics.tint = shipGraphics.tint === 0xFFFFFF ? 0xff9999 : 0xFFFFFF;
+ }, 200);
+ LK.setTimeout(function () {
+ LK.clearInterval(flashInterval);
+ shipGraphics.tint = 0xFFFFFF;
+ }, 5000);
+ };
+ self.hit = function () {
+ if (self.shieldActive) {
+ self.deactivateShield();
+ return false;
+ }
+ if (!self.invulnerable) {
+ self.lives--;
+ self.invulnerable = true;
+ // Flash effect
+ LK.effects.flashObject(self, 0xff0000, 500);
+ // Make player semi-transparent while invulnerable
+ shipGraphics.alpha = 0.5;
+ // Make player vulnerable again after 2 seconds
+ LK.setTimeout(function () {
+ self.invulnerable = false;
+ shipGraphics.alpha = 1;
+ }, 2000);
+ return true;
+ }
+ return false;
+ };
+ self.update = function () {
+ // Update shield duration
+ if (self.shieldActive) {
+ self.shieldDuration--;
+ if (self.shieldDuration <= 0) {
+ self.deactivateShield();
+ }
+ }
+ // Update multishot duration
+ if (self.multishot) {
+ self.multishotDuration--;
+ if (self.multishotDuration <= 0) {
+ self.multishot = false;
+ }
+ }
+ };
+ self.down = function (x, y, obj) {
+ // This is handled in game down handler
+ };
+ 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.active = true;
+ self.type = "shield"; // Default type
+ self.setup = function (type) {
+ self.type = type || "shield";
+ // Change color based on type
+ if (self.type === "shield") {
+ powerupGraphics.tint = 0x3498db; // Blue
+ } else if (self.type === "multishot") {
+ powerupGraphics.tint = 0xe74c3c; // Red
+ } else if (self.type === "bomb") {
+ powerupGraphics.tint = 0xf1c40f; // Yellow
+ }
+ };
+ self.update = function () {
+ self.y += self.speed;
+ // Make it pulse slightly
+ if (LK.ticks % 10 === 0) {
+ tween(powerupGraphics.scale, {
+ x: 1.1,
+ y: 1.1
+ }, {
+ duration: 300,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ tween(powerupGraphics.scale, {
+ x: 1,
+ y: 1
+ }, {
+ duration: 300,
+ easing: tween.easeInOut
+ });
+ }
+ });
+ }
+ // Off-screen check
+ if (self.y > 2732 + 50) {
+ self.active = false;
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
backgroundColor: 0x000000
-});
\ No newline at end of file
+});
+
+/****
+* Game Code
+****/
+// Game constants
+var GAME_WIDTH = 2048;
+var GAME_HEIGHT = 2732;
+var WAVE_DELAY = 180; // 3 seconds between waves
+var MAX_ASTEROIDS = 10; // Maximum number of asteroids on screen at once
+var ASTEROID_SPAWN_CHANCE = 0.02; // Chance to spawn a new asteroid each frame when below max
+var POWERUP_CHANCE = 0.002; // Chance to spawn a powerup each frame
+// Game variables
+var player;
+var earth;
+var bullets = [];
+var asteroids = [];
+var powerups = [];
+var waveNumber = 1;
+var waveDelay = 0;
+var score = 0;
+var combo = 0;
+var comboTimer = 0;
+var dragMode = false;
+var gameStarted = false;
+var gameOver = false;
+// UI elements
+var scoreTxt;
+var waveText;
+var livesText;
+var earthHealthText;
+var comboText;
+var startText;
+// Initialize game
+function initGame() {
+ // Set background to space
+ game.setBackgroundColor(0x000033);
+ // Create earth (at bottom center)
+ earth = new Earth();
+ earth.x = GAME_WIDTH / 2;
+ earth.y = GAME_HEIGHT - 250;
+ game.addChild(earth);
+ // Create player
+ player = new Player();
+ player.x = GAME_WIDTH / 2;
+ player.y = GAME_HEIGHT - 500;
+ game.addChild(player);
+ // Reset game variables
+ bullets = [];
+ asteroids = [];
+ powerups = [];
+ waveNumber = 1;
+ waveDelay = 120; // 2 second delay before first wave
+ score = 0;
+ combo = 0;
+ comboTimer = 0;
+ // Update LK score
+ LK.setScore(0);
+ // Create score text
+ scoreTxt = new Text2("SCORE: 0", {
+ size: 80,
+ fill: 0xFFFFFF
+ });
+ scoreTxt.anchor.set(0, 0);
+ LK.gui.topRight.addChild(scoreTxt);
+ // Create wave text
+ waveText = new Text2("WAVE: 1", {
+ size: 80,
+ fill: 0xFFFFFF
+ });
+ waveText.anchor.set(1, 0);
+ LK.gui.topLeft.addChild(waveText);
+ // Create lives text
+ livesText = new Text2("SHIELDS: 3", {
+ size: 80,
+ fill: 0xFFFFFF
+ });
+ livesText.anchor.set(0.5, 0);
+ LK.gui.top.addChild(livesText);
+ // Create earth health text
+ earthHealthText = new Text2("EARTH: 100%", {
+ size: 80,
+ fill: 0xFFFFFF
+ });
+ earthHealthText.anchor.set(0.5, 0);
+ LK.gui.bottom.addChild(earthHealthText);
+ // Create combo text (initially invisible)
+ comboText = new Text2("COMBO: x1", {
+ size: 100,
+ fill: 0xFFFF00
+ });
+ comboText.anchor.set(0.5, 0.5);
+ comboText.x = GAME_WIDTH / 2;
+ comboText.y = GAME_HEIGHT / 2;
+ comboText.alpha = 0;
+ game.addChild(comboText);
+ // Create start text
+ startText = new Text2("TAP TO START", {
+ size: 120,
+ fill: 0xFFFFFF
+ });
+ startText.anchor.set(0.5, 0.5);
+ LK.gui.center.addChild(startText);
+ // Animate start text
+ pulseStartText();
+ gameStarted = false;
+ gameOver = false;
+ // Play music
+ LK.playMusic('gameMusic', {
+ fade: {
+ start: 0,
+ end: 0.3,
+ duration: 1000
+ }
+ });
+}
+function pulseStartText() {
+ tween(startText.scale, {
+ x: 1.1,
+ y: 1.1
+ }, {
+ duration: 800,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ tween(startText.scale, {
+ x: 1,
+ y: 1
+ }, {
+ duration: 800,
+ easing: tween.easeInOut,
+ onFinish: pulseStartText
+ });
+ }
+ });
+}
+function startGame() {
+ gameStarted = true;
+ // Hide start text
+ tween(startText, {
+ alpha: 0
+ }, {
+ duration: 500,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ LK.gui.center.removeChild(startText);
+ }
+ });
+}
+// Spawn a new wave of asteroids
+function spawnWave() {
+ var asteroidCount = Math.min(5 + waveNumber, MAX_ASTEROIDS);
+ var speed = Math.min(4 + waveNumber * 0.5, 12);
+ for (var i = 0; i < asteroidCount; i++) {
+ var size = 1;
+ var random = Math.random();
+ // Higher chance of larger asteroids in later waves
+ if (waveNumber > 3 && random > 0.7) {
+ size = 2;
+ }
+ if (waveNumber > 7 && random > 0.9) {
+ size = 3;
+ }
+ spawnAsteroid(size, speed);
+ }
+ // Show wave number
+ waveText.setText("WAVE: " + waveNumber);
+ var waveAnnouncement = new Text2("WAVE " + waveNumber, {
+ size: 150,
+ fill: 0xFFFF00
+ });
+ waveAnnouncement.anchor.set(0.5, 0.5);
+ waveAnnouncement.x = GAME_WIDTH / 2;
+ waveAnnouncement.y = GAME_HEIGHT / 2;
+ game.addChild(waveAnnouncement);
+ // Animate wave announcement
+ tween(waveAnnouncement.scale, {
+ x: 1.5,
+ y: 1.5
+ }, {
+ duration: 1000,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(waveAnnouncement, {
+ alpha: 0
+ }, {
+ duration: 500,
+ easing: tween.easeIn,
+ onFinish: function onFinish() {
+ game.removeChild(waveAnnouncement);
+ }
+ });
+ }
+ });
+ waveNumber++;
+}
+// Spawn a single asteroid
+function spawnAsteroid(size, speed) {
+ var asteroid = new Asteroid();
+ asteroid.x = Math.random() * (GAME_WIDTH - 100) + 50;
+ asteroid.y = -100;
+ asteroid.speed = speed || 4 + Math.random() * 3;
+ asteroid.setup(size || 1);
+ asteroids.push(asteroid);
+ game.addChild(asteroid);
+ return asteroid;
+}
+// Spawn a power-up
+function spawnPowerup() {
+ var powerup = new PowerUp();
+ powerup.x = Math.random() * (GAME_WIDTH - 100) + 50;
+ powerup.y = -100;
+ // Choose random power-up type
+ var random = Math.random();
+ if (random < 0.4) {
+ powerup.setup("shield");
+ } else if (random < 0.8) {
+ powerup.setup("multishot");
+ } else {
+ powerup.setup("bomb");
+ }
+ powerups.push(powerup);
+ game.addChild(powerup);
+}
+// Fire bullets from player
+function fireBullet() {
+ if (!gameStarted || gameOver) {
+ return;
+ }
+ // Play sound
+ LK.getSound('shoot').play();
+ if (player.multishot) {
+ // Fire 3 bullets in a spread
+ for (var i = -1; i <= 1; i++) {
+ var bullet = new Bullet();
+ bullet.x = player.x + i * 40;
+ bullet.y = player.y - 50;
+ bullets.push(bullet);
+ game.addChild(bullet);
+ }
+ } else {
+ // Fire single bullet
+ var bullet = new Bullet();
+ bullet.x = player.x;
+ bullet.y = player.y - 50;
+ bullets.push(bullet);
+ game.addChild(bullet);
+ }
+}
+// Check collisions between game objects
+function checkCollisions() {
+ // Check bullet-asteroid collisions
+ for (var i = bullets.length - 1; i >= 0; i--) {
+ var bullet = bullets[i];
+ if (!bullet.active) {
+ continue;
+ }
+ for (var j = asteroids.length - 1; j >= 0; j--) {
+ var asteroid = asteroids[j];
+ if (!asteroid.active) {
+ continue;
+ }
+ if (bullet.intersects(asteroid)) {
+ bullet.active = false;
+ // Asteroid hit logic
+ if (asteroid.hit()) {
+ // Asteroid destroyed
+ LK.getSound('explosion').play();
+ // Create explosion effect
+ createExplosion(asteroid.x, asteroid.y);
+ // Update score
+ updateScore(asteroid.value);
+ // Remove asteroid
+ asteroid.active = false;
+ }
+ break;
+ }
+ }
+ }
+ // Check player-asteroid collisions
+ if (!player.invulnerable) {
+ for (var j = asteroids.length - 1; j >= 0; j--) {
+ var asteroid = asteroids[j];
+ if (!asteroid.active) {
+ continue;
+ }
+ if (player.intersects(asteroid)) {
+ // Player hit
+ if (player.hit()) {
+ // Update lives display
+ livesText.setText("SHIELDS: " + player.lives);
+ // Check game over
+ if (player.lives <= 0) {
+ endGame();
+ return;
+ }
+ }
+ // Create explosion effect
+ createExplosion(asteroid.x, asteroid.y);
+ // Remove asteroid
+ asteroid.active = false;
+ // Reset combo
+ combo = 0;
+ comboTimer = 0;
+ comboText.alpha = 0;
+ }
+ }
+ }
+ // Check earth-asteroid collisions
+ for (var j = asteroids.length - 1; j >= 0; j--) {
+ var asteroid = asteroids[j];
+ if (!asteroid.active) {
+ continue;
+ }
+ if (asteroid.intersects(earth)) {
+ // Earth hit
+ var damage = asteroid.size * 5;
+ if (earth.damage(damage)) {
+ // Game over if earth health reaches 0
+ endGame();
+ return;
+ }
+ // Update earth health display
+ earthHealthText.setText("EARTH: " + earth.health + "%");
+ // Create explosion effect
+ createExplosion(asteroid.x, asteroid.y);
+ // Remove asteroid
+ asteroid.active = false;
+ // Reset combo
+ combo = 0;
+ comboTimer = 0;
+ comboText.alpha = 0;
+ }
+ }
+ // Check player-powerup collisions
+ for (var j = powerups.length - 1; j >= 0; j--) {
+ var powerup = powerups[j];
+ if (!powerup.active) {
+ continue;
+ }
+ if (player.intersects(powerup)) {
+ // Collect powerup
+ LK.getSound('powerup').play();
+ if (powerup.type === "shield") {
+ player.activateShield();
+ } else if (powerup.type === "multishot") {
+ player.activateMultishot();
+ } else if (powerup.type === "bomb") {
+ // Clear all asteroids
+ for (var k = asteroids.length - 1; k >= 0; k--) {
+ var asteroid = asteroids[k];
+ createExplosion(asteroid.x, asteroid.y);
+ asteroid.active = false;
+ updateScore(asteroid.value / 2); // Half points for bomb kills
+ }
+ // Screen flash
+ LK.effects.flashScreen(0xffff00, 500);
+ }
+ // Remove powerup
+ powerup.active = false;
+ }
+ }
+}
+// Create explosion effect
+function createExplosion(x, y) {
+ var explosion = LK.getAsset('asteroid', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: x,
+ y: y,
+ alpha: 0.8,
+ tint: 0xff9900
+ });
+ game.addChild(explosion);
+ // Animate explosion
+ tween(explosion.scale, {
+ x: 3,
+ y: 3
+ }, {
+ duration: 500,
+ easing: tween.easeOut
+ });
+ tween(explosion, {
+ alpha: 0
+ }, {
+ duration: 500,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ game.removeChild(explosion);
+ }
+ });
+}
+// Update score with combo multiplier
+function updateScore(value) {
+ // Update combo
+ combo++;
+ comboTimer = 180; // 3 seconds to maintain combo
+ // Calculate score with combo
+ var multiplier = Math.min(Math.floor(combo / 3) + 1, 5);
+ var points = value * multiplier;
+ score += points;
+ LK.setScore(score);
+ // Update score display
+ scoreTxt.setText("SCORE: " + score);
+ // Show combo text if multiplier > 1
+ if (multiplier > 1) {
+ comboText.setText("COMBO: x" + multiplier);
+ comboText.alpha = 1;
+ // Make combo text pulse
+ tween.stop(comboText.scale);
+ comboText.scale.set(1);
+ tween(comboText.scale, {
+ x: 1.5,
+ y: 1.5
+ }, {
+ duration: 200,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(comboText.scale, {
+ x: 1,
+ y: 1
+ }, {
+ duration: 200,
+ easing: tween.easeIn
+ });
+ }
+ });
+ }
+ // Show floating score text
+ var pointText = new Text2("+" + points, {
+ size: 60,
+ fill: 0xFFFF00
+ });
+ pointText.anchor.set(0.5, 0.5);
+ pointText.x = player.x;
+ pointText.y = player.y - 100;
+ game.addChild(pointText);
+ // Animate score text
+ tween(pointText, {
+ y: pointText.y - 100,
+ alpha: 0
+ }, {
+ duration: 1000,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ game.removeChild(pointText);
+ }
+ });
+}
+// End the game
+function endGame() {
+ gameOver = true;
+ // Show game over text
+ var gameOverText = new Text2("GAME OVER", {
+ size: 200,
+ fill: 0xFF0000
+ });
+ gameOverText.anchor.set(0.5, 0.5);
+ LK.gui.center.addChild(gameOverText);
+ // Animate game over text
+ tween(gameOverText.scale, {
+ x: 1.5,
+ y: 1.5
+ }, {
+ duration: 1000,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ // Show final score
+ var finalScoreText = new Text2("FINAL SCORE: " + score, {
+ size: 100,
+ fill: 0xFFFFFF
+ });
+ finalScoreText.anchor.set(0.5, 0.5);
+ finalScoreText.y = 150;
+ LK.gui.center.addChild(finalScoreText);
+ // Show game over after a delay
+ LK.setTimeout(function () {
+ LK.showGameOver();
+ }, 3000);
+ }
+ });
+ // Stop music with fade out
+ LK.playMusic('gameMusic', {
+ fade: {
+ start: 0.3,
+ end: 0,
+ duration: 2000
+ }
+ });
+}
+// Handle drag movement for player ship
+function handleMove(x, y, obj) {
+ if (dragMode && gameStarted && !gameOver) {
+ player.x = x;
+ // Keep player within bounds
+ if (player.x < 75) {
+ player.x = 75;
+ }
+ if (player.x > GAME_WIDTH - 75) {
+ player.x = GAME_WIDTH - 75;
+ }
+ }
+}
+// Initialize game
+initGame();
+// Game mouse/touch events
+game.down = function (x, y, obj) {
+ if (!gameStarted) {
+ startGame();
+ return;
+ }
+ if (gameOver) {
+ return;
+ }
+ dragMode = true;
+ player.x = x;
+ // Keep player within bounds
+ if (player.x < 75) {
+ player.x = 75;
+ }
+ if (player.x > GAME_WIDTH - 75) {
+ player.x = GAME_WIDTH - 75;
+ }
+ // Fire bullet on touch
+ fireBullet();
+};
+game.up = function (x, y, obj) {
+ dragMode = false;
+};
+game.move = handleMove;
+// Game update loop
+game.update = function () {
+ if (!gameStarted) {
+ return;
+ }
+ if (gameOver) {
+ return;
+ }
+ // Update player
+ player.update();
+ // Fire automatically every 15 frames (4 times per second)
+ if (LK.ticks % 15 === 0) {
+ fireBullet();
+ }
+ // Update combo timer
+ if (combo > 0) {
+ comboTimer--;
+ if (comboTimer <= 0) {
+ combo = 0;
+ tween(comboText, {
+ alpha: 0
+ }, {
+ duration: 500,
+ easing: tween.easeOut
+ });
+ }
+ }
+ // Update wave delay
+ if (waveDelay > 0) {
+ waveDelay--;
+ if (waveDelay <= 0) {
+ spawnWave();
+ waveDelay = WAVE_DELAY;
+ }
+ }
+ // Random asteroid spawn between waves (with increasing chance based on wave)
+ if (asteroids.length < MAX_ASTEROIDS && Math.random() < ASTEROID_SPAWN_CHANCE * (1 + waveNumber * 0.1)) {
+ spawnAsteroid();
+ }
+ // Random powerup spawn
+ if (Math.random() < POWERUP_CHANCE) {
+ spawnPowerup();
+ }
+ // Update bullets
+ for (var i = bullets.length - 1; i >= 0; i--) {
+ bullets[i].update();
+ if (!bullets[i].active) {
+ game.removeChild(bullets[i]);
+ bullets.splice(i, 1);
+ }
+ }
+ // Update asteroids
+ for (var i = asteroids.length - 1; i >= 0; i--) {
+ asteroids[i].update();
+ if (!asteroids[i].active) {
+ game.removeChild(asteroids[i]);
+ asteroids.splice(i, 1);
+ }
+ }
+ // Update powerups
+ for (var i = powerups.length - 1; i >= 0; i--) {
+ powerups[i].update();
+ if (!powerups[i].active) {
+ game.removeChild(powerups[i]);
+ powerups.splice(i, 1);
+ }
+ }
+ // Check collisions
+ checkCollisions();
+};
\ No newline at end of file
Earth. 2d
Asteroid. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Spaceship. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Space ship plasma bullet. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows