/****
* 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