User prompt
make it less laggy
User prompt
quadriple that
User prompt
triple that
User prompt
make him shoot two bullets instead of one
User prompt
make the player automatically shoot
User prompt
spawn stars in the background
User prompt
make the heart falling more common
User prompt
make the heart fall with the rest of the items
User prompt
add a heart
User prompt
give the player 30 lives
User prompt
add stars to the background
User prompt
make the background space'
User prompt
make the shape of the ship a triangle
User prompt
make it so clicking the ship will make it shoot
User prompt
make the ship follow the mouse
Code edit (1 edits merged)
Please save this source code
User prompt
Galactic Defender
Initial prompt
a space shooter game
/**** * 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