/****
* 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: 3.0,
scaleY: 3.0
});
self.speed = 12 + Math.random() * 10;
self.rotationSpeed = (Math.random() - 0.5) * 0.1;
self.update = function () {
self.y += self.speed;
asteroidGraphics.rotation += self.rotationSpeed;
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 2.5
});
self.speed = 8 + Math.random() * 4;
self.rotationSpeed = (Math.random() - 0.5) * 0.1;
// Add floating animation
self.floatDirection = 1;
self.floatSpeed = 0.03 + Math.random() * 0.02;
self.floatAmount = 12 + Math.random() * 8;
self.floatTimer = Math.random() * 120;
self.update = function () {
self.y += self.speed;
coinGraphics.rotation += self.rotationSpeed;
// Add floating effect
self.floatTimer += self.floatSpeed;
var floatOffset = Math.sin(self.floatTimer) * self.floatAmount;
coinGraphics.y = floatOffset;
};
return self;
});
var Debris = Container.expand(function () {
var self = Container.call(this);
var debrisGraphics = self.attachAsset('debris', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
// Make medium debris darker
debrisGraphics.tint = 0x404040;
self.speed = 10 + Math.random() * 8;
self.horizontalSpeed = (Math.random() - 0.5) * 2;
self.update = function () {
self.y += self.speed;
self.x += self.horizontalSpeed;
};
return self;
});
var Fuel = Container.expand(function () {
var self = Container.call(this);
var fuelGraphics = self.attachAsset('fuel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.0,
scaleY: 3.0
});
self.speed = 9 + Math.random() * 6;
// Start floating animation
self.floatDirection = 1;
self.floatSpeed = 0.02 + Math.random() * 0.02;
self.floatAmount = 15 + Math.random() * 10;
self.originalY = 0;
self.floatTimer = Math.random() * 120;
// Add diverse rotation properties
self.rotationSpeed = (Math.random() - 0.5) * 0.04; // Random speed between -0.02 and 0.02
self.rotationDirection = Math.random() > 0.5 ? 1 : -1; // Random direction
self.update = function () {
self.y += self.speed;
// Add floating effect
self.floatTimer += self.floatSpeed;
var floatOffset = Math.sin(self.floatTimer) * self.floatAmount;
fuelGraphics.y = floatOffset;
// Add diverse rotation
fuelGraphics.rotation += self.rotationSpeed * self.rotationDirection;
};
return self;
});
var Spaceship = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('spaceship', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0
});
self.speed = 0;
self.maxSpeed = 8;
self.acceleration = 0.3;
self.friction = 0.85;
self.targetX = 1024; // Default center position
self.update = function () {
// Smoothly move towards target position
var deltaX = self.targetX - self.x;
self.x += deltaX * 0.2; // Smooth interpolation factor
// Keep ship within bounds
if (self.x < 40) {
self.x = 40;
}
if (self.x > 2008) {
self.x = 2008;
}
};
self.moveLeft = function () {
self.speed = Math.max(self.speed - self.acceleration, -self.maxSpeed);
};
self.moveRight = function () {
self.speed = Math.min(self.speed + self.acceleration, self.maxSpeed);
};
self.setTargetX = function (x) {
self.targetX = x;
};
return self;
});
var Spark = Container.expand(function () {
var self = Container.call(this);
var sparkGraphics = self.attachAsset('debris', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2 + Math.random() * 0.3,
scaleY: 0.5 + Math.random() * 0.6
});
// Make all sparks orange color
sparkGraphics.tint = 0xff6600;
self.speed = 8 + Math.random() * 6;
self.horizontalSpeed = (Math.random() - 0.5) * 4;
self.life = 30 + Math.random() * 20;
self.maxLife = self.life;
self.update = function () {
self.y += self.speed;
self.x += self.horizontalSpeed;
self.life--;
// Fade out over time with higher minimum opacity
self.alpha = Math.max(0.3, self.life / self.maxLife);
// Scale down over time but maintain larger minimum size
var scale = Math.max(0.2, self.life / self.maxLife * 0.5);
sparkGraphics.scaleX = scale;
sparkGraphics.scaleY = scale;
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('debris', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2 + Math.random() * 0.3,
scaleY: 0.2 + Math.random() * 0.3
});
// Make stars white and bright
starGraphics.tint = 0xffffff;
self.speed = 3 + Math.random() * 4;
self.twinkleTimer = Math.random() * 120;
self.maxAlpha = 0.8 + Math.random() * 0.2;
self.alpha = self.maxAlpha;
self.update = function () {
self.y += self.speed;
// Twinkling effect
self.twinkleTimer += 1;
var twinkle = Math.sin(self.twinkleTimer * 0.05) * 0.3 + 0.7;
self.alpha = self.maxAlpha * twinkle;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000011
});
/****
* Game Code
****/
// Game state management
var gameStarted = false;
var startScreen = null;
var startButton = null;
var spaceship = new Spaceship();
var obstacles = [];
var stars = [];
var sparks = [];
var scrollSpeed = 6;
var spawnTimer = 0;
var spawnRate = 120; // frames between spawns
var gameSpeed = 1;
var altitude = 0;
var lastTouchX = null;
var isDragging = false;
var maxHealth = 100;
var currentHealth = 100;
var healthBarBg;
var healthBarFill;
var maxFuel = 100;
var currentFuel = 100;
var fuelBarBg;
var fuelBarFill;
var fuelConsumptionRate = 0.15; // Fuel consumed per frame
var fuelPickups = [];
var coins = [];
// Create horizontal bar behind spaceship
var spaceshipBar = LK.getAsset('spaceshipBar', {
anchorX: 0.5,
anchorY: 0.5
});
spaceshipBar.x = 1024;
spaceshipBar.y = 2400;
spaceshipBar.alpha = 0.5; // Make bar even more transparent
game.addChild(spaceshipBar);
// Position spaceship
spaceship.x = 1024;
spaceship.y = 2400;
game.addChild(spaceship);
// Create score display
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
scoreText.visible = false; // Hide initially
LK.gui.top.addChild(scoreText);
// Create altitude display
var altitudeText = new Text2('Altitude: 0m', {
size: 50,
fill: 0xFFFFFF
});
altitudeText.anchor.set(0.5, 0);
altitudeText.y = 80;
altitudeText.visible = false; // Hide initially
LK.gui.top.addChild(altitudeText);
// Create health bar background
healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.0
});
healthBarBg.x = 1024;
healthBarBg.y = 200;
game.addChild(healthBarBg);
// Create health bar fill
healthBarFill = LK.getAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.0
});
healthBarFill.x = 1024;
healthBarFill.y = 202;
game.addChild(healthBarFill);
// Create fuel bar background
fuelBarBg = LK.getAsset('fuelBarBg', {
anchorX: 0.5,
anchorY: 0.0
});
fuelBarBg.x = 150;
fuelBarBg.y = 300;
game.addChild(fuelBarBg);
// Create fuel bar fill
fuelBarFill = LK.getAsset('fuelBarFill', {
anchorX: 0.5,
anchorY: 0.0
});
fuelBarFill.x = 150;
fuelBarFill.y = 302;
game.addChild(fuelBarFill);
// Create fuel icon below fuel bar
var fuelIcon = LK.getAsset('fuel', {
anchorX: 0.5,
anchorY: 0.0,
scaleX: 2.5,
scaleY: 2.5
});
fuelIcon.x = 150;
fuelIcon.y = 1850; // Position below the fuel bar
game.addChild(fuelIcon);
// Start pulsing animation for fuel icon
function startFuelIconPulse() {
tween(fuelIcon, {
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(fuelIcon, {
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: startFuelIconPulse
});
}
});
}
startFuelIconPulse();
function createObstacle() {
var obstacle;
if (Math.random() < 0.7) {
obstacle = new Asteroid();
} else {
obstacle = new Debris();
}
obstacle.x = Math.random() * (2048 - 100) + 50;
obstacle.y = -50;
obstacles.push(obstacle);
game.addChild(obstacle);
// Z-index management: larger objects (asteroids) should render above smaller objects (debris)
// Find the correct index to insert this obstacle
var targetIndex = game.getChildIndex(obstacle); // Start with current index
var maxIndex = game.children.length - 1;
// Only reorder if we have other obstacles to compare with
if (obstacle instanceof Asteroid) {
// Asteroids should be above debris - find the highest debris index
for (var j = 0; j < game.children.length; j++) {
var child = game.children[j];
if (child instanceof Debris) {
targetIndex = Math.min(j + 1, maxIndex);
}
}
} else if (obstacle instanceof Debris) {
// Debris should be below asteroids - find the lowest asteroid index
for (var j = 0; j < game.children.length; j++) {
var child = game.children[j];
if (child instanceof Asteroid) {
targetIndex = Math.max(j - 1, 0);
break; // Insert before first asteroid
}
}
}
// Ensure targetIndex is within valid bounds
targetIndex = Math.max(0, Math.min(targetIndex, maxIndex));
game.setChildIndex(obstacle, targetIndex);
}
function handleTouch(x, y) {
// Directly set spaceship target to cursor position
spaceship.setTargetX(x);
}
game.down = function (x, y, obj) {
if (!gameStarted) {
// Check if start button was clicked
if (startButton && x >= startButton.x - 495 && x <= startButton.x + 495 && y >= startButton.y - 48 && y <= startButton.y + 48) {
gameStarted = true;
LK.setScore(0);
removeStartScreen();
}
return;
}
isDragging = true;
lastTouchX = x;
handleTouch(x, y);
};
game.move = function (x, y, obj) {
if (!gameStarted) return;
// Always follow cursor, not just when dragging
handleTouch(x, y);
};
game.up = function (x, y, obj) {
isDragging = false;
lastTouchX = null;
};
game.update = function () {
if (!gameStarted) {
// Only update twinkling stars on start screen
if (LK.ticks % 15 === 0) {
var star = new Star();
star.x = Math.random() * 2048;
star.y = -10;
stars.push(star);
game.addChild(star);
// Move star behind everything
game.setChildIndex(star, 0);
}
// Update and cleanup stars
for (var s = stars.length - 1; s >= 0; s--) {
var star = stars[s];
if (star.lastY === undefined) star.lastY = star.y;
if (star.lastY < 2800 && star.y >= 2800) {
star.destroy();
stars.splice(s, 1);
continue;
}
star.lastY = star.y;
}
return;
}
// Update altitude only
altitude += scrollSpeed;
// Update score and altitude displays
scoreText.setText('Score: ' + LK.getScore());
altitudeText.setText('Altitude: ' + Math.floor(altitude) + 'm');
// Increase difficulty over time
if (LK.ticks % 600 === 0) {
// Every 10 seconds
gameSpeed += 0.1;
scrollSpeed = Math.min(scrollSpeed + 0.3, 10);
spawnRate = Math.max(spawnRate - 5, 30);
}
// Spawn obstacles - increase frequency based on altitude
spawnTimer++;
// Calculate dynamic spawn rate based on altitude
var altitudeBasedSpawnRate = Math.max(spawnRate - Math.floor(altitude / 500), 15); // Decrease spawn rate (increase frequency) every 500m altitude, minimum 15 frames
if (spawnTimer >= altitudeBasedSpawnRate) {
// Spawn normal obstacle first
createObstacle();
// Spawn additional large asteroids based on altitude (not small debris)
var extraAsteroidCount = Math.floor(altitude / 2000); // Add extra asteroid every 2000m altitude
for (var obs = 0; obs < extraAsteroidCount; obs++) {
// Force spawn only asteroids for altitude-based increases
var asteroid = new Asteroid();
asteroid.x = Math.random() * (2048 - 100) + 50;
asteroid.y = -50;
obstacles.push(asteroid);
game.addChild(asteroid);
// Z-index management for asteroids
var targetIndex = game.getChildIndex(asteroid);
var maxIndex = game.children.length - 1;
for (var j = 0; j < game.children.length; j++) {
var child = game.children[j];
if (child instanceof Debris) {
targetIndex = Math.min(j + 1, maxIndex);
}
}
targetIndex = Math.max(0, Math.min(targetIndex, maxIndex));
game.setChildIndex(asteroid, targetIndex);
}
spawnTimer = 0;
}
// Consume fuel constantly
currentFuel -= fuelConsumptionRate;
if (currentFuel < 0) currentFuel = 0;
// Update fuel bar
var fuelPercent = currentFuel / maxFuel;
fuelBarFill.scaleY = fuelPercent;
fuelBarFill.y = 302 + 1596 * (1 - fuelPercent);
// Fuel bar maintains original blue color - no color changes
// Lose health when out of fuel
if (currentFuel <= 0) {
currentHealth -= 1;
// Update health bar
var healthPercent = currentHealth / maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.x = 1024 - 148 + 296 * healthPercent * 0.5;
// Check if health is depleted
if (currentHealth <= 0) {
// Update highest altitude if current is higher
if (altitude > (storage.highestAltitude || 0)) {
storage.highestAltitude = altitude;
}
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Spawn fuel pickups occasionally
if (LK.ticks % 300 === 0) {
// Every 5 seconds
var fuelPickup = new Fuel();
fuelPickup.x = Math.random() * (2048 - 100) + 50;
fuelPickup.y = -50;
fuelPickups.push(fuelPickup);
game.addChild(fuelPickup);
}
// Spawn coins regularly
if (LK.ticks % 180 === 0) {
// Every 3 seconds
var coin = new Coin();
coin.x = Math.random() * (2048 - 100) + 50;
coin.y = -50;
coins.push(coin);
game.addChild(coin);
}
// Update fuel pickups and check collisions
for (var f = fuelPickups.length - 1; f >= 0; f--) {
var fuelPickup = fuelPickups[f];
// Track last position for cleanup
if (fuelPickup.lastY === undefined) fuelPickup.lastY = fuelPickup.y;
// Remove fuel pickups that are off screen
if (fuelPickup.lastY < 2800 && fuelPickup.y >= 2800) {
fuelPickup.destroy();
fuelPickups.splice(f, 1);
continue;
}
// Check collision with spaceship
if (fuelPickup.intersects(spaceship)) {
// Completely refill fuel
currentFuel = maxFuel;
LK.getSound('fuel_pickup').play();
fuelPickup.destroy();
fuelPickups.splice(f, 1);
continue;
}
fuelPickup.lastY = fuelPickup.y;
}
// Update coins and check collisions
for (var c = coins.length - 1; c >= 0; c--) {
var coin = coins[c];
// Track last position for cleanup
if (coin.lastY === undefined) coin.lastY = coin.y;
// Remove coins that are off screen
if (coin.lastY < 2800 && coin.y >= 2800) {
coin.destroy();
coins.splice(c, 1);
continue;
}
// Check collision with spaceship
if (coin.intersects(spaceship)) {
// Add coin to persistent storage first
storage.coins = (storage.coins || 0) + 1;
// Update score to match stored coins
LK.setScore(storage.coins);
LK.getSound('coin_collect').play();
coin.destroy();
coins.splice(c, 1);
continue;
}
coin.lastY = coin.y;
}
// Update obstacles and check collisions
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
// Track last position for cleanup
if (obstacle.lastY === undefined) obstacle.lastY = obstacle.y;
// Remove obstacles that are off screen
if (obstacle.lastY < 2800 && obstacle.y >= 2800) {
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
// Check collision with spaceship
if (obstacle.intersects(spaceship)) {
// Only deal damage if it's an asteroid (not small debris or stars)
if (obstacle instanceof Asteroid) {
// Reduce health instead of immediate game over
currentHealth -= 20;
// Update health bar
var healthPercent = currentHealth / maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.x = 1024 - 148 + 296 * healthPercent * 0.5;
// Flash screen red briefly
LK.effects.flashScreen(0xff0000, 300);
LK.getSound('explosion').play();
// Check if health is depleted
if (currentHealth <= 0) {
// Update highest altitude if current is higher
if (altitude > (storage.highestAltitude || 0)) {
storage.highestAltitude = altitude;
}
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Remove only asteroids that hit us
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
}
obstacle.lastY = obstacle.y;
}
// Spawn beautiful twinkling stars
if (LK.ticks % 15 === 0) {
var star = new Star();
star.x = Math.random() * 2048;
star.y = -10;
stars.push(star);
game.addChild(star);
// Move star behind spaceship bar
game.setChildIndex(star, 0);
}
// Update stars and remove off-screen ones
for (var s = stars.length - 1; s >= 0; s--) {
var star = stars[s];
// Track last position for cleanup
if (star.lastY === undefined) star.lastY = star.y;
// Remove stars that are off screen
if (star.lastY < 2800 && star.y >= 2800) {
star.destroy();
stars.splice(s, 1);
continue;
}
star.lastY = star.y;
}
// Spawn fire sparks from spaceship thrusters
if (LK.ticks % 3 === 0) {
// Create 2-3 sparks every few frames
var sparkCount = 2 + Math.floor(Math.random() * 2);
for (var sp = 0; sp < sparkCount; sp++) {
var spark = new Spark();
// Position sparks at bottom of spaceship with some spread
spark.x = spaceship.x + (Math.random() - 0.5) * 60;
spark.y = spaceship.y + 60; // Bottom of spaceship
sparks.push(spark);
game.addChild(spark);
}
}
// Move spaceship elements to front every frame to stay above obstacles
game.setChildIndex(spaceshipBar, game.children.length - 1);
game.setChildIndex(spaceship, game.children.length - 1);
// Move all sparks to front to stay above obstacles
for (var sp = 0; sp < sparks.length; sp++) {
var spark = sparks[sp];
if (spark.parent === game) {
game.setChildIndex(spark, game.children.length - 1);
}
}
// Update sparks and remove dead ones
for (var k = sparks.length - 1; k >= 0; k--) {
var spark = sparks[k];
// Remove sparks that are dead or off screen
if (spark.life <= 0 || spark.y > 2800) {
spark.destroy();
sparks.splice(k, 1);
continue;
}
}
};
// Create interactive space-themed start screen
function createStartScreen() {
// Create semi-transparent dark space background
startScreen = LK.getAsset('spaceshipBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 137.0
});
startScreen.x = 1024;
startScreen.y = 1366;
startScreen.alpha = 0.95;
startScreen.tint = 0x001122;
game.addChild(startScreen);
// Create nebula-like background layers for depth
var nebula1 = LK.getAsset('startScreenBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.28,
scaleY: 2.732
});
nebula1.x = 1024;
nebula1.y = 1366;
nebula1.alpha = 0.3;
nebula1.tint = 0x4B0082; // Deep purple
game.addChild(nebula1);
var nebula2 = LK.getAsset('startScreenBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 3.0
});
nebula2.x = 900;
nebula2.y = 1200;
nebula2.alpha = 0.2;
nebula2.tint = 0x191970; // Midnight blue
game.addChild(nebula2);
// Create animated title with glow effect
var titleText = new Text2('SPACE NAVIGATOR', {
size: 140,
fill: 0x00FFFF,
// Cyan glow
font: "'Arial Black', 'Impact', 'Helvetica Bold', sans-serif"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
game.addChild(titleText);
// Create subtitle with mission description
var subtitleText = new Text2('Navigate through the cosmic void', {
size: 60,
fill: 0x87CEEB,
// Sky blue
font: "'Arial Black', 'Impact', 'Helvetica Bold', sans-serif"
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 550;
game.addChild(subtitleText);
var missionText = new Text2('Dodge asteroids • Collect fuel • Survive the journey', {
size: 45,
fill: 0xFFD700,
// Gold
font: "'Arial Black', 'Impact', 'Helvetica Bold', sans-serif"
});
missionText.anchor.set(0.5, 0.5);
missionText.x = 1024;
missionText.y = 650;
game.addChild(missionText);
// Create animated spaceship for visual appeal
var menuSpaceship = LK.getAsset('spaceship', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4.0,
scaleY: 4.0
});
menuSpaceship.x = 1024;
menuSpaceship.y = 900;
menuSpaceship.tint = 0x00DDFF; // Light cyan
game.addChild(menuSpaceship);
// Create glowing start button with enhanced design
startButton = LK.getAsset('spaceshipBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 18.0
});
startButton.x = 1024;
startButton.y = 1400;
startButton.tint = 0x00AA00; // Green
game.addChild(startButton);
// Create button glow effect layers
var buttonGlow1 = LK.getAsset('spaceshipBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.65,
scaleY: 20.0
});
buttonGlow1.x = 1024;
buttonGlow1.y = 1400;
buttonGlow1.alpha = 0.3;
buttonGlow1.tint = 0x00FF00; // Bright green glow
game.addChild(buttonGlow1);
var buttonGlow2 = LK.getAsset('spaceshipBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 22.0
});
buttonGlow2.x = 1024;
buttonGlow2.y = 1400;
buttonGlow2.alpha = 0.15;
buttonGlow2.tint = 0x00FF88; // Lighter green glow
game.addChild(buttonGlow2);
// Create enhanced button text with shadow effect
var buttonText = new Text2('► LAUNCH MISSION ◄', {
size: 85,
fill: 0xFFFFFF,
font: "'Arial Black', 'Impact', 'Helvetica Bold', sans-serif"
});
buttonText.anchor.set(0.5, 0.5);
buttonText.x = 1024;
buttonText.y = 1400;
game.addChild(buttonText);
// Create stats container background
var statsBackground = LK.getAsset('spaceshipBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 25.0
});
statsBackground.x = 1024;
statsBackground.y = 1850;
statsBackground.alpha = 0.2;
statsBackground.tint = 0x003366; // Dark blue
game.addChild(statsBackground);
// Create highest altitude display
var highestAltitude = storage.highestAltitude || 0;
var altitudeStatsText = new Text2('🚀 HIGHEST ALTITUDE: ' + Math.floor(highestAltitude) + 'm', {
size: 55,
fill: 0x00DDFF,
font: "'Arial Black', 'Impact', 'Helvetica Bold', sans-serif"
});
altitudeStatsText.anchor.set(0.5, 0.5);
altitudeStatsText.x = 1024;
altitudeStatsText.y = 1800;
game.addChild(altitudeStatsText);
// Create total coins display
var totalCoins = storage.coins || 0;
var coinsStatsText = new Text2('💰 TOTAL COINS: ' + totalCoins, {
size: 55,
fill: 0xFFD700,
font: "'Arial Black', 'Impact', 'Helvetica Bold', sans-serif"
});
coinsStatsText.anchor.set(0.5, 0.5);
coinsStatsText.x = 1024;
coinsStatsText.y = 1900;
game.addChild(coinsStatsText);
// Add gentle glow animation to stats
function statsGlow() {
tween(altitudeStatsText, {
fill: 0x00AAFF
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(altitudeStatsText, {
fill: 0x00DDFF
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: statsGlow
});
}
});
}
function coinsGlow() {
tween(coinsStatsText, {
fill: 0xFFAA00
}, {
duration: 2800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(coinsStatsText, {
fill: 0xFFD700
}, {
duration: 2800,
easing: tween.easeInOut,
onFinish: coinsGlow
});
}
});
}
function statsBackgroundPulse() {
tween(statsBackground, {
alpha: 0.3,
scaleY: 26.0
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(statsBackground, {
alpha: 0.2,
scaleY: 25.0
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: statsBackgroundPulse
});
}
});
}
// Start stats animations
statsGlow();
coinsGlow();
statsBackgroundPulse();
// Start complex pulsing animations for interactive feel
function startButtonPulse() {
tween(startButton, {
scaleX: 0.55,
scaleY: 17.0,
tint: 0x00FF00
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(startButton, {
scaleX: 0.6,
scaleY: 18.0,
tint: 0x00AA00
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: startButtonPulse
});
}
});
}
function glowPulse1() {
tween(buttonGlow1, {
scaleX: 0.7,
scaleY: 22.0,
alpha: 0.4
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(buttonGlow1, {
scaleX: 0.65,
scaleY: 20.0,
alpha: 0.3
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: glowPulse1
});
}
});
}
function glowPulse2() {
tween(buttonGlow2, {
scaleX: 0.75,
scaleY: 24.0,
alpha: 0.2
}, {
duration: 1200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(buttonGlow2, {
scaleX: 0.7,
scaleY: 22.0,
alpha: 0.15
}, {
duration: 1200,
easing: tween.easeInOut,
onFinish: glowPulse2
});
}
});
}
function titleGlow() {
tween(titleText, {
fill: 0x00AAFF
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText, {
fill: 0x00FFFF
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: titleGlow
});
}
});
}
function spaceshipFloat() {
tween(menuSpaceship, {
y: 880,
rotation: 0.1
}, {
duration: 2500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(menuSpaceship, {
y: 920,
rotation: -0.1
}, {
duration: 2500,
easing: tween.easeInOut,
onFinish: spaceshipFloat
});
}
});
}
// Start all animations
startButtonPulse();
glowPulse1();
glowPulse2();
titleGlow();
spaceshipFloat();
// Hide main menu button when start screen is shown
mainMenuButton.visible = false;
// Store references for cleanup
startScreen.titleText = titleText;
startScreen.subtitleText = subtitleText;
startScreen.missionText = missionText;
startScreen.menuSpaceship = menuSpaceship;
startScreen.buttonText = buttonText;
startScreen.nebula1 = nebula1;
startScreen.nebula2 = nebula2;
startScreen.buttonGlow1 = buttonGlow1;
startScreen.buttonGlow2 = buttonGlow2;
startScreen.statsBackground = statsBackground;
startScreen.altitudeStatsText = altitudeStatsText;
startScreen.coinsStatsText = coinsStatsText;
}
function removeStartScreen() {
if (startScreen) {
// Stop all ongoing tween animations
tween.stop(startButton);
tween.stop(startScreen.buttonGlow1);
tween.stop(startScreen.buttonGlow2);
tween.stop(startScreen.titleText);
tween.stop(startScreen.menuSpaceship);
tween.stop(startScreen.altitudeStatsText);
tween.stop(startScreen.coinsStatsText);
tween.stop(startScreen.statsBackground);
// Show main menu button when game starts
mainMenuButton.visible = true;
// Show altitude and score text when game starts
scoreText.visible = true;
altitudeText.visible = true;
// Destroy all start screen elements
startScreen.destroy();
startScreen.titleText.destroy();
startScreen.subtitleText.destroy();
startScreen.missionText.destroy();
startScreen.menuSpaceship.destroy();
startScreen.buttonText.destroy();
startScreen.nebula1.destroy();
startScreen.nebula2.destroy();
startScreen.buttonGlow1.destroy();
startScreen.buttonGlow2.destroy();
startScreen.statsBackground.destroy();
startScreen.altitudeStatsText.destroy();
startScreen.coinsStatsText.destroy();
startButton.destroy();
// Clear references
startScreen = null;
startButton = null;
}
}
// Create main menu button next to pause button
var mainMenuButton = new Text2('MENU', {
size: 55,
fill: 0xFFFFFF
});
mainMenuButton.anchor.set(0, 0);
mainMenuButton.x = 160; // Position to the right of pause button area
mainMenuButton.y = 50;
LK.gui.addChild(mainMenuButton);
// Add touch handler for main menu button
mainMenuButton.down = function (x, y, obj) {
// Reset game state and show start screen
gameStarted = false;
// Hide altitude and score text when returning to main menu
scoreText.visible = false;
altitudeText.visible = false;
// Clear all game objects
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
}
obstacles = [];
for (var s = stars.length - 1; s >= 0; s--) {
stars[s].destroy();
}
stars = [];
for (var sp = sparks.length - 1; sp >= 0; sp--) {
sparks[sp].destroy();
}
sparks = [];
for (var f = fuelPickups.length - 1; f >= 0; f--) {
fuelPickups[f].destroy();
}
fuelPickups = [];
for (var c = coins.length - 1; c >= 0; c--) {
coins[c].destroy();
}
coins = [];
// Reset game variables
altitude = 0;
scrollSpeed = 6;
spawnTimer = 0;
spawnRate = 120;
gameSpeed = 1;
currentHealth = 100;
currentFuel = 100;
LK.setScore(0);
// Reset spaceship position
spaceship.x = 1024;
spaceship.y = 2400;
spaceship.targetX = 1024;
// Reset health bar
var healthPercent = currentHealth / maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.x = 1024 - 148 + 296 * healthPercent * 0.5;
// Reset fuel bar
var fuelPercent = currentFuel / maxFuel;
fuelBarFill.scaleY = fuelPercent;
fuelBarFill.y = 302 + 1596 * (1 - fuelPercent);
// Show start screen
createStartScreen();
};
// Initialize start screen and start background music
createStartScreen();
LK.playMusic('space_music'); /****
* 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: 3.0,
scaleY: 3.0
});
self.speed = 12 + Math.random() * 10;
self.rotationSpeed = (Math.random() - 0.5) * 0.1;
self.update = function () {
self.y += self.speed;
asteroidGraphics.rotation += self.rotationSpeed;
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 2.5
});
self.speed = 8 + Math.random() * 4;
self.rotationSpeed = (Math.random() - 0.5) * 0.1;
// Add floating animation
self.floatDirection = 1;
self.floatSpeed = 0.03 + Math.random() * 0.02;
self.floatAmount = 12 + Math.random() * 8;
self.floatTimer = Math.random() * 120;
self.update = function () {
self.y += self.speed;
coinGraphics.rotation += self.rotationSpeed;
// Add floating effect
self.floatTimer += self.floatSpeed;
var floatOffset = Math.sin(self.floatTimer) * self.floatAmount;
coinGraphics.y = floatOffset;
};
return self;
});
var Debris = Container.expand(function () {
var self = Container.call(this);
var debrisGraphics = self.attachAsset('debris', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
// Make medium debris darker
debrisGraphics.tint = 0x404040;
self.speed = 10 + Math.random() * 8;
self.horizontalSpeed = (Math.random() - 0.5) * 2;
self.update = function () {
self.y += self.speed;
self.x += self.horizontalSpeed;
};
return self;
});
var Fuel = Container.expand(function () {
var self = Container.call(this);
var fuelGraphics = self.attachAsset('fuel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.0,
scaleY: 3.0
});
self.speed = 9 + Math.random() * 6;
// Start floating animation
self.floatDirection = 1;
self.floatSpeed = 0.02 + Math.random() * 0.02;
self.floatAmount = 15 + Math.random() * 10;
self.originalY = 0;
self.floatTimer = Math.random() * 120;
// Add diverse rotation properties
self.rotationSpeed = (Math.random() - 0.5) * 0.04; // Random speed between -0.02 and 0.02
self.rotationDirection = Math.random() > 0.5 ? 1 : -1; // Random direction
self.update = function () {
self.y += self.speed;
// Add floating effect
self.floatTimer += self.floatSpeed;
var floatOffset = Math.sin(self.floatTimer) * self.floatAmount;
fuelGraphics.y = floatOffset;
// Add diverse rotation
fuelGraphics.rotation += self.rotationSpeed * self.rotationDirection;
};
return self;
});
var Spaceship = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('spaceship', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0
});
self.speed = 0;
self.maxSpeed = 8;
self.acceleration = 0.3;
self.friction = 0.85;
self.targetX = 1024; // Default center position
self.update = function () {
// Smoothly move towards target position
var deltaX = self.targetX - self.x;
self.x += deltaX * 0.2; // Smooth interpolation factor
// Keep ship within bounds
if (self.x < 40) {
self.x = 40;
}
if (self.x > 2008) {
self.x = 2008;
}
};
self.moveLeft = function () {
self.speed = Math.max(self.speed - self.acceleration, -self.maxSpeed);
};
self.moveRight = function () {
self.speed = Math.min(self.speed + self.acceleration, self.maxSpeed);
};
self.setTargetX = function (x) {
self.targetX = x;
};
return self;
});
var Spark = Container.expand(function () {
var self = Container.call(this);
var sparkGraphics = self.attachAsset('debris', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2 + Math.random() * 0.3,
scaleY: 0.5 + Math.random() * 0.6
});
// Make all sparks orange color
sparkGraphics.tint = 0xff6600;
self.speed = 8 + Math.random() * 6;
self.horizontalSpeed = (Math.random() - 0.5) * 4;
self.life = 30 + Math.random() * 20;
self.maxLife = self.life;
self.update = function () {
self.y += self.speed;
self.x += self.horizontalSpeed;
self.life--;
// Fade out over time with higher minimum opacity
self.alpha = Math.max(0.3, self.life / self.maxLife);
// Scale down over time but maintain larger minimum size
var scale = Math.max(0.2, self.life / self.maxLife * 0.5);
sparkGraphics.scaleX = scale;
sparkGraphics.scaleY = scale;
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('debris', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2 + Math.random() * 0.3,
scaleY: 0.2 + Math.random() * 0.3
});
// Make stars white and bright
starGraphics.tint = 0xffffff;
self.speed = 3 + Math.random() * 4;
self.twinkleTimer = Math.random() * 120;
self.maxAlpha = 0.8 + Math.random() * 0.2;
self.alpha = self.maxAlpha;
self.update = function () {
self.y += self.speed;
// Twinkling effect
self.twinkleTimer += 1;
var twinkle = Math.sin(self.twinkleTimer * 0.05) * 0.3 + 0.7;
self.alpha = self.maxAlpha * twinkle;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000011
});
/****
* Game Code
****/
// Game state management
var gameStarted = false;
var startScreen = null;
var startButton = null;
var spaceship = new Spaceship();
var obstacles = [];
var stars = [];
var sparks = [];
var scrollSpeed = 6;
var spawnTimer = 0;
var spawnRate = 120; // frames between spawns
var gameSpeed = 1;
var altitude = 0;
var lastTouchX = null;
var isDragging = false;
var maxHealth = 100;
var currentHealth = 100;
var healthBarBg;
var healthBarFill;
var maxFuel = 100;
var currentFuel = 100;
var fuelBarBg;
var fuelBarFill;
var fuelConsumptionRate = 0.15; // Fuel consumed per frame
var fuelPickups = [];
var coins = [];
// Create horizontal bar behind spaceship
var spaceshipBar = LK.getAsset('spaceshipBar', {
anchorX: 0.5,
anchorY: 0.5
});
spaceshipBar.x = 1024;
spaceshipBar.y = 2400;
spaceshipBar.alpha = 0.5; // Make bar even more transparent
game.addChild(spaceshipBar);
// Position spaceship
spaceship.x = 1024;
spaceship.y = 2400;
game.addChild(spaceship);
// Create score display
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
scoreText.visible = false; // Hide initially
LK.gui.top.addChild(scoreText);
// Create altitude display
var altitudeText = new Text2('Altitude: 0m', {
size: 50,
fill: 0xFFFFFF
});
altitudeText.anchor.set(0.5, 0);
altitudeText.y = 80;
altitudeText.visible = false; // Hide initially
LK.gui.top.addChild(altitudeText);
// Create health bar background
healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.0
});
healthBarBg.x = 1024;
healthBarBg.y = 200;
game.addChild(healthBarBg);
// Create health bar fill
healthBarFill = LK.getAsset('healthBarFill', {
anchorX: 0.5,
anchorY: 0.0
});
healthBarFill.x = 1024;
healthBarFill.y = 202;
game.addChild(healthBarFill);
// Create fuel bar background
fuelBarBg = LK.getAsset('fuelBarBg', {
anchorX: 0.5,
anchorY: 0.0
});
fuelBarBg.x = 150;
fuelBarBg.y = 300;
game.addChild(fuelBarBg);
// Create fuel bar fill
fuelBarFill = LK.getAsset('fuelBarFill', {
anchorX: 0.5,
anchorY: 0.0
});
fuelBarFill.x = 150;
fuelBarFill.y = 302;
game.addChild(fuelBarFill);
// Create fuel icon below fuel bar
var fuelIcon = LK.getAsset('fuel', {
anchorX: 0.5,
anchorY: 0.0,
scaleX: 2.5,
scaleY: 2.5
});
fuelIcon.x = 150;
fuelIcon.y = 1850; // Position below the fuel bar
game.addChild(fuelIcon);
// Start pulsing animation for fuel icon
function startFuelIconPulse() {
tween(fuelIcon, {
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(fuelIcon, {
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: startFuelIconPulse
});
}
});
}
startFuelIconPulse();
function createObstacle() {
var obstacle;
if (Math.random() < 0.7) {
obstacle = new Asteroid();
} else {
obstacle = new Debris();
}
obstacle.x = Math.random() * (2048 - 100) + 50;
obstacle.y = -50;
obstacles.push(obstacle);
game.addChild(obstacle);
// Z-index management: larger objects (asteroids) should render above smaller objects (debris)
// Find the correct index to insert this obstacle
var targetIndex = game.getChildIndex(obstacle); // Start with current index
var maxIndex = game.children.length - 1;
// Only reorder if we have other obstacles to compare with
if (obstacle instanceof Asteroid) {
// Asteroids should be above debris - find the highest debris index
for (var j = 0; j < game.children.length; j++) {
var child = game.children[j];
if (child instanceof Debris) {
targetIndex = Math.min(j + 1, maxIndex);
}
}
} else if (obstacle instanceof Debris) {
// Debris should be below asteroids - find the lowest asteroid index
for (var j = 0; j < game.children.length; j++) {
var child = game.children[j];
if (child instanceof Asteroid) {
targetIndex = Math.max(j - 1, 0);
break; // Insert before first asteroid
}
}
}
// Ensure targetIndex is within valid bounds
targetIndex = Math.max(0, Math.min(targetIndex, maxIndex));
game.setChildIndex(obstacle, targetIndex);
}
function handleTouch(x, y) {
// Directly set spaceship target to cursor position
spaceship.setTargetX(x);
}
game.down = function (x, y, obj) {
if (!gameStarted) {
// Check if start button was clicked
if (startButton && x >= startButton.x - 495 && x <= startButton.x + 495 && y >= startButton.y - 48 && y <= startButton.y + 48) {
gameStarted = true;
LK.setScore(0);
removeStartScreen();
}
return;
}
isDragging = true;
lastTouchX = x;
handleTouch(x, y);
};
game.move = function (x, y, obj) {
if (!gameStarted) return;
// Always follow cursor, not just when dragging
handleTouch(x, y);
};
game.up = function (x, y, obj) {
isDragging = false;
lastTouchX = null;
};
game.update = function () {
if (!gameStarted) {
// Only update twinkling stars on start screen
if (LK.ticks % 15 === 0) {
var star = new Star();
star.x = Math.random() * 2048;
star.y = -10;
stars.push(star);
game.addChild(star);
// Move star behind everything
game.setChildIndex(star, 0);
}
// Update and cleanup stars
for (var s = stars.length - 1; s >= 0; s--) {
var star = stars[s];
if (star.lastY === undefined) star.lastY = star.y;
if (star.lastY < 2800 && star.y >= 2800) {
star.destroy();
stars.splice(s, 1);
continue;
}
star.lastY = star.y;
}
return;
}
// Update altitude only
altitude += scrollSpeed;
// Update score and altitude displays
scoreText.setText('Score: ' + LK.getScore());
altitudeText.setText('Altitude: ' + Math.floor(altitude) + 'm');
// Increase difficulty over time
if (LK.ticks % 600 === 0) {
// Every 10 seconds
gameSpeed += 0.1;
scrollSpeed = Math.min(scrollSpeed + 0.3, 10);
spawnRate = Math.max(spawnRate - 5, 30);
}
// Spawn obstacles - increase frequency based on altitude
spawnTimer++;
// Calculate dynamic spawn rate based on altitude
var altitudeBasedSpawnRate = Math.max(spawnRate - Math.floor(altitude / 500), 15); // Decrease spawn rate (increase frequency) every 500m altitude, minimum 15 frames
if (spawnTimer >= altitudeBasedSpawnRate) {
// Spawn normal obstacle first
createObstacle();
// Spawn additional large asteroids based on altitude (not small debris)
var extraAsteroidCount = Math.floor(altitude / 2000); // Add extra asteroid every 2000m altitude
for (var obs = 0; obs < extraAsteroidCount; obs++) {
// Force spawn only asteroids for altitude-based increases
var asteroid = new Asteroid();
asteroid.x = Math.random() * (2048 - 100) + 50;
asteroid.y = -50;
obstacles.push(asteroid);
game.addChild(asteroid);
// Z-index management for asteroids
var targetIndex = game.getChildIndex(asteroid);
var maxIndex = game.children.length - 1;
for (var j = 0; j < game.children.length; j++) {
var child = game.children[j];
if (child instanceof Debris) {
targetIndex = Math.min(j + 1, maxIndex);
}
}
targetIndex = Math.max(0, Math.min(targetIndex, maxIndex));
game.setChildIndex(asteroid, targetIndex);
}
spawnTimer = 0;
}
// Consume fuel constantly
currentFuel -= fuelConsumptionRate;
if (currentFuel < 0) currentFuel = 0;
// Update fuel bar
var fuelPercent = currentFuel / maxFuel;
fuelBarFill.scaleY = fuelPercent;
fuelBarFill.y = 302 + 1596 * (1 - fuelPercent);
// Fuel bar maintains original blue color - no color changes
// Lose health when out of fuel
if (currentFuel <= 0) {
currentHealth -= 1;
// Update health bar
var healthPercent = currentHealth / maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.x = 1024 - 148 + 296 * healthPercent * 0.5;
// Check if health is depleted
if (currentHealth <= 0) {
// Update highest altitude if current is higher
if (altitude > (storage.highestAltitude || 0)) {
storage.highestAltitude = altitude;
}
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Spawn fuel pickups occasionally
if (LK.ticks % 300 === 0) {
// Every 5 seconds
var fuelPickup = new Fuel();
fuelPickup.x = Math.random() * (2048 - 100) + 50;
fuelPickup.y = -50;
fuelPickups.push(fuelPickup);
game.addChild(fuelPickup);
}
// Spawn coins regularly
if (LK.ticks % 180 === 0) {
// Every 3 seconds
var coin = new Coin();
coin.x = Math.random() * (2048 - 100) + 50;
coin.y = -50;
coins.push(coin);
game.addChild(coin);
}
// Update fuel pickups and check collisions
for (var f = fuelPickups.length - 1; f >= 0; f--) {
var fuelPickup = fuelPickups[f];
// Track last position for cleanup
if (fuelPickup.lastY === undefined) fuelPickup.lastY = fuelPickup.y;
// Remove fuel pickups that are off screen
if (fuelPickup.lastY < 2800 && fuelPickup.y >= 2800) {
fuelPickup.destroy();
fuelPickups.splice(f, 1);
continue;
}
// Check collision with spaceship
if (fuelPickup.intersects(spaceship)) {
// Completely refill fuel
currentFuel = maxFuel;
LK.getSound('fuel_pickup').play();
fuelPickup.destroy();
fuelPickups.splice(f, 1);
continue;
}
fuelPickup.lastY = fuelPickup.y;
}
// Update coins and check collisions
for (var c = coins.length - 1; c >= 0; c--) {
var coin = coins[c];
// Track last position for cleanup
if (coin.lastY === undefined) coin.lastY = coin.y;
// Remove coins that are off screen
if (coin.lastY < 2800 && coin.y >= 2800) {
coin.destroy();
coins.splice(c, 1);
continue;
}
// Check collision with spaceship
if (coin.intersects(spaceship)) {
// Add coin to persistent storage first
storage.coins = (storage.coins || 0) + 1;
// Update score to match stored coins
LK.setScore(storage.coins);
LK.getSound('coin_collect').play();
coin.destroy();
coins.splice(c, 1);
continue;
}
coin.lastY = coin.y;
}
// Update obstacles and check collisions
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
// Track last position for cleanup
if (obstacle.lastY === undefined) obstacle.lastY = obstacle.y;
// Remove obstacles that are off screen
if (obstacle.lastY < 2800 && obstacle.y >= 2800) {
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
// Check collision with spaceship
if (obstacle.intersects(spaceship)) {
// Only deal damage if it's an asteroid (not small debris or stars)
if (obstacle instanceof Asteroid) {
// Reduce health instead of immediate game over
currentHealth -= 20;
// Update health bar
var healthPercent = currentHealth / maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.x = 1024 - 148 + 296 * healthPercent * 0.5;
// Flash screen red briefly
LK.effects.flashScreen(0xff0000, 300);
LK.getSound('explosion').play();
// Check if health is depleted
if (currentHealth <= 0) {
// Update highest altitude if current is higher
if (altitude > (storage.highestAltitude || 0)) {
storage.highestAltitude = altitude;
}
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// Remove only asteroids that hit us
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
}
obstacle.lastY = obstacle.y;
}
// Spawn beautiful twinkling stars
if (LK.ticks % 15 === 0) {
var star = new Star();
star.x = Math.random() * 2048;
star.y = -10;
stars.push(star);
game.addChild(star);
// Move star behind spaceship bar
game.setChildIndex(star, 0);
}
// Update stars and remove off-screen ones
for (var s = stars.length - 1; s >= 0; s--) {
var star = stars[s];
// Track last position for cleanup
if (star.lastY === undefined) star.lastY = star.y;
// Remove stars that are off screen
if (star.lastY < 2800 && star.y >= 2800) {
star.destroy();
stars.splice(s, 1);
continue;
}
star.lastY = star.y;
}
// Spawn fire sparks from spaceship thrusters
if (LK.ticks % 3 === 0) {
// Create 2-3 sparks every few frames
var sparkCount = 2 + Math.floor(Math.random() * 2);
for (var sp = 0; sp < sparkCount; sp++) {
var spark = new Spark();
// Position sparks at bottom of spaceship with some spread
spark.x = spaceship.x + (Math.random() - 0.5) * 60;
spark.y = spaceship.y + 60; // Bottom of spaceship
sparks.push(spark);
game.addChild(spark);
}
}
// Move spaceship elements to front every frame to stay above obstacles
game.setChildIndex(spaceshipBar, game.children.length - 1);
game.setChildIndex(spaceship, game.children.length - 1);
// Move all sparks to front to stay above obstacles
for (var sp = 0; sp < sparks.length; sp++) {
var spark = sparks[sp];
if (spark.parent === game) {
game.setChildIndex(spark, game.children.length - 1);
}
}
// Update sparks and remove dead ones
for (var k = sparks.length - 1; k >= 0; k--) {
var spark = sparks[k];
// Remove sparks that are dead or off screen
if (spark.life <= 0 || spark.y > 2800) {
spark.destroy();
sparks.splice(k, 1);
continue;
}
}
};
// Create interactive space-themed start screen
function createStartScreen() {
// Create semi-transparent dark space background
startScreen = LK.getAsset('spaceshipBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 137.0
});
startScreen.x = 1024;
startScreen.y = 1366;
startScreen.alpha = 0.95;
startScreen.tint = 0x001122;
game.addChild(startScreen);
// Create nebula-like background layers for depth
var nebula1 = LK.getAsset('startScreenBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.28,
scaleY: 2.732
});
nebula1.x = 1024;
nebula1.y = 1366;
nebula1.alpha = 0.3;
nebula1.tint = 0x4B0082; // Deep purple
game.addChild(nebula1);
var nebula2 = LK.getAsset('startScreenBg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 3.0
});
nebula2.x = 900;
nebula2.y = 1200;
nebula2.alpha = 0.2;
nebula2.tint = 0x191970; // Midnight blue
game.addChild(nebula2);
// Create animated title with glow effect
var titleText = new Text2('SPACE NAVIGATOR', {
size: 140,
fill: 0x00FFFF,
// Cyan glow
font: "'Arial Black', 'Impact', 'Helvetica Bold', sans-serif"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
game.addChild(titleText);
// Create subtitle with mission description
var subtitleText = new Text2('Navigate through the cosmic void', {
size: 60,
fill: 0x87CEEB,
// Sky blue
font: "'Arial Black', 'Impact', 'Helvetica Bold', sans-serif"
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 550;
game.addChild(subtitleText);
var missionText = new Text2('Dodge asteroids • Collect fuel • Survive the journey', {
size: 45,
fill: 0xFFD700,
// Gold
font: "'Arial Black', 'Impact', 'Helvetica Bold', sans-serif"
});
missionText.anchor.set(0.5, 0.5);
missionText.x = 1024;
missionText.y = 650;
game.addChild(missionText);
// Create animated spaceship for visual appeal
var menuSpaceship = LK.getAsset('spaceship', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4.0,
scaleY: 4.0
});
menuSpaceship.x = 1024;
menuSpaceship.y = 900;
menuSpaceship.tint = 0x00DDFF; // Light cyan
game.addChild(menuSpaceship);
// Create glowing start button with enhanced design
startButton = LK.getAsset('spaceshipBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 18.0
});
startButton.x = 1024;
startButton.y = 1400;
startButton.tint = 0x00AA00; // Green
game.addChild(startButton);
// Create button glow effect layers
var buttonGlow1 = LK.getAsset('spaceshipBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.65,
scaleY: 20.0
});
buttonGlow1.x = 1024;
buttonGlow1.y = 1400;
buttonGlow1.alpha = 0.3;
buttonGlow1.tint = 0x00FF00; // Bright green glow
game.addChild(buttonGlow1);
var buttonGlow2 = LK.getAsset('spaceshipBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 22.0
});
buttonGlow2.x = 1024;
buttonGlow2.y = 1400;
buttonGlow2.alpha = 0.15;
buttonGlow2.tint = 0x00FF88; // Lighter green glow
game.addChild(buttonGlow2);
// Create enhanced button text with shadow effect
var buttonText = new Text2('► LAUNCH MISSION ◄', {
size: 85,
fill: 0xFFFFFF,
font: "'Arial Black', 'Impact', 'Helvetica Bold', sans-serif"
});
buttonText.anchor.set(0.5, 0.5);
buttonText.x = 1024;
buttonText.y = 1400;
game.addChild(buttonText);
// Create stats container background
var statsBackground = LK.getAsset('spaceshipBar', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 25.0
});
statsBackground.x = 1024;
statsBackground.y = 1850;
statsBackground.alpha = 0.2;
statsBackground.tint = 0x003366; // Dark blue
game.addChild(statsBackground);
// Create highest altitude display
var highestAltitude = storage.highestAltitude || 0;
var altitudeStatsText = new Text2('🚀 HIGHEST ALTITUDE: ' + Math.floor(highestAltitude) + 'm', {
size: 55,
fill: 0x00DDFF,
font: "'Arial Black', 'Impact', 'Helvetica Bold', sans-serif"
});
altitudeStatsText.anchor.set(0.5, 0.5);
altitudeStatsText.x = 1024;
altitudeStatsText.y = 1800;
game.addChild(altitudeStatsText);
// Create total coins display
var totalCoins = storage.coins || 0;
var coinsStatsText = new Text2('💰 TOTAL COINS: ' + totalCoins, {
size: 55,
fill: 0xFFD700,
font: "'Arial Black', 'Impact', 'Helvetica Bold', sans-serif"
});
coinsStatsText.anchor.set(0.5, 0.5);
coinsStatsText.x = 1024;
coinsStatsText.y = 1900;
game.addChild(coinsStatsText);
// Add gentle glow animation to stats
function statsGlow() {
tween(altitudeStatsText, {
fill: 0x00AAFF
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(altitudeStatsText, {
fill: 0x00DDFF
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: statsGlow
});
}
});
}
function coinsGlow() {
tween(coinsStatsText, {
fill: 0xFFAA00
}, {
duration: 2800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(coinsStatsText, {
fill: 0xFFD700
}, {
duration: 2800,
easing: tween.easeInOut,
onFinish: coinsGlow
});
}
});
}
function statsBackgroundPulse() {
tween(statsBackground, {
alpha: 0.3,
scaleY: 26.0
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(statsBackground, {
alpha: 0.2,
scaleY: 25.0
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: statsBackgroundPulse
});
}
});
}
// Start stats animations
statsGlow();
coinsGlow();
statsBackgroundPulse();
// Start complex pulsing animations for interactive feel
function startButtonPulse() {
tween(startButton, {
scaleX: 0.55,
scaleY: 17.0,
tint: 0x00FF00
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(startButton, {
scaleX: 0.6,
scaleY: 18.0,
tint: 0x00AA00
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: startButtonPulse
});
}
});
}
function glowPulse1() {
tween(buttonGlow1, {
scaleX: 0.7,
scaleY: 22.0,
alpha: 0.4
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(buttonGlow1, {
scaleX: 0.65,
scaleY: 20.0,
alpha: 0.3
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: glowPulse1
});
}
});
}
function glowPulse2() {
tween(buttonGlow2, {
scaleX: 0.75,
scaleY: 24.0,
alpha: 0.2
}, {
duration: 1200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(buttonGlow2, {
scaleX: 0.7,
scaleY: 22.0,
alpha: 0.15
}, {
duration: 1200,
easing: tween.easeInOut,
onFinish: glowPulse2
});
}
});
}
function titleGlow() {
tween(titleText, {
fill: 0x00AAFF
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText, {
fill: 0x00FFFF
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: titleGlow
});
}
});
}
function spaceshipFloat() {
tween(menuSpaceship, {
y: 880,
rotation: 0.1
}, {
duration: 2500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(menuSpaceship, {
y: 920,
rotation: -0.1
}, {
duration: 2500,
easing: tween.easeInOut,
onFinish: spaceshipFloat
});
}
});
}
// Start all animations
startButtonPulse();
glowPulse1();
glowPulse2();
titleGlow();
spaceshipFloat();
// Hide main menu button when start screen is shown
mainMenuButton.visible = false;
// Store references for cleanup
startScreen.titleText = titleText;
startScreen.subtitleText = subtitleText;
startScreen.missionText = missionText;
startScreen.menuSpaceship = menuSpaceship;
startScreen.buttonText = buttonText;
startScreen.nebula1 = nebula1;
startScreen.nebula2 = nebula2;
startScreen.buttonGlow1 = buttonGlow1;
startScreen.buttonGlow2 = buttonGlow2;
startScreen.statsBackground = statsBackground;
startScreen.altitudeStatsText = altitudeStatsText;
startScreen.coinsStatsText = coinsStatsText;
}
function removeStartScreen() {
if (startScreen) {
// Stop all ongoing tween animations
tween.stop(startButton);
tween.stop(startScreen.buttonGlow1);
tween.stop(startScreen.buttonGlow2);
tween.stop(startScreen.titleText);
tween.stop(startScreen.menuSpaceship);
tween.stop(startScreen.altitudeStatsText);
tween.stop(startScreen.coinsStatsText);
tween.stop(startScreen.statsBackground);
// Show main menu button when game starts
mainMenuButton.visible = true;
// Show altitude and score text when game starts
scoreText.visible = true;
altitudeText.visible = true;
// Destroy all start screen elements
startScreen.destroy();
startScreen.titleText.destroy();
startScreen.subtitleText.destroy();
startScreen.missionText.destroy();
startScreen.menuSpaceship.destroy();
startScreen.buttonText.destroy();
startScreen.nebula1.destroy();
startScreen.nebula2.destroy();
startScreen.buttonGlow1.destroy();
startScreen.buttonGlow2.destroy();
startScreen.statsBackground.destroy();
startScreen.altitudeStatsText.destroy();
startScreen.coinsStatsText.destroy();
startButton.destroy();
// Clear references
startScreen = null;
startButton = null;
}
}
// Create main menu button next to pause button
var mainMenuButton = new Text2('MENU', {
size: 55,
fill: 0xFFFFFF
});
mainMenuButton.anchor.set(0, 0);
mainMenuButton.x = 160; // Position to the right of pause button area
mainMenuButton.y = 50;
LK.gui.addChild(mainMenuButton);
// Add touch handler for main menu button
mainMenuButton.down = function (x, y, obj) {
// Reset game state and show start screen
gameStarted = false;
// Hide altitude and score text when returning to main menu
scoreText.visible = false;
altitudeText.visible = false;
// Clear all game objects
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
}
obstacles = [];
for (var s = stars.length - 1; s >= 0; s--) {
stars[s].destroy();
}
stars = [];
for (var sp = sparks.length - 1; sp >= 0; sp--) {
sparks[sp].destroy();
}
sparks = [];
for (var f = fuelPickups.length - 1; f >= 0; f--) {
fuelPickups[f].destroy();
}
fuelPickups = [];
for (var c = coins.length - 1; c >= 0; c--) {
coins[c].destroy();
}
coins = [];
// Reset game variables
altitude = 0;
scrollSpeed = 6;
spawnTimer = 0;
spawnRate = 120;
gameSpeed = 1;
currentHealth = 100;
currentFuel = 100;
LK.setScore(0);
// Reset spaceship position
spaceship.x = 1024;
spaceship.y = 2400;
spaceship.targetX = 1024;
// Reset health bar
var healthPercent = currentHealth / maxHealth;
healthBarFill.scaleX = healthPercent;
healthBarFill.x = 1024 - 148 + 296 * healthPercent * 0.5;
// Reset fuel bar
var fuelPercent = currentFuel / maxFuel;
fuelBarFill.scaleY = fuelPercent;
fuelBarFill.y = 302 + 1596 * (1 - fuelPercent);
// Show start screen
createStartScreen();
};
// Initialize start screen and start background music
createStartScreen();
LK.playMusic('space_music');