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