/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0, shieldLevel: 1, laserLevel: 1, thrusterLevel: 1 }); /**** * Classes ****/ var Asteroid = Container.expand(function () { var self = Container.call(this); // Initialize with random size self.size = Math.random() * 0.5 + 0.8; // Between 0.8 and 1.3 self.health = Math.ceil(self.size * 3); self.initialHealth = self.health; self.speedX = (Math.random() - 0.5) * 4; self.speedY = Math.random() * 3 + 2; self.rotationSpeed = (Math.random() - 0.5) * 0.05; self.value = Math.ceil(self.size * 10); // Points value self.resourceValue = Math.ceil(self.size * 2); // Resource value var asteroidGraphic = self.attachAsset('asteroid', { anchorX: 0.5, anchorY: 0.5, scaleX: self.size, scaleY: self.size }); self.takeDamage = function (amount) { self.health -= amount; // Visual feedback LK.effects.flashObject(self, 0xffffff, 200); // Break apart if (self.health <= 0) { self["break"](); return true; } // Change appearance based on damage var healthPercent = self.health / self.initialHealth; asteroidGraphic.alpha = 0.5 + healthPercent * 0.5; return false; }; self["break"] = function () { // Create minerals var mineralCount = Math.ceil(self.size * 2); for (var i = 0; i < mineralCount; i++) { var mineral = new Mineral(); mineral.x = self.x + (Math.random() - 0.5) * 50; mineral.y = self.y + (Math.random() - 0.5) * 50; minerals.push(mineral); game.addChild(mineral); } // Add score addScore(self.value); // Mark for removal self.toBeRemoved = true; }; self.update = function () { // Move asteroid self.x += self.speedX; self.y += self.speedY; // Rotate asteroid asteroidGraphic.rotation += self.rotationSpeed; // Wrap around screen edges horizontally if (self.x < -100) { self.x = 2148; } if (self.x > 2148) { self.x = -100; } // Remove if off bottom of screen if (self.y > 2832) { self.toBeRemoved = true; } }; return self; }); var ExplosiveAsteroid = Asteroid.expand(function () { var self = Asteroid.call(this); // Override the asteroid graphic with an explosive one self.removeChildren(); var asteroidGraphic = self.attachAsset('explosiveAsteroid', { anchorX: 0.5, anchorY: 0.5, scaleX: self.size, scaleY: self.size }); // Make it pulse function pulse() { tween(asteroidGraphic, { alpha: 0.6 }, { duration: 500, onFinish: function onFinish() { tween(asteroidGraphic, { alpha: 1 }, { duration: 500, onFinish: pulse }); } }); } pulse(); // Override break function to create explosion var originalBreak = self["break"]; self["break"] = function () { // Create explosion var explosion = new Explosion(); explosion.x = self.x; explosion.y = self.y; explosions.push(explosion); game.addChild(explosion); // Original break functionality originalBreak(); }; return self; }); var Explosion = Container.expand(function () { var self = Container.call(this); var explosionGraphic = self.attachAsset('explosion', { anchorX: 0.5, anchorY: 0.5, alpha: 0.9 }); self.radius = 50; self.damage = 40; self.lifetime = 500; // milliseconds self.born = Date.now(); // Play explosion sound LK.getSound('explosion').play(); // Animate explosion tween(explosionGraphic, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: self.lifetime, onFinish: function onFinish() { self.toBeRemoved = true; } }); self.update = function () { self.radius = 50 + (Date.now() - self.born) / self.lifetime * 100; }; return self; }); var GravitationalAnomaly = Container.expand(function () { var self = Container.call(this); var anomalyGraphic = self.attachAsset('anomaly', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); self.radius = 150; self.strength = 0.5; self.update = function () { // Visual effect or animation can be added here }; return self; }); var Laser = Container.expand(function () { var self = Container.call(this); var laserGraphic = self.attachAsset('laser', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 15; self.power = 1; // Will be set by ship when fired self.update = function () { self.y -= self.speed; // Destroy when off screen if (self.y < -100) { self.toBeRemoved = true; } }; return self; }); var Mineral = Container.expand(function () { var self = Container.call(this); var mineralGraphic = self.attachAsset('mineral', { anchorX: 0.5, anchorY: 0.5 }); self.speedX = (Math.random() - 0.5) * 2; self.speedY = Math.random() * 2 + 1; self.value = Math.floor(Math.random() * 3) + 1; self.rotationSpeed = (Math.random() - 0.5) * 0.1; // Different colors based on value if (self.value === 1) { mineralGraphic.tint = 0x95a5a6; // Iron (gray) } else if (self.value === 2) { mineralGraphic.tint = 0xf1c40f; // Gold (yellow) } else { mineralGraphic.tint = 0x1abc9c; // Platinum (teal) } self.update = function () { // Move mineral self.x += self.speedX; self.y += self.speedY; // Rotate mineral mineralGraphic.rotation += self.rotationSpeed; // Wrap around screen edges horizontally if (self.x < -50) { self.x = 2098; } if (self.x > 2098) { self.x = -50; } // Remove if off bottom of screen if (self.y > 2832) { self.toBeRemoved = true; } }; return self; }); var Ship = Container.expand(function () { var self = Container.call(this); // Ship attributes self.maxShields = 100; self.shields = self.maxShields; self.speed = 5; self.lastFired = 0; self.fireRate = 500; // milliseconds between shots self.laserPower = 1; self.invulnerable = false; // Create ship body var shipBody = self.attachAsset('ship', { anchorX: 0.5, anchorY: 0.5 }); // Create shield indicator var shieldIndicator = self.attachAsset('shield', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 }); // Method to update shield appearance self.updateShieldDisplay = function () { var shieldPercent = self.shields / self.maxShields; shieldIndicator.alpha = 0.1 + shieldPercent * 0.4; if (self.shields < 30) { shieldIndicator.tint = 0xff0000; // Red when low } else if (self.shields < 60) { shieldIndicator.tint = 0xffff00; // Yellow when medium } else { shieldIndicator.tint = 0x3498db; // Blue when high } }; // Method to take damage self.takeDamage = function (amount) { if (self.invulnerable) { return; } self.shields -= amount; LK.getSound('damage').play(); // Visual feedback LK.effects.flashObject(self, 0xff0000, 500); // Make invulnerable briefly self.invulnerable = true; LK.setTimeout(function () { self.invulnerable = false; }, 1000); self.updateShieldDisplay(); if (self.shields <= 0) { gameOver(); } }; // Method to fire laser self.fireLaser = function () { var now = Date.now(); if (now - self.lastFired < self.fireRate) { return; } self.lastFired = now; var laser = new Laser(); laser.x = self.x; laser.y = self.y - 50; laser.power = self.laserPower; lasers.push(laser); game.addChild(laser); LK.getSound('laser').play(); }; // Init shield display self.updateShieldDisplay(); return self; }); var UpgradeCrate = Container.expand(function () { var self = Container.call(this); var crateGraphic = self.attachAsset('upgradeCrate', { anchorX: 0.5, anchorY: 0.5 }); self.speedY = 3; self.pulseAmount = 0; // Pulse effect function pulse() { tween(crateGraphic, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.sinOut, onFinish: function onFinish() { tween(crateGraphic, { scaleX: 1, scaleY: 1 }, { duration: 800, easing: tween.sinIn, onFinish: pulse }); } }); } pulse(); self.update = function () { // Move crate self.y += self.speedY; // Remove if off bottom of screen if (self.y > 2832) { self.toBeRemoved = true; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game variables var score = 0; var resources = 0; var level = 1; var ship; var lasers = []; var asteroids = []; var explosiveAsteroids = []; var minerals = []; var explosions = []; var upgradeCrates = []; var lastAsteroidTime = 0; var gravitationalAnomalies = []; var asteroidSpawnRate = 1500; // milliseconds between asteroid spawns var nextUpgradeScore = 500; var gameActive = true; var dragOffset = { x: 0, y: 0 }; var dragActive = false; // Initialize background game.setBackgroundColor(0x000033); // Create UI elements var scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0, 0); LK.gui.topRight.addChild(scoreText); scoreText.x = -300; scoreText.y = 20; var resourceText = new Text2('Resources: 0', { size: 60, fill: 0xFFFFFF }); resourceText.anchor.set(0, 0); LK.gui.topRight.addChild(resourceText); resourceText.x = -300; resourceText.y = 90; var levelText = new Text2('Level: 1', { size: 60, fill: 0xFFFFFF }); levelText.anchor.set(0, 0); LK.gui.topRight.addChild(levelText); levelText.x = -300; levelText.y = 160; var shieldText = new Text2('Shield: 100%', { size: 60, fill: 0xFFFFFF }); shieldText.anchor.set(0, 0); LK.gui.bottom.addChild(shieldText); shieldText.x = -650; shieldText.y = -80; // Initialize ship ship = new Ship(); ship.x = 2048 / 2; ship.y = 2500; game.addChild(ship); // Load saved upgrades loadUpgrades(); // Start background music LK.playMusic('gameMusic', { fade: { start: 0, end: 0.4, duration: 1000 } }); // Game functions function addScore(points) { score += points; scoreText.setText('Score: ' + score); // Check if player reached next upgrade threshold if (score >= nextUpgradeScore) { spawnUpgradeCrate(); nextUpgradeScore += 500; } // Check for level increase var newLevel = Math.floor(score / 1000) + 1; if (newLevel > level) { level = newLevel; levelText.setText('Level: ' + level); // Increase difficulty asteroidSpawnRate = Math.max(300, 1500 - level * 100); } } function addResource(amount) { resources += amount; resourceText.setText('Resources: ' + resources); // Save high score if better than previous if (score > storage.highScore) { storage.highScore = score; } } function spawnAsteroid() { // Decide whether to spawn regular or explosive asteroid var isExplosive = Math.random() < 0.2; var asteroid; if (isExplosive) { asteroid = new ExplosiveAsteroid(); explosiveAsteroids.push(asteroid); } else { asteroid = new Asteroid(); asteroids.push(asteroid); } // Position at random location at top of screen asteroid.x = Math.random() * 2048; asteroid.y = -100; // Add to game game.addChild(asteroid); } function spawnUpgradeCrate() { var crate = new UpgradeCrate(); crate.x = Math.random() * (2048 - 200) + 100; // Keep away from edges crate.y = -100; upgradeCrates.push(crate); game.addChild(crate); } function applyUpgrade() { // Show upgrade options in a future version // For now, just upgrade shields if (resources >= 10) { resources -= 10; resourceText.setText('Resources: ' + resources); // Upgrade a random system var system = Math.floor(Math.random() * 3); if (system === 0 && storage.shieldLevel < 5) { storage.shieldLevel++; ship.maxShields = 100 + (storage.shieldLevel - 1) * 25; ship.shields = ship.maxShields; shieldText.setText('Shield: ' + Math.floor(ship.shields) + '%'); ship.updateShieldDisplay(); } else if (system === 1 && storage.laserLevel < 5) { storage.laserLevel++; ship.laserPower = storage.laserLevel; ship.fireRate = 500 - (storage.laserLevel - 1) * 50; } else if (storage.thrusterLevel < 5) { storage.thrusterLevel++; ship.speed = 5 + (storage.thrusterLevel - 1); } LK.getSound('upgrade').play(); // Visual feedback LK.effects.flashObject(ship, 0x9b59b6, 1000); } } function loadUpgrades() { // Apply saved upgrade levels ship.maxShields = 100 + (storage.shieldLevel - 1) * 25; ship.shields = ship.maxShields; ship.laserPower = storage.laserLevel; ship.fireRate = 500 - (storage.laserLevel - 1) * 50; ship.speed = 5 + (storage.thrusterLevel - 1); shieldText.setText('Shield: ' + Math.floor(ship.shields) + '%'); ship.updateShieldDisplay(); } function gameOver() { gameActive = false; LK.effects.flashScreen(0xff0000, 1000); LK.setTimeout(function () { LK.showGameOver(); }, 1000); } // Input handlers game.down = function (x, y, obj) { if (!gameActive) { return; } // Start dragging the ship dragOffset.x = ship.x - x; dragOffset.y = ship.y - y; dragActive = true; // Fire laser on tap ship.fireLaser(); }; game.move = function (x, y, obj) { if (!gameActive || !dragActive) { return; } // Move ship with drag, keeping it on screen ship.x = Math.min(Math.max(x + dragOffset.x, 50), 2048 - 50); ship.y = Math.min(Math.max(y + dragOffset.y, 50), 2732 - 50); }; game.up = function (x, y, obj) { dragActive = false; }; // Game loop game.update = function () { if (!gameActive) { return; } // Spawn new asteroids var now = Date.now(); if (now - lastAsteroidTime > asteroidSpawnRate) { spawnAsteroid(); lastAsteroidTime = now; } // Randomly spawn gravitational anomalies if (Math.random() < 0.001) { // Adjust probability as needed var anomaly = new GravitationalAnomaly(); anomaly.x = Math.random() * 2048; anomaly.y = Math.random() * 2732; gravitationalAnomalies.push(anomaly); game.addChild(anomaly); } // Update UI shieldText.setText('Shield: ' + Math.floor(ship.shields) + '%'); // Update and check lasers for (var i = lasers.length - 1; i >= 0; i--) { var laser = lasers[i]; if (laser.toBeRemoved) { game.removeChild(laser); lasers.splice(i, 1); continue; } // Check laser collisions with asteroids for (var j = asteroids.length - 1; j >= 0; j--) { var asteroid = asteroids[j]; if (laser.intersects(asteroid)) { if (asteroid.takeDamage(laser.power)) { // Asteroid was destroyed game.removeChild(asteroid); asteroids.splice(j, 1); } // Remove laser on hit laser.toBeRemoved = true; break; } } // Check laser collisions with explosive asteroids for (var j = explosiveAsteroids.length - 1; j >= 0; j--) { var expAsteroid = explosiveAsteroids[j]; if (laser.intersects(expAsteroid)) { if (expAsteroid.takeDamage(laser.power)) { // Asteroid was destroyed game.removeChild(expAsteroid); explosiveAsteroids.splice(j, 1); } // Remove laser on hit laser.toBeRemoved = true; break; } } } // Update and check minerals for (var i = minerals.length - 1; i >= 0; i--) { var mineral = minerals[i]; if (mineral.toBeRemoved) { game.removeChild(mineral); minerals.splice(i, 1); continue; } // Check if ship collects mineral if (ship.intersects(mineral)) { addResource(mineral.value); LK.getSound('collect').play(); mineral.toBeRemoved = true; // Visual feedback LK.effects.flashObject(ship, 0x2ecc71, 200); } } // Update and check asteroids for (var i = asteroids.length - 1; i >= 0; i--) { var asteroid = asteroids[i]; if (asteroid.toBeRemoved) { game.removeChild(asteroid); asteroids.splice(i, 1); continue; } // Check collision with ship if (ship.intersects(asteroid)) { ship.takeDamage(10 + level); asteroid["break"](); game.removeChild(asteroid); asteroids.splice(i, 1); } } // Update and check explosive asteroids for (var i = explosiveAsteroids.length - 1; i >= 0; i--) { var expAsteroid = explosiveAsteroids[i]; if (expAsteroid.toBeRemoved) { game.removeChild(expAsteroid); explosiveAsteroids.splice(i, 1); continue; } // Check collision with ship if (ship.intersects(expAsteroid)) { ship.takeDamage(20 + level * 2); expAsteroid["break"](); game.removeChild(expAsteroid); explosiveAsteroids.splice(i, 1); } } // Update and check explosions for (var i = explosions.length - 1; i >= 0; i--) { var explosion = explosions[i]; if (explosion.toBeRemoved) { game.removeChild(explosion); explosions.splice(i, 1); continue; } // Check if ship is caught in explosion var dx = ship.x - explosion.x; var dy = ship.y - explosion.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < explosion.radius + 50) { // Add ship radius // Damage diminishes with distance var damageMultiplier = 1 - distance / (explosion.radius + 50); ship.takeDamage(explosion.damage * damageMultiplier); } } // Update and check gravitational anomalies for (var i = gravitationalAnomalies.length - 1; i >= 0; i--) { var anomaly = gravitationalAnomalies[i]; if (anomaly.toBeRemoved) { game.removeChild(anomaly); gravitationalAnomalies.splice(i, 1); continue; } // Check if ship is affected by anomaly var dx = ship.x - anomaly.x; var dy = ship.y - anomaly.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < anomaly.radius) { // Apply gravitational pull var pullStrength = anomaly.strength * (1 - distance / anomaly.radius); ship.x += dx * pullStrength; ship.y += dy * pullStrength; } } // Update and check upgrade crates for (var i = upgradeCrates.length - 1; i >= 0; i--) { var crate = upgradeCrates[i]; if (crate.toBeRemoved) { game.removeChild(crate); upgradeCrates.splice(i, 1); continue; } // Check if ship collects upgrade if (ship.intersects(crate)) { applyUpgrade(); crate.toBeRemoved = true; } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
shieldLevel: 1,
laserLevel: 1,
thrusterLevel: 1
});
/****
* Classes
****/
var Asteroid = Container.expand(function () {
var self = Container.call(this);
// Initialize with random size
self.size = Math.random() * 0.5 + 0.8; // Between 0.8 and 1.3
self.health = Math.ceil(self.size * 3);
self.initialHealth = self.health;
self.speedX = (Math.random() - 0.5) * 4;
self.speedY = Math.random() * 3 + 2;
self.rotationSpeed = (Math.random() - 0.5) * 0.05;
self.value = Math.ceil(self.size * 10); // Points value
self.resourceValue = Math.ceil(self.size * 2); // Resource value
var asteroidGraphic = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: self.size,
scaleY: self.size
});
self.takeDamage = function (amount) {
self.health -= amount;
// Visual feedback
LK.effects.flashObject(self, 0xffffff, 200);
// Break apart
if (self.health <= 0) {
self["break"]();
return true;
}
// Change appearance based on damage
var healthPercent = self.health / self.initialHealth;
asteroidGraphic.alpha = 0.5 + healthPercent * 0.5;
return false;
};
self["break"] = function () {
// Create minerals
var mineralCount = Math.ceil(self.size * 2);
for (var i = 0; i < mineralCount; i++) {
var mineral = new Mineral();
mineral.x = self.x + (Math.random() - 0.5) * 50;
mineral.y = self.y + (Math.random() - 0.5) * 50;
minerals.push(mineral);
game.addChild(mineral);
}
// Add score
addScore(self.value);
// Mark for removal
self.toBeRemoved = true;
};
self.update = function () {
// Move asteroid
self.x += self.speedX;
self.y += self.speedY;
// Rotate asteroid
asteroidGraphic.rotation += self.rotationSpeed;
// Wrap around screen edges horizontally
if (self.x < -100) {
self.x = 2148;
}
if (self.x > 2148) {
self.x = -100;
}
// Remove if off bottom of screen
if (self.y > 2832) {
self.toBeRemoved = true;
}
};
return self;
});
var ExplosiveAsteroid = Asteroid.expand(function () {
var self = Asteroid.call(this);
// Override the asteroid graphic with an explosive one
self.removeChildren();
var asteroidGraphic = self.attachAsset('explosiveAsteroid', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: self.size,
scaleY: self.size
});
// Make it pulse
function pulse() {
tween(asteroidGraphic, {
alpha: 0.6
}, {
duration: 500,
onFinish: function onFinish() {
tween(asteroidGraphic, {
alpha: 1
}, {
duration: 500,
onFinish: pulse
});
}
});
}
pulse();
// Override break function to create explosion
var originalBreak = self["break"];
self["break"] = function () {
// Create explosion
var explosion = new Explosion();
explosion.x = self.x;
explosion.y = self.y;
explosions.push(explosion);
game.addChild(explosion);
// Original break functionality
originalBreak();
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphic = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9
});
self.radius = 50;
self.damage = 40;
self.lifetime = 500; // milliseconds
self.born = Date.now();
// Play explosion sound
LK.getSound('explosion').play();
// Animate explosion
tween(explosionGraphic, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: self.lifetime,
onFinish: function onFinish() {
self.toBeRemoved = true;
}
});
self.update = function () {
self.radius = 50 + (Date.now() - self.born) / self.lifetime * 100;
};
return self;
});
var GravitationalAnomaly = Container.expand(function () {
var self = Container.call(this);
var anomalyGraphic = self.attachAsset('anomaly', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.radius = 150;
self.strength = 0.5;
self.update = function () {
// Visual effect or animation can be added here
};
return self;
});
var Laser = Container.expand(function () {
var self = Container.call(this);
var laserGraphic = self.attachAsset('laser', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.power = 1; // Will be set by ship when fired
self.update = function () {
self.y -= self.speed;
// Destroy when off screen
if (self.y < -100) {
self.toBeRemoved = true;
}
};
return self;
});
var Mineral = Container.expand(function () {
var self = Container.call(this);
var mineralGraphic = self.attachAsset('mineral', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = (Math.random() - 0.5) * 2;
self.speedY = Math.random() * 2 + 1;
self.value = Math.floor(Math.random() * 3) + 1;
self.rotationSpeed = (Math.random() - 0.5) * 0.1;
// Different colors based on value
if (self.value === 1) {
mineralGraphic.tint = 0x95a5a6; // Iron (gray)
} else if (self.value === 2) {
mineralGraphic.tint = 0xf1c40f; // Gold (yellow)
} else {
mineralGraphic.tint = 0x1abc9c; // Platinum (teal)
}
self.update = function () {
// Move mineral
self.x += self.speedX;
self.y += self.speedY;
// Rotate mineral
mineralGraphic.rotation += self.rotationSpeed;
// Wrap around screen edges horizontally
if (self.x < -50) {
self.x = 2098;
}
if (self.x > 2098) {
self.x = -50;
}
// Remove if off bottom of screen
if (self.y > 2832) {
self.toBeRemoved = true;
}
};
return self;
});
var Ship = Container.expand(function () {
var self = Container.call(this);
// Ship attributes
self.maxShields = 100;
self.shields = self.maxShields;
self.speed = 5;
self.lastFired = 0;
self.fireRate = 500; // milliseconds between shots
self.laserPower = 1;
self.invulnerable = false;
// Create ship body
var shipBody = self.attachAsset('ship', {
anchorX: 0.5,
anchorY: 0.5
});
// Create shield indicator
var shieldIndicator = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
// Method to update shield appearance
self.updateShieldDisplay = function () {
var shieldPercent = self.shields / self.maxShields;
shieldIndicator.alpha = 0.1 + shieldPercent * 0.4;
if (self.shields < 30) {
shieldIndicator.tint = 0xff0000; // Red when low
} else if (self.shields < 60) {
shieldIndicator.tint = 0xffff00; // Yellow when medium
} else {
shieldIndicator.tint = 0x3498db; // Blue when high
}
};
// Method to take damage
self.takeDamage = function (amount) {
if (self.invulnerable) {
return;
}
self.shields -= amount;
LK.getSound('damage').play();
// Visual feedback
LK.effects.flashObject(self, 0xff0000, 500);
// Make invulnerable briefly
self.invulnerable = true;
LK.setTimeout(function () {
self.invulnerable = false;
}, 1000);
self.updateShieldDisplay();
if (self.shields <= 0) {
gameOver();
}
};
// Method to fire laser
self.fireLaser = function () {
var now = Date.now();
if (now - self.lastFired < self.fireRate) {
return;
}
self.lastFired = now;
var laser = new Laser();
laser.x = self.x;
laser.y = self.y - 50;
laser.power = self.laserPower;
lasers.push(laser);
game.addChild(laser);
LK.getSound('laser').play();
};
// Init shield display
self.updateShieldDisplay();
return self;
});
var UpgradeCrate = Container.expand(function () {
var self = Container.call(this);
var crateGraphic = self.attachAsset('upgradeCrate', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedY = 3;
self.pulseAmount = 0;
// Pulse effect
function pulse() {
tween(crateGraphic, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.sinOut,
onFinish: function onFinish() {
tween(crateGraphic, {
scaleX: 1,
scaleY: 1
}, {
duration: 800,
easing: tween.sinIn,
onFinish: pulse
});
}
});
}
pulse();
self.update = function () {
// Move crate
self.y += self.speedY;
// Remove if off bottom of screen
if (self.y > 2832) {
self.toBeRemoved = true;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game variables
var score = 0;
var resources = 0;
var level = 1;
var ship;
var lasers = [];
var asteroids = [];
var explosiveAsteroids = [];
var minerals = [];
var explosions = [];
var upgradeCrates = [];
var lastAsteroidTime = 0;
var gravitationalAnomalies = [];
var asteroidSpawnRate = 1500; // milliseconds between asteroid spawns
var nextUpgradeScore = 500;
var gameActive = true;
var dragOffset = {
x: 0,
y: 0
};
var dragActive = false;
// Initialize background
game.setBackgroundColor(0x000033);
// Create UI elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreText);
scoreText.x = -300;
scoreText.y = 20;
var resourceText = new Text2('Resources: 0', {
size: 60,
fill: 0xFFFFFF
});
resourceText.anchor.set(0, 0);
LK.gui.topRight.addChild(resourceText);
resourceText.x = -300;
resourceText.y = 90;
var levelText = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(0, 0);
LK.gui.topRight.addChild(levelText);
levelText.x = -300;
levelText.y = 160;
var shieldText = new Text2('Shield: 100%', {
size: 60,
fill: 0xFFFFFF
});
shieldText.anchor.set(0, 0);
LK.gui.bottom.addChild(shieldText);
shieldText.x = -650;
shieldText.y = -80;
// Initialize ship
ship = new Ship();
ship.x = 2048 / 2;
ship.y = 2500;
game.addChild(ship);
// Load saved upgrades
loadUpgrades();
// Start background music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.4,
duration: 1000
}
});
// Game functions
function addScore(points) {
score += points;
scoreText.setText('Score: ' + score);
// Check if player reached next upgrade threshold
if (score >= nextUpgradeScore) {
spawnUpgradeCrate();
nextUpgradeScore += 500;
}
// Check for level increase
var newLevel = Math.floor(score / 1000) + 1;
if (newLevel > level) {
level = newLevel;
levelText.setText('Level: ' + level);
// Increase difficulty
asteroidSpawnRate = Math.max(300, 1500 - level * 100);
}
}
function addResource(amount) {
resources += amount;
resourceText.setText('Resources: ' + resources);
// Save high score if better than previous
if (score > storage.highScore) {
storage.highScore = score;
}
}
function spawnAsteroid() {
// Decide whether to spawn regular or explosive asteroid
var isExplosive = Math.random() < 0.2;
var asteroid;
if (isExplosive) {
asteroid = new ExplosiveAsteroid();
explosiveAsteroids.push(asteroid);
} else {
asteroid = new Asteroid();
asteroids.push(asteroid);
}
// Position at random location at top of screen
asteroid.x = Math.random() * 2048;
asteroid.y = -100;
// Add to game
game.addChild(asteroid);
}
function spawnUpgradeCrate() {
var crate = new UpgradeCrate();
crate.x = Math.random() * (2048 - 200) + 100; // Keep away from edges
crate.y = -100;
upgradeCrates.push(crate);
game.addChild(crate);
}
function applyUpgrade() {
// Show upgrade options in a future version
// For now, just upgrade shields
if (resources >= 10) {
resources -= 10;
resourceText.setText('Resources: ' + resources);
// Upgrade a random system
var system = Math.floor(Math.random() * 3);
if (system === 0 && storage.shieldLevel < 5) {
storage.shieldLevel++;
ship.maxShields = 100 + (storage.shieldLevel - 1) * 25;
ship.shields = ship.maxShields;
shieldText.setText('Shield: ' + Math.floor(ship.shields) + '%');
ship.updateShieldDisplay();
} else if (system === 1 && storage.laserLevel < 5) {
storage.laserLevel++;
ship.laserPower = storage.laserLevel;
ship.fireRate = 500 - (storage.laserLevel - 1) * 50;
} else if (storage.thrusterLevel < 5) {
storage.thrusterLevel++;
ship.speed = 5 + (storage.thrusterLevel - 1);
}
LK.getSound('upgrade').play();
// Visual feedback
LK.effects.flashObject(ship, 0x9b59b6, 1000);
}
}
function loadUpgrades() {
// Apply saved upgrade levels
ship.maxShields = 100 + (storage.shieldLevel - 1) * 25;
ship.shields = ship.maxShields;
ship.laserPower = storage.laserLevel;
ship.fireRate = 500 - (storage.laserLevel - 1) * 50;
ship.speed = 5 + (storage.thrusterLevel - 1);
shieldText.setText('Shield: ' + Math.floor(ship.shields) + '%');
ship.updateShieldDisplay();
}
function gameOver() {
gameActive = false;
LK.effects.flashScreen(0xff0000, 1000);
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
// Input handlers
game.down = function (x, y, obj) {
if (!gameActive) {
return;
}
// Start dragging the ship
dragOffset.x = ship.x - x;
dragOffset.y = ship.y - y;
dragActive = true;
// Fire laser on tap
ship.fireLaser();
};
game.move = function (x, y, obj) {
if (!gameActive || !dragActive) {
return;
}
// Move ship with drag, keeping it on screen
ship.x = Math.min(Math.max(x + dragOffset.x, 50), 2048 - 50);
ship.y = Math.min(Math.max(y + dragOffset.y, 50), 2732 - 50);
};
game.up = function (x, y, obj) {
dragActive = false;
};
// Game loop
game.update = function () {
if (!gameActive) {
return;
}
// Spawn new asteroids
var now = Date.now();
if (now - lastAsteroidTime > asteroidSpawnRate) {
spawnAsteroid();
lastAsteroidTime = now;
}
// Randomly spawn gravitational anomalies
if (Math.random() < 0.001) {
// Adjust probability as needed
var anomaly = new GravitationalAnomaly();
anomaly.x = Math.random() * 2048;
anomaly.y = Math.random() * 2732;
gravitationalAnomalies.push(anomaly);
game.addChild(anomaly);
}
// Update UI
shieldText.setText('Shield: ' + Math.floor(ship.shields) + '%');
// Update and check lasers
for (var i = lasers.length - 1; i >= 0; i--) {
var laser = lasers[i];
if (laser.toBeRemoved) {
game.removeChild(laser);
lasers.splice(i, 1);
continue;
}
// Check laser collisions with asteroids
for (var j = asteroids.length - 1; j >= 0; j--) {
var asteroid = asteroids[j];
if (laser.intersects(asteroid)) {
if (asteroid.takeDamage(laser.power)) {
// Asteroid was destroyed
game.removeChild(asteroid);
asteroids.splice(j, 1);
}
// Remove laser on hit
laser.toBeRemoved = true;
break;
}
}
// Check laser collisions with explosive asteroids
for (var j = explosiveAsteroids.length - 1; j >= 0; j--) {
var expAsteroid = explosiveAsteroids[j];
if (laser.intersects(expAsteroid)) {
if (expAsteroid.takeDamage(laser.power)) {
// Asteroid was destroyed
game.removeChild(expAsteroid);
explosiveAsteroids.splice(j, 1);
}
// Remove laser on hit
laser.toBeRemoved = true;
break;
}
}
}
// Update and check minerals
for (var i = minerals.length - 1; i >= 0; i--) {
var mineral = minerals[i];
if (mineral.toBeRemoved) {
game.removeChild(mineral);
minerals.splice(i, 1);
continue;
}
// Check if ship collects mineral
if (ship.intersects(mineral)) {
addResource(mineral.value);
LK.getSound('collect').play();
mineral.toBeRemoved = true;
// Visual feedback
LK.effects.flashObject(ship, 0x2ecc71, 200);
}
}
// Update and check asteroids
for (var i = asteroids.length - 1; i >= 0; i--) {
var asteroid = asteroids[i];
if (asteroid.toBeRemoved) {
game.removeChild(asteroid);
asteroids.splice(i, 1);
continue;
}
// Check collision with ship
if (ship.intersects(asteroid)) {
ship.takeDamage(10 + level);
asteroid["break"]();
game.removeChild(asteroid);
asteroids.splice(i, 1);
}
}
// Update and check explosive asteroids
for (var i = explosiveAsteroids.length - 1; i >= 0; i--) {
var expAsteroid = explosiveAsteroids[i];
if (expAsteroid.toBeRemoved) {
game.removeChild(expAsteroid);
explosiveAsteroids.splice(i, 1);
continue;
}
// Check collision with ship
if (ship.intersects(expAsteroid)) {
ship.takeDamage(20 + level * 2);
expAsteroid["break"]();
game.removeChild(expAsteroid);
explosiveAsteroids.splice(i, 1);
}
}
// Update and check explosions
for (var i = explosions.length - 1; i >= 0; i--) {
var explosion = explosions[i];
if (explosion.toBeRemoved) {
game.removeChild(explosion);
explosions.splice(i, 1);
continue;
}
// Check if ship is caught in explosion
var dx = ship.x - explosion.x;
var dy = ship.y - explosion.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosion.radius + 50) {
// Add ship radius
// Damage diminishes with distance
var damageMultiplier = 1 - distance / (explosion.radius + 50);
ship.takeDamage(explosion.damage * damageMultiplier);
}
}
// Update and check gravitational anomalies
for (var i = gravitationalAnomalies.length - 1; i >= 0; i--) {
var anomaly = gravitationalAnomalies[i];
if (anomaly.toBeRemoved) {
game.removeChild(anomaly);
gravitationalAnomalies.splice(i, 1);
continue;
}
// Check if ship is affected by anomaly
var dx = ship.x - anomaly.x;
var dy = ship.y - anomaly.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < anomaly.radius) {
// Apply gravitational pull
var pullStrength = anomaly.strength * (1 - distance / anomaly.radius);
ship.x += dx * pullStrength;
ship.y += dy * pullStrength;
}
}
// Update and check upgrade crates
for (var i = upgradeCrates.length - 1; i >= 0; i--) {
var crate = upgradeCrates[i];
if (crate.toBeRemoved) {
game.removeChild(crate);
upgradeCrates.splice(i, 1);
continue;
}
// Check if ship collects upgrade
if (ship.intersects(crate)) {
applyUpgrade();
crate.toBeRemoved = true;
}
}
};