/**** * 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 = 3; 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 = Math.min(speed || 2, 2); 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(); };
/****
* 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 = 3;
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 = Math.min(speed || 2, 2);
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();
};
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