/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Asteroid var Asteroid = Container.expand(function () { var self = Container.call(this); var rock = self.attachAsset('asteroid', { anchorX: 0.5, anchorY: 0.5 }); self.width = rock.width; self.height = rock.height; self.speed = 10 + Math.random() * 6; self.rotationSpeed = (Math.random() - 0.5) * 0.1; self.update = function () { self.y += self.speed; rock.rotation += self.rotationSpeed; }; return self; }); // Enemy Bullet var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.width = bullet.width; self.height = bullet.height; self.speed = 22; self.update = function () { self.y += self.speed; }; return self; }); // Enemy Ship var EnemyShip = Container.expand(function () { var self = Container.call(this); var ship = self.attachAsset('enemyShip', { anchorX: 0.5, anchorY: 0.5 }); self.width = ship.width; self.height = ship.height; self.speed = 7 + Math.random() * 4; self.shootCooldown = 60 + Math.floor(Math.random() * 60); self.update = function () { self.y += self.speed; if (self.shootCooldown > 0) { self.shootCooldown--; } else { self.shoot(); self.shootCooldown = 90 + Math.floor(Math.random() * 60); } }; self.shoot = function () { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y + self.height / 2 + bullet.height / 2; enemyBullets.push(bullet); game.addChild(bullet); }; return self; }); // HeartDrop (falling heart item) var HeartDrop = Container.expand(function () { var self = Container.call(this); var heart = self.attachAsset('heart', { anchorX: 0.5, anchorY: 0.5 }); self.width = heart.width; self.height = heart.height; self.speed = 10; self.update = function () { self.y += self.speed; }; return self; }); // Player Bullet var PlayerBullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5 }); self.width = bullet.width; self.height = bullet.height; self.speed = -36; self.update = function () { self.y += self.speed; }; return self; }); // Player Ship var PlayerShip = Container.expand(function () { var self = Container.call(this); var ship = self.attachAsset('playerShip', { anchorX: 0.5, anchorY: 0.5 }); self.width = ship.width; self.height = ship.height; self.shootCooldown = 0; self.invincible = false; self.invincibleTicks = 0; self.update = function () { if (self.shootCooldown > 0) self.shootCooldown--; if (self.invincible) { self.invincibleTicks--; if (self.invincibleTicks <= 0) { self.invincible = false; ship.alpha = 1; } else { // Flicker effect ship.alpha = LK.ticks % 10 < 5 ? 0.4 : 1; } } }; // Shoot method self.shoot = function () { if (self.shootCooldown <= 0) { // Shoot 6 bullets, evenly spread (performance optimized) var bulletCount = 6; var spread = 120; // total spread in pixels for (var i = 0; i < bulletCount; i++) { var offset = -spread / 2 + spread / (bulletCount - 1) * i; var bullet = new PlayerBullet(); bullet.x = self.x + offset; bullet.y = self.y - self.height / 2 - bullet.height / 2; playerBullets.push(bullet); game.addChild(bullet); } LK.getSound('shoot').play(); self.shootCooldown = 12; // 12 ticks cooldown } }; // Invincibility after hit self.setInvincible = function (ticks) { self.invincible = true; self.invincibleTicks = ticks; }; // Add down handler so clicking the ship makes it shoot self.down = function (x, y, obj) { // Only allow shooting if game is not over if (typeof gameOver !== "undefined" && !gameOver) { self.shoot(); } }; return self; }); // Powerup var Powerup = Container.expand(function () { var self = Container.call(this); var p = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); self.width = p.width; self.height = p.height; self.speed = 9; self.update = function () { self.y += self.speed; }; return self; }); // Star (background) var Star = Container.expand(function () { var self = Container.call(this); // Use a white ellipse as a star, random small size var size = 2 + Math.random() * 4; var star = self.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, width: size, height: size, color: 0xffffff }); self.width = size; self.height = size; self.speed = 2 + Math.random() * 4; self.alpha = 0.3 + Math.random() * 0.5; self.update = function () { self.y += self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Play background music // Spaceship (player) // Player bullet // Enemy ship // Enemy bullet // Asteroid // Power-up // Explosion effect (for flash) // Sounds // Music LK.playMusic('galacticMusic'); // Game variables var stars = []; var starTick = 0; var player; var playerBullets = []; var enemyShips = []; var enemyBullets = []; var asteroids = []; var powerups = []; var score = 0; var lives = 30; var level = 1; var spawnTick = 0; var asteroidTick = 0; var powerupTick = 0; var heartDropTick = 0; var heartDrops = []; var dragging = false; var dragOffsetX = 0; var dragOffsetY = 0; var lastTouchX = 0; var lastTouchY = 0; var gameOver = false; // Score display var scoreTxt = new Text2('0', { size: 100, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Lives display var livesTxt = new Text2('♥♥♥', { size: 80, fill: 0xFF6666 }); livesTxt.anchor.set(1, 0); LK.gui.topRight.addChild(livesTxt); // Add a heart image next to the lives text var heartIcon = LK.getAsset('heart', { anchorX: 1, anchorY: 0, x: -80, y: 0, width: 60, height: 60 }); livesTxt.addChild(heartIcon); // Center player at bottom center player = new PlayerShip(); player.x = 2048 / 2; player.y = 2732 - 300; game.addChild(player); // Touch controls game.down = function (x, y, obj) { if (gameOver) return; // Only start drag if touch is on player var local = player.toLocal(game.toGlobal({ x: x, y: y })); if (local.x > -player.width / 2 && local.x < player.width / 2 && local.y > -player.height / 2 && local.y < player.height / 2) { dragging = true; dragOffsetX = player.x - x; dragOffsetY = player.y - y; } lastTouchX = x; lastTouchY = y; }; game.move = function (x, y, obj) { if (gameOver) return; // Make the player ship follow the mouse/touch position directly, clamped to screen bounds var halfW = player.width / 2; var halfH = player.height / 2; var newX = x; var newY = y; if (newX < halfW) newX = halfW; if (newX > 2048 - halfW) newX = 2048 - halfW; if (newY < halfH + 200) newY = halfH + 200; // Don't allow too high if (newY > 2732 - halfH) newY = 2732 - halfH; player.x = newX; player.y = newY; lastTouchX = x; lastTouchY = y; }; game.up = function (x, y, obj) { dragging = false; lastTouchX = x; lastTouchY = y; }; // Tap to shoot (anywhere) game.tap = function (x, y, obj) { if (gameOver) return; player.shoot(); }; // For compatibility, also allow shooting on down if not dragging game.down = function (origDown) { return function (x, y, obj) { origDown(x, y, obj); if (!dragging && !gameOver) { player.shoot(); } }; }(game.down); // Main update loop game.update = function () { // --- Star background update --- starTick++; // Spawn a new star every 6-10 ticks (slower for performance) if (starTick >= 6 + Math.floor(Math.random() * 5)) { starTick = 0; var s = new Star(); s.x = 10 + Math.random() * (2048 - 20); s.y = -s.height; s.alpha = 0.3 + Math.random() * 0.5; stars.push(s); // Add to back of display list (background) game.addChildAt(s, 0); } // Update and remove off-screen stars for (var i = stars.length - 1; i >= 0; i--) { var s = stars[i]; s.update(); if (s.y > 2732 + s.height) { s.destroy(); stars.splice(i, 1); } } if (gameOver) return; // Update player player.update(); // Auto-shoot: player fires every update if not on cooldown and not game over if (!gameOver) { player.shoot(); } // Update player bullets // Limit max bullets for performance var maxPlayerBullets = 60; if (playerBullets.length > maxPlayerBullets) { // Remove oldest bullets if over limit for (var rm = 0; rm < playerBullets.length - maxPlayerBullets; rm++) { var oldB = playerBullets[rm]; oldB.destroy(); } playerBullets.splice(0, playerBullets.length - maxPlayerBullets); } for (var i = playerBullets.length - 1; i >= 0; i--) { var b = playerBullets[i]; b.update(); // Remove if off screen if (b.y < -b.height) { b.destroy(); playerBullets.splice(i, 1); continue; } // Check collision with enemies for (var j = enemyShips.length - 1; j >= 0; j--) { var e = enemyShips[j]; if (b.intersects(e)) { // Destroy enemy LK.getSound('enemyExplode').play(); score += 100; scoreTxt.setText(score); // Flash enemy LK.effects.flashObject(e, 0xffffff, 200); e.destroy(); enemyShips.splice(j, 1); // Remove bullet b.destroy(); playerBullets.splice(i, 1); break; } } // Check collision with asteroids for (var k = asteroids.length - 1; k >= 0; k--) { var a = asteroids[k]; if (b.intersects(a)) { // Destroy asteroid LK.getSound('enemyExplode').play(); score += 50; scoreTxt.setText(score); LK.effects.flashObject(a, 0xffffff, 150); a.destroy(); asteroids.splice(k, 1); // Remove bullet b.destroy(); playerBullets.splice(i, 1); break; } } } // Update enemy ships for (var i = enemyShips.length - 1; i >= 0; i--) { var e = enemyShips[i]; e.update(); // Remove if off screen if (e.y > 2732 + e.height) { e.destroy(); enemyShips.splice(i, 1); continue; } // Check collision with player if (!player.invincible && e.intersects(player)) { handlePlayerHit(); e.destroy(); enemyShips.splice(i, 1); continue; } } // Update enemy bullets for (var i = enemyBullets.length - 1; i >= 0; i--) { var b = enemyBullets[i]; b.update(); if (b.y > 2732 + b.height) { b.destroy(); enemyBullets.splice(i, 1); continue; } if (!player.invincible && b.intersects(player)) { handlePlayerHit(); b.destroy(); enemyBullets.splice(i, 1); continue; } } // Update asteroids for (var i = asteroids.length - 1; i >= 0; i--) { var a = asteroids[i]; a.update(); if (a.y > 2732 + a.height) { a.destroy(); asteroids.splice(i, 1); continue; } if (!player.invincible && a.intersects(player)) { handlePlayerHit(); a.destroy(); asteroids.splice(i, 1); continue; } } // Update powerups for (var i = powerups.length - 1; i >= 0; i--) { var p = powerups[i]; p.update(); if (p.y > 2732 + p.height) { p.destroy(); powerups.splice(i, 1); continue; } if (p.intersects(player)) { LK.getSound('powerup').play(); score += 250; scoreTxt.setText(score); // Grant temporary invincibility player.setInvincible(120); p.destroy(); powerups.splice(i, 1); continue; } } // Update heart drops for (var i = heartDrops.length - 1; i >= 0; i--) { var h = heartDrops[i]; h.update(); if (h.y > 2732 + h.height) { h.destroy(); heartDrops.splice(i, 1); continue; } if (h.intersects(player)) { // Collect heart: +1 life, max 30 if (lives < 30) { lives++; updateLivesDisplay(); } h.destroy(); heartDrops.splice(i, 1); continue; } } // Spawning logic spawnTick++; asteroidTick++; powerupTick++; // Enemy spawn var enemyInterval = Math.max(60, 180 - level * 10); if (spawnTick >= enemyInterval) { spawnTick = 0; var e = new EnemyShip(); e.x = 200 + Math.random() * (2048 - 400); e.y = -e.height; enemyShips.push(e); game.addChild(e); } // Asteroid spawn var asteroidInterval = Math.max(80, 220 - level * 8); if (asteroidTick >= asteroidInterval) { asteroidTick = 0; var a = new Asteroid(); a.x = 100 + Math.random() * (2048 - 200); a.y = -a.height; asteroids.push(a); game.addChild(a); } // Powerup spawn if (powerupTick >= 900) { powerupTick = 0; var p = new Powerup(); p.x = 200 + Math.random() * (2048 - 400); p.y = -p.height; powerups.push(p); game.addChild(p); } // Heart drop spawn (random, about every 400-700 ticks) heartDropTick++; if (heartDropTick >= 400 + Math.floor(Math.random() * 300)) { heartDropTick = 0; var h = new HeartDrop(); h.x = 200 + Math.random() * (2048 - 400); h.y = -h.height; heartDrops.push(h); game.addChild(h); } // Level up every 1000 points var newLevel = Math.floor(score / 1000) + 1; if (newLevel > level) { level = newLevel; // Optionally, flash screen or show level up LK.effects.flashScreen(0x00ffcc, 400); } }; // Handle player hit function handlePlayerHit() { if (player.invincible) return; lives--; updateLivesDisplay(); LK.getSound('playerExplode').play(); LK.effects.flashScreen(0xff0000, 600); player.setInvincible(90); if (lives <= 0) { endGame(); } } // Update lives display function updateLivesDisplay() { var s = ''; for (var i = 0; i < lives; i++) s += '♥'; livesTxt.setText(s); } // End game function endGame() { gameOver = true; LK.showGameOver(); } // Reset game state on restart game.on('reset', function () { // Remove all objects for (var i = 0; i < stars.length; i++) stars[i].destroy(); for (var i = 0; i < playerBullets.length; i++) playerBullets[i].destroy(); for (var i = 0; i < enemyShips.length; i++) enemyShips[i].destroy(); for (var i = 0; i < enemyBullets.length; i++) enemyBullets[i].destroy(); for (var i = 0; i < asteroids.length; i++) asteroids[i].destroy(); for (var i = 0; i < powerups.length; i++) powerups[i].destroy(); for (var i = 0; i < heartDrops.length; i++) heartDrops[i].destroy(); stars = []; playerBullets = []; enemyShips = []; enemyBullets = []; asteroids = []; powerups = []; heartDrops = []; score = 0; level = 1; lives = 30; spawnTick = 0; asteroidTick = 0; powerupTick = 0; heartDropTick = 0; starTick = 0; dragging = false; gameOver = false; scoreTxt.setText('0'); updateLivesDisplay(); player.x = 2048 / 2; player.y = 2732 - 300; player.invincible = false; player.invincibleTicks = 0; LK.playMusic('galacticMusic'); }); // For touch devices, allow tap to shoot game.on('tap', function (x, y, obj) { if (gameOver) return; player.shoot(); });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Asteroid
var Asteroid = Container.expand(function () {
var self = Container.call(this);
var rock = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = rock.width;
self.height = rock.height;
self.speed = 10 + Math.random() * 6;
self.rotationSpeed = (Math.random() - 0.5) * 0.1;
self.update = function () {
self.y += self.speed;
rock.rotation += self.rotationSpeed;
};
return self;
});
// Enemy Bullet
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = bullet.width;
self.height = bullet.height;
self.speed = 22;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Enemy Ship
var EnemyShip = Container.expand(function () {
var self = Container.call(this);
var ship = self.attachAsset('enemyShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = ship.width;
self.height = ship.height;
self.speed = 7 + Math.random() * 4;
self.shootCooldown = 60 + Math.floor(Math.random() * 60);
self.update = function () {
self.y += self.speed;
if (self.shootCooldown > 0) {
self.shootCooldown--;
} else {
self.shoot();
self.shootCooldown = 90 + Math.floor(Math.random() * 60);
}
};
self.shoot = function () {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + self.height / 2 + bullet.height / 2;
enemyBullets.push(bullet);
game.addChild(bullet);
};
return self;
});
// HeartDrop (falling heart item)
var HeartDrop = Container.expand(function () {
var self = Container.call(this);
var heart = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = heart.width;
self.height = heart.height;
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player Bullet
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = bullet.width;
self.height = bullet.height;
self.speed = -36;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player Ship
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
var ship = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = ship.width;
self.height = ship.height;
self.shootCooldown = 0;
self.invincible = false;
self.invincibleTicks = 0;
self.update = function () {
if (self.shootCooldown > 0) self.shootCooldown--;
if (self.invincible) {
self.invincibleTicks--;
if (self.invincibleTicks <= 0) {
self.invincible = false;
ship.alpha = 1;
} else {
// Flicker effect
ship.alpha = LK.ticks % 10 < 5 ? 0.4 : 1;
}
}
};
// Shoot method
self.shoot = function () {
if (self.shootCooldown <= 0) {
// Shoot 6 bullets, evenly spread (performance optimized)
var bulletCount = 6;
var spread = 120; // total spread in pixels
for (var i = 0; i < bulletCount; i++) {
var offset = -spread / 2 + spread / (bulletCount - 1) * i;
var bullet = new PlayerBullet();
bullet.x = self.x + offset;
bullet.y = self.y - self.height / 2 - bullet.height / 2;
playerBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('shoot').play();
self.shootCooldown = 12; // 12 ticks cooldown
}
};
// Invincibility after hit
self.setInvincible = function (ticks) {
self.invincible = true;
self.invincibleTicks = ticks;
};
// Add down handler so clicking the ship makes it shoot
self.down = function (x, y, obj) {
// Only allow shooting if game is not over
if (typeof gameOver !== "undefined" && !gameOver) {
self.shoot();
}
};
return self;
});
// Powerup
var Powerup = Container.expand(function () {
var self = Container.call(this);
var p = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = p.width;
self.height = p.height;
self.speed = 9;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Star (background)
var Star = Container.expand(function () {
var self = Container.call(this);
// Use a white ellipse as a star, random small size
var size = 2 + Math.random() * 4;
var star = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: size,
height: size,
color: 0xffffff
});
self.width = size;
self.height = size;
self.speed = 2 + Math.random() * 4;
self.alpha = 0.3 + Math.random() * 0.5;
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Play background music
// Spaceship (player)
// Player bullet
// Enemy ship
// Enemy bullet
// Asteroid
// Power-up
// Explosion effect (for flash)
// Sounds
// Music
LK.playMusic('galacticMusic');
// Game variables
var stars = [];
var starTick = 0;
var player;
var playerBullets = [];
var enemyShips = [];
var enemyBullets = [];
var asteroids = [];
var powerups = [];
var score = 0;
var lives = 30;
var level = 1;
var spawnTick = 0;
var asteroidTick = 0;
var powerupTick = 0;
var heartDropTick = 0;
var heartDrops = [];
var dragging = false;
var dragOffsetX = 0;
var dragOffsetY = 0;
var lastTouchX = 0;
var lastTouchY = 0;
var gameOver = false;
// Score display
var scoreTxt = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Lives display
var livesTxt = new Text2('♥♥♥', {
size: 80,
fill: 0xFF6666
});
livesTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(livesTxt);
// Add a heart image next to the lives text
var heartIcon = LK.getAsset('heart', {
anchorX: 1,
anchorY: 0,
x: -80,
y: 0,
width: 60,
height: 60
});
livesTxt.addChild(heartIcon);
// Center player at bottom center
player = new PlayerShip();
player.x = 2048 / 2;
player.y = 2732 - 300;
game.addChild(player);
// Touch controls
game.down = function (x, y, obj) {
if (gameOver) return;
// Only start drag if touch is on player
var local = player.toLocal(game.toGlobal({
x: x,
y: y
}));
if (local.x > -player.width / 2 && local.x < player.width / 2 && local.y > -player.height / 2 && local.y < player.height / 2) {
dragging = true;
dragOffsetX = player.x - x;
dragOffsetY = player.y - y;
}
lastTouchX = x;
lastTouchY = y;
};
game.move = function (x, y, obj) {
if (gameOver) return;
// Make the player ship follow the mouse/touch position directly, clamped to screen bounds
var halfW = player.width / 2;
var halfH = player.height / 2;
var newX = x;
var newY = y;
if (newX < halfW) newX = halfW;
if (newX > 2048 - halfW) newX = 2048 - halfW;
if (newY < halfH + 200) newY = halfH + 200; // Don't allow too high
if (newY > 2732 - halfH) newY = 2732 - halfH;
player.x = newX;
player.y = newY;
lastTouchX = x;
lastTouchY = y;
};
game.up = function (x, y, obj) {
dragging = false;
lastTouchX = x;
lastTouchY = y;
};
// Tap to shoot (anywhere)
game.tap = function (x, y, obj) {
if (gameOver) return;
player.shoot();
};
// For compatibility, also allow shooting on down if not dragging
game.down = function (origDown) {
return function (x, y, obj) {
origDown(x, y, obj);
if (!dragging && !gameOver) {
player.shoot();
}
};
}(game.down);
// Main update loop
game.update = function () {
// --- Star background update ---
starTick++;
// Spawn a new star every 6-10 ticks (slower for performance)
if (starTick >= 6 + Math.floor(Math.random() * 5)) {
starTick = 0;
var s = new Star();
s.x = 10 + Math.random() * (2048 - 20);
s.y = -s.height;
s.alpha = 0.3 + Math.random() * 0.5;
stars.push(s);
// Add to back of display list (background)
game.addChildAt(s, 0);
}
// Update and remove off-screen stars
for (var i = stars.length - 1; i >= 0; i--) {
var s = stars[i];
s.update();
if (s.y > 2732 + s.height) {
s.destroy();
stars.splice(i, 1);
}
}
if (gameOver) return;
// Update player
player.update();
// Auto-shoot: player fires every update if not on cooldown and not game over
if (!gameOver) {
player.shoot();
}
// Update player bullets
// Limit max bullets for performance
var maxPlayerBullets = 60;
if (playerBullets.length > maxPlayerBullets) {
// Remove oldest bullets if over limit
for (var rm = 0; rm < playerBullets.length - maxPlayerBullets; rm++) {
var oldB = playerBullets[rm];
oldB.destroy();
}
playerBullets.splice(0, playerBullets.length - maxPlayerBullets);
}
for (var i = playerBullets.length - 1; i >= 0; i--) {
var b = playerBullets[i];
b.update();
// Remove if off screen
if (b.y < -b.height) {
b.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check collision with enemies
for (var j = enemyShips.length - 1; j >= 0; j--) {
var e = enemyShips[j];
if (b.intersects(e)) {
// Destroy enemy
LK.getSound('enemyExplode').play();
score += 100;
scoreTxt.setText(score);
// Flash enemy
LK.effects.flashObject(e, 0xffffff, 200);
e.destroy();
enemyShips.splice(j, 1);
// Remove bullet
b.destroy();
playerBullets.splice(i, 1);
break;
}
}
// Check collision with asteroids
for (var k = asteroids.length - 1; k >= 0; k--) {
var a = asteroids[k];
if (b.intersects(a)) {
// Destroy asteroid
LK.getSound('enemyExplode').play();
score += 50;
scoreTxt.setText(score);
LK.effects.flashObject(a, 0xffffff, 150);
a.destroy();
asteroids.splice(k, 1);
// Remove bullet
b.destroy();
playerBullets.splice(i, 1);
break;
}
}
}
// Update enemy ships
for (var i = enemyShips.length - 1; i >= 0; i--) {
var e = enemyShips[i];
e.update();
// Remove if off screen
if (e.y > 2732 + e.height) {
e.destroy();
enemyShips.splice(i, 1);
continue;
}
// Check collision with player
if (!player.invincible && e.intersects(player)) {
handlePlayerHit();
e.destroy();
enemyShips.splice(i, 1);
continue;
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var b = enemyBullets[i];
b.update();
if (b.y > 2732 + b.height) {
b.destroy();
enemyBullets.splice(i, 1);
continue;
}
if (!player.invincible && b.intersects(player)) {
handlePlayerHit();
b.destroy();
enemyBullets.splice(i, 1);
continue;
}
}
// Update asteroids
for (var i = asteroids.length - 1; i >= 0; i--) {
var a = asteroids[i];
a.update();
if (a.y > 2732 + a.height) {
a.destroy();
asteroids.splice(i, 1);
continue;
}
if (!player.invincible && a.intersects(player)) {
handlePlayerHit();
a.destroy();
asteroids.splice(i, 1);
continue;
}
}
// Update powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var p = powerups[i];
p.update();
if (p.y > 2732 + p.height) {
p.destroy();
powerups.splice(i, 1);
continue;
}
if (p.intersects(player)) {
LK.getSound('powerup').play();
score += 250;
scoreTxt.setText(score);
// Grant temporary invincibility
player.setInvincible(120);
p.destroy();
powerups.splice(i, 1);
continue;
}
}
// Update heart drops
for (var i = heartDrops.length - 1; i >= 0; i--) {
var h = heartDrops[i];
h.update();
if (h.y > 2732 + h.height) {
h.destroy();
heartDrops.splice(i, 1);
continue;
}
if (h.intersects(player)) {
// Collect heart: +1 life, max 30
if (lives < 30) {
lives++;
updateLivesDisplay();
}
h.destroy();
heartDrops.splice(i, 1);
continue;
}
}
// Spawning logic
spawnTick++;
asteroidTick++;
powerupTick++;
// Enemy spawn
var enemyInterval = Math.max(60, 180 - level * 10);
if (spawnTick >= enemyInterval) {
spawnTick = 0;
var e = new EnemyShip();
e.x = 200 + Math.random() * (2048 - 400);
e.y = -e.height;
enemyShips.push(e);
game.addChild(e);
}
// Asteroid spawn
var asteroidInterval = Math.max(80, 220 - level * 8);
if (asteroidTick >= asteroidInterval) {
asteroidTick = 0;
var a = new Asteroid();
a.x = 100 + Math.random() * (2048 - 200);
a.y = -a.height;
asteroids.push(a);
game.addChild(a);
}
// Powerup spawn
if (powerupTick >= 900) {
powerupTick = 0;
var p = new Powerup();
p.x = 200 + Math.random() * (2048 - 400);
p.y = -p.height;
powerups.push(p);
game.addChild(p);
}
// Heart drop spawn (random, about every 400-700 ticks)
heartDropTick++;
if (heartDropTick >= 400 + Math.floor(Math.random() * 300)) {
heartDropTick = 0;
var h = new HeartDrop();
h.x = 200 + Math.random() * (2048 - 400);
h.y = -h.height;
heartDrops.push(h);
game.addChild(h);
}
// Level up every 1000 points
var newLevel = Math.floor(score / 1000) + 1;
if (newLevel > level) {
level = newLevel;
// Optionally, flash screen or show level up
LK.effects.flashScreen(0x00ffcc, 400);
}
};
// Handle player hit
function handlePlayerHit() {
if (player.invincible) return;
lives--;
updateLivesDisplay();
LK.getSound('playerExplode').play();
LK.effects.flashScreen(0xff0000, 600);
player.setInvincible(90);
if (lives <= 0) {
endGame();
}
}
// Update lives display
function updateLivesDisplay() {
var s = '';
for (var i = 0; i < lives; i++) s += '♥';
livesTxt.setText(s);
}
// End game
function endGame() {
gameOver = true;
LK.showGameOver();
}
// Reset game state on restart
game.on('reset', function () {
// Remove all objects
for (var i = 0; i < stars.length; i++) stars[i].destroy();
for (var i = 0; i < playerBullets.length; i++) playerBullets[i].destroy();
for (var i = 0; i < enemyShips.length; i++) enemyShips[i].destroy();
for (var i = 0; i < enemyBullets.length; i++) enemyBullets[i].destroy();
for (var i = 0; i < asteroids.length; i++) asteroids[i].destroy();
for (var i = 0; i < powerups.length; i++) powerups[i].destroy();
for (var i = 0; i < heartDrops.length; i++) heartDrops[i].destroy();
stars = [];
playerBullets = [];
enemyShips = [];
enemyBullets = [];
asteroids = [];
powerups = [];
heartDrops = [];
score = 0;
level = 1;
lives = 30;
spawnTick = 0;
asteroidTick = 0;
powerupTick = 0;
heartDropTick = 0;
starTick = 0;
dragging = false;
gameOver = false;
scoreTxt.setText('0');
updateLivesDisplay();
player.x = 2048 / 2;
player.y = 2732 - 300;
player.invincible = false;
player.invincibleTicks = 0;
LK.playMusic('galacticMusic');
});
// For touch devices, allow tap to shoot
game.on('tap', function (x, y, obj) {
if (gameOver) return;
player.shoot();
});
a cool ship. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
an asteroid. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
bullet. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
an evil futuristic looking ship. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
explosion of metal and fire cloud. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
fire bullet. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
green health plus. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
heart. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat