User prompt
Also make the hearts visible on the screen
User prompt
OK, so for the power up a player can only have the minimum of three hearts if a player is down a heart and they get the power up they just get the third Heart
User prompt
And make the player automatically shoot
User prompt
The slider isn’t working out. It’s too glitchy.
User prompt
Make a slider at the bottom so it’s easier to control the player
User prompt
How about the power ups give the player an a heart
User prompt
make controls easyer
User prompt
make only a few players shoot
User prompt
make a slider so the player can move back and forth
User prompt
all of them are shooting at once how about only a few shoot
Code edit (1 edits merged)
Please save this source code
User prompt
Space Invader Blitz
Initial prompt
make a space invader like game
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Alien invader var Alien = Container.expand(function () { var self = Container.call(this); var alien = self.attachAsset('alien', { anchorX: 0.5, anchorY: 0.5 }); self.width = alien.width; self.height = alien.height; self.row = 0; self.col = 0; self.direction = 1; // 1: right, -1: left self.speed = 2; self.shootCooldown = 0; self.alive = true; // Alien shoots self.shoot = function () { var bullet = new AlienBullet(); bullet.x = self.x; bullet.y = self.y + self.height / 2 + bullet.height / 2; alienBullets.push(bullet); game.addChild(bullet); LK.getSound('alienShoot').play(); }; return self; }); // Alien bullet var AlienBullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('alienBullet', { anchorX: 0.5, anchorY: 0.5 }); self.width = bullet.width; self.height = bullet.height; self.speed = 18; self.update = function () { self.y += self.speed; }; return self; }); // Player spaceship var Player = 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.canShoot = true; self.shootCooldown = 0; self.lives = 3; self.invincible = false; self.invincibleTimer = 0; self.poweredUp = false; self.powerupTimer = 0; // Shoot a bullet self.shoot = function () { if (!self.canShoot) return; var bullet = new PlayerBullet(); bullet.x = self.x; bullet.y = self.y - self.height / 2 - bullet.height / 2; playerBullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); self.canShoot = false; self.shootCooldown = 18; // 18 ticks ~0.3s }; // Power-up effect self.activatePowerup = function () { self.poweredUp = true; self.powerupTimer = 360; // 6 seconds // Visual feedback: flash ship tween(self, { alpha: 0.5 }, { duration: 120, easing: tween.easeIn, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 120, easing: tween.easeOut }); } }); }; // Invincibility effect self.setInvincible = function (duration) { self.invincible = true; self.invincibleTimer = duration; // Visual feedback: flicker }; 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 = -18; self.update = function () { self.y += self.speed; }; return self; }); // Power-up 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 = 10; self.type = 'rapid'; // Only one type for MVP self.update = function () { self.y += self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000010 }); /**** * Game Code ****/ // Music // Sound effects // Power-up // Alien bullet // Player bullet // Alien invader // Spaceship (player) // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var PLAYER_Y = GAME_HEIGHT - 220; var ALIEN_ROWS = 4; var ALIEN_COLS = 8; var ALIEN_X_MARGIN = 120; var ALIEN_Y_MARGIN = 120; var ALIEN_SPACING_X = 180; var ALIEN_SPACING_Y = 160; var ALIEN_START_Y = 320; var ALIEN_MOVE_DOWN = 60; var ALIEN_BASE_SPEED = 2; var ALIEN_SPEEDUP_PER_WAVE = 0.5; var ALIEN_SHOOT_CHANCE = 0.008; // Per alien per tick var POWERUP_CHANCE = 0.015; // Per tick, if no powerup present // Game state var player; var aliens = []; var playerBullets = []; var alienBullets = []; var powerups = []; var wave = 1; var score = 0; var lives = 3; var gameOver = false; var youWin = false; var moveDir = 1; // 1: right, -1: left var moveDownPending = false; var alienSpeed = ALIEN_BASE_SPEED; var dragNode = null; var lastTouchX = 0; var lastTouchY = 0; // GUI var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Heart icons for lives var heartIcons = []; var heartSpacing = 120; for (var i = 0; i < 3; i++) { var heart = LK.getAsset('powerup', { anchorX: 0.5, anchorY: 0.5, x: 120 + i * heartSpacing, y: 100, scaleX: 0.7, scaleY: 0.7 }); LK.gui.top.addChild(heart); heartIcons.push(heart); } var livesTxt = new Text2('', { size: 100, fill: 0xFF4444 }); livesTxt.anchor.set(0.5, 0); LK.gui.topRight.addChild(livesTxt); var waveTxt = new Text2('Wave 1', { size: 80, fill: 0x00FFCC }); waveTxt.anchor.set(0.5, 0); LK.gui.top.addChild(waveTxt); // Helper: update GUI function updateGUI() { scoreTxt.setText(score); // Update heart icons visibility for (var i = 0; i < heartIcons.length; i++) { heartIcons[i].visible = i < lives; } var hearts = ''; for (var i = 0; i < lives; i++) hearts += '♥'; livesTxt.setText(hearts); waveTxt.setText('Wave ' + wave); } // Helper: spawn aliens in grid function spawnAliens() { aliens = []; var totalWidth = (ALIEN_COLS - 1) * ALIEN_SPACING_X; var startX = (GAME_WIDTH - totalWidth) / 2; for (var row = 0; row < ALIEN_ROWS; row++) { for (var col = 0; col < ALIEN_COLS; col++) { var alien = new Alien(); alien.x = startX + col * ALIEN_SPACING_X; alien.y = ALIEN_START_Y + row * ALIEN_SPACING_Y; alien.row = row; alien.col = col; alien.direction = moveDir; alien.speed = alienSpeed; aliens.push(alien); game.addChild(alien); } } } // Helper: start new wave function startWave() { alienSpeed = ALIEN_BASE_SPEED + (wave - 1) * ALIEN_SPEEDUP_PER_WAVE; spawnAliens(); moveDir = 1; moveDownPending = false; waveTxt.setText('Wave ' + wave); } // Helper: reset game function resetGame() { // Remove all objects for (var i = 0; i < aliens.length; i++) aliens[i].destroy(); for (var i = 0; i < playerBullets.length; i++) playerBullets[i].destroy(); for (var i = 0; i < alienBullets.length; i++) alienBullets[i].destroy(); for (var i = 0; i < powerups.length; i++) powerups[i].destroy(); aliens = []; playerBullets = []; alienBullets = []; powerups = []; wave = 1; score = 0; lives = 3; gameOver = false; youWin = false; updateGUI(); // Reset player if (player) player.destroy(); player = new Player(); player.x = GAME_WIDTH / 2; player.y = PLAYER_Y; game.addChild(player); startWave(); } // Helper: show game over function triggerGameOver() { if (gameOver) return; gameOver = true; LK.getSound('loseLife').play(); LK.effects.flashScreen(0xff0000, 1200); LK.showGameOver(); } // Helper: show win function triggerYouWin() { if (youWin) return; youWin = true; LK.effects.flashScreen(0x00ff00, 1200); LK.showYouWin(); } // Helper: spawn powerup function spawnPowerup() { var p = new Powerup(); p.x = 200 + Math.random() * (GAME_WIDTH - 400); p.y = 200; powerups.push(p); game.addChild(p); } // --- Start Screen Implementation --- var startScreenOverlay = new Container(); var startBg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: GAME_HEIGHT / 2, scaleX: 16, scaleY: 22, tint: 0x000010 }); startScreenOverlay.addChild(startBg); var titleTxt = new Text2('SPACE INVADERS', { size: 220, fill: 0xFFFF00 }); titleTxt.anchor.set(0.5, 0.5); titleTxt.x = GAME_WIDTH / 2; titleTxt.y = GAME_HEIGHT / 2 - 320; startScreenOverlay.addChild(titleTxt); // Decorative player ship (centered, above button) var decorPlayer = LK.getAsset('playerShip', { anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: GAME_HEIGHT / 2 - 80, scaleX: 1.2, scaleY: 1.2 }); startScreenOverlay.addChild(decorPlayer); // Decorative powerups (left and right of player ship) var decorPowerupLeft = LK.getAsset('powerup', { anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2 - 220, y: GAME_HEIGHT / 2 - 80, scaleX: 0.9, scaleY: 0.9 }); var decorPowerupRight = LK.getAsset('powerup', { anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2 + 220, y: GAME_HEIGHT / 2 - 80, scaleX: 0.9, scaleY: 0.9 }); startScreenOverlay.addChild(decorPowerupLeft); startScreenOverlay.addChild(decorPowerupRight); // Start button var startBtn = new Text2('Start', { size: 140, fill: 0x00FFCC, background: 0x222222, padding: 60, radius: 60 }); startBtn.anchor.set(0.5, 0.5); startBtn.x = GAME_WIDTH / 2; startBtn.y = GAME_HEIGHT / 2 + 120; startScreenOverlay.addChild(startBtn); // Start button press handler startBtn.down = function (x, y, obj) { if (!gameStarted) { gameStarted = true; startScreenOverlay.visible = false; resetGame(); LK.playMusic('arcadebg', { fade: { start: 0, end: 1, duration: 1200 } }); } }; // Decorative aliens removed from start screen var creditsTxt = new Text2('by FRVR', { size: 80, fill: 0x00FFCC }); creditsTxt.anchor.set(0.5, 0.5); creditsTxt.x = GAME_WIDTH / 2; creditsTxt.y = GAME_HEIGHT / 2 + 320; startScreenOverlay.addChild(creditsTxt); // No aliens on start screen! game.addChild(startScreenOverlay); // Ensure no aliens are deleted from the game on the start screen for (var i = 0; i < aliens.length; i++) { if (aliens[i]) { aliens[i].destroy(); } } aliens = []; var gameStarted = false; // Only allow tap to start when on start screen game.down = function (x, y, obj) { if (gameOver || youWin) return; // Check if touch is on player ship if (player && y > player.y - player.height / 2 && y < player.y + player.height / 2 && x > player.x - player.width / 2 && x < player.x + player.width / 2) { draggingPlayer = true; dragOffsetX = x - player.x; } else { // Tap elsewhere: do nothing (auto-shoot enabled) } }; // --- End Start Screen Implementation --- // Drag-to-move and tap-to-shoot controls var draggingPlayer = false; var dragOffsetX = 0; game.down = function (x, y, obj) { if (gameOver || youWin) return; // Check if touch is on player ship if (player && y > player.y - player.height / 2 && y < player.y + player.height / 2 && x > player.x - player.width / 2 && x < player.x + player.width / 2) { draggingPlayer = true; dragOffsetX = x - player.x; } else { // Tap elsewhere: do nothing (auto-shoot enabled) } }; game.move = function (x, y, obj) { if (draggingPlayer && !gameOver && !youWin) { // Clamp player within screen bounds var minX = player.width / 2; var maxX = GAME_WIDTH - player.width / 2; var newX = Math.max(minX, Math.min(x - dragOffsetX, maxX)); player.x = newX; } }; game.up = function (x, y, obj) { draggingPlayer = false; }; // Main game loop game.update = function () { if (gameOver || youWin) return; // Player auto-shooting if (player && !player.canShoot) { player.shootCooldown--; if (player.shootCooldown <= 0) player.canShoot = true; } if (player && player.canShoot) { player.shoot(); } // Powerup timer if (player && player.poweredUp) { player.powerupTimer--; if (player.powerupTimer <= 0) { player.poweredUp = false; } } // Invincibility timer if (player && player.invincible) { player.invincibleTimer--; // Flicker effect player.alpha = LK.ticks % 10 < 5 ? 0.4 : 1; if (player.invincibleTimer <= 0) { player.invincible = false; player.alpha = 1; } } // Move aliens var leftmost = GAME_WIDTH, rightmost = 0, bottommost = 0; for (var i = 0; i < aliens.length; i++) { var a = aliens[i]; if (!a.alive) continue; a.x += moveDir * alienSpeed; if (a.x - a.width / 2 < leftmost) leftmost = a.x - a.width / 2; if (a.x + a.width / 2 > rightmost) rightmost = a.x + a.width / 2; if (a.y + a.height / 2 > bottommost) bottommost = a.y + a.height / 2; } // Change direction if at edge if (!moveDownPending && (leftmost < ALIEN_X_MARGIN || rightmost > GAME_WIDTH - ALIEN_X_MARGIN)) { moveDir *= -1; moveDownPending = true; } if (moveDownPending) { for (var i = 0; i < aliens.length; i++) { var a = aliens[i]; if (!a.alive) continue; a.y += ALIEN_MOVE_DOWN; } moveDownPending = false; } // Aliens shoot randomly, but only bottom-most alive in each column can shoot var bottomAliens = {}; for (var i = 0; i < aliens.length; i++) { var a = aliens[i]; if (!a.alive) continue; // Track the bottom-most alive alien in each column if (!bottomAliens[a.col] || a.y > bottomAliens[a.col].y) { bottomAliens[a.col] = a; } } // Only allow a few (e.g. 2) random bottom aliens to shoot per tick var shootableAliens = []; for (var col in bottomAliens) { shootableAliens.push(bottomAliens[col]); } var maxShooters = 2; for (var s = 0; s < maxShooters && shootableAliens.length > 0; s++) { var idx = Math.floor(Math.random() * shootableAliens.length); var a = shootableAliens[idx]; if (Math.random() < ALIEN_SHOOT_CHANCE + 0.001 * wave) { a.shoot(); } shootableAliens.splice(idx, 1); } // Update player bullets 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 aliens for (var j = 0; j < aliens.length; j++) { var a = aliens[j]; if (!a.alive) continue; if (b.intersects(a)) { a.alive = false; a.visible = false; b.destroy(); playerBullets.splice(i, 1); LK.getSound('alienExplode').play(); score += 10; updateGUI(); break; } } } // Update alien bullets for (var i = alienBullets.length - 1; i >= 0; i--) { var b = alienBullets[i]; b.update(); // Remove if off screen if (b.y > GAME_HEIGHT + b.height) { b.destroy(); alienBullets.splice(i, 1); continue; } // Check collision with player if (player && !player.invincible && b.intersects(player)) { b.destroy(); alienBullets.splice(i, 1); // Lose life lives--; updateGUI(); LK.getSound('hit').play(); if (lives <= 0) { triggerGameOver(); return; } else { player.setInvincible(90); // 1.5s invincibility } } } // Update powerups for (var i = powerups.length - 1; i >= 0; i--) { var p = powerups[i]; p.update(); if (p.y > GAME_HEIGHT + p.height) { p.destroy(); powerups.splice(i, 1); continue; } if (p.intersects(player)) { LK.getSound('powerup').play(); // Only restore up to 3 hearts if (lives < 3) { lives = 3; updateGUI(); } p.destroy(); powerups.splice(i, 1); } } // Powerup spawn if (powerups.length === 0 && Math.random() < POWERUP_CHANCE) { spawnPowerup(); } // Check if aliens reach player for (var i = 0; i < aliens.length; i++) { var a = aliens[i]; if (!a.alive) continue; if (player && a.y + a.height / 2 >= player.y - player.height / 2) { triggerGameOver(); return; } } // Next wave if all aliens dead var anyAlive = false; for (var i = 0; i < aliens.length; i++) { if (aliens[i].alive) { anyAlive = true; break; } } if (!anyAlive) { wave++; if (wave > 10) { triggerYouWin(); return; } startWave(); } }; // Clean up on game over or reset game.on('destroy', function () { LK.stopMusic(); });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Alien invader
var Alien = Container.expand(function () {
var self = Container.call(this);
var alien = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = alien.width;
self.height = alien.height;
self.row = 0;
self.col = 0;
self.direction = 1; // 1: right, -1: left
self.speed = 2;
self.shootCooldown = 0;
self.alive = true;
// Alien shoots
self.shoot = function () {
var bullet = new AlienBullet();
bullet.x = self.x;
bullet.y = self.y + self.height / 2 + bullet.height / 2;
alienBullets.push(bullet);
game.addChild(bullet);
LK.getSound('alienShoot').play();
};
return self;
});
// Alien bullet
var AlienBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('alienBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = bullet.width;
self.height = bullet.height;
self.speed = 18;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player spaceship
var Player = 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.canShoot = true;
self.shootCooldown = 0;
self.lives = 3;
self.invincible = false;
self.invincibleTimer = 0;
self.poweredUp = false;
self.powerupTimer = 0;
// Shoot a bullet
self.shoot = function () {
if (!self.canShoot) return;
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - self.height / 2 - bullet.height / 2;
playerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
self.canShoot = false;
self.shootCooldown = 18; // 18 ticks ~0.3s
};
// Power-up effect
self.activatePowerup = function () {
self.poweredUp = true;
self.powerupTimer = 360; // 6 seconds
// Visual feedback: flash ship
tween(self, {
alpha: 0.5
}, {
duration: 120,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(self, {
alpha: 1
}, {
duration: 120,
easing: tween.easeOut
});
}
});
};
// Invincibility effect
self.setInvincible = function (duration) {
self.invincible = true;
self.invincibleTimer = duration;
// Visual feedback: flicker
};
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 = -18;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Power-up
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 = 10;
self.type = 'rapid'; // Only one type for MVP
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000010
});
/****
* Game Code
****/
// Music
// Sound effects
// Power-up
// Alien bullet
// Player bullet
// Alien invader
// Spaceship (player)
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var PLAYER_Y = GAME_HEIGHT - 220;
var ALIEN_ROWS = 4;
var ALIEN_COLS = 8;
var ALIEN_X_MARGIN = 120;
var ALIEN_Y_MARGIN = 120;
var ALIEN_SPACING_X = 180;
var ALIEN_SPACING_Y = 160;
var ALIEN_START_Y = 320;
var ALIEN_MOVE_DOWN = 60;
var ALIEN_BASE_SPEED = 2;
var ALIEN_SPEEDUP_PER_WAVE = 0.5;
var ALIEN_SHOOT_CHANCE = 0.008; // Per alien per tick
var POWERUP_CHANCE = 0.015; // Per tick, if no powerup present
// Game state
var player;
var aliens = [];
var playerBullets = [];
var alienBullets = [];
var powerups = [];
var wave = 1;
var score = 0;
var lives = 3;
var gameOver = false;
var youWin = false;
var moveDir = 1; // 1: right, -1: left
var moveDownPending = false;
var alienSpeed = ALIEN_BASE_SPEED;
var dragNode = null;
var lastTouchX = 0;
var lastTouchY = 0;
// GUI
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Heart icons for lives
var heartIcons = [];
var heartSpacing = 120;
for (var i = 0; i < 3; i++) {
var heart = LK.getAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
x: 120 + i * heartSpacing,
y: 100,
scaleX: 0.7,
scaleY: 0.7
});
LK.gui.top.addChild(heart);
heartIcons.push(heart);
}
var livesTxt = new Text2('', {
size: 100,
fill: 0xFF4444
});
livesTxt.anchor.set(0.5, 0);
LK.gui.topRight.addChild(livesTxt);
var waveTxt = new Text2('Wave 1', {
size: 80,
fill: 0x00FFCC
});
waveTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(waveTxt);
// Helper: update GUI
function updateGUI() {
scoreTxt.setText(score);
// Update heart icons visibility
for (var i = 0; i < heartIcons.length; i++) {
heartIcons[i].visible = i < lives;
}
var hearts = '';
for (var i = 0; i < lives; i++) hearts += '♥';
livesTxt.setText(hearts);
waveTxt.setText('Wave ' + wave);
}
// Helper: spawn aliens in grid
function spawnAliens() {
aliens = [];
var totalWidth = (ALIEN_COLS - 1) * ALIEN_SPACING_X;
var startX = (GAME_WIDTH - totalWidth) / 2;
for (var row = 0; row < ALIEN_ROWS; row++) {
for (var col = 0; col < ALIEN_COLS; col++) {
var alien = new Alien();
alien.x = startX + col * ALIEN_SPACING_X;
alien.y = ALIEN_START_Y + row * ALIEN_SPACING_Y;
alien.row = row;
alien.col = col;
alien.direction = moveDir;
alien.speed = alienSpeed;
aliens.push(alien);
game.addChild(alien);
}
}
}
// Helper: start new wave
function startWave() {
alienSpeed = ALIEN_BASE_SPEED + (wave - 1) * ALIEN_SPEEDUP_PER_WAVE;
spawnAliens();
moveDir = 1;
moveDownPending = false;
waveTxt.setText('Wave ' + wave);
}
// Helper: reset game
function resetGame() {
// Remove all objects
for (var i = 0; i < aliens.length; i++) aliens[i].destroy();
for (var i = 0; i < playerBullets.length; i++) playerBullets[i].destroy();
for (var i = 0; i < alienBullets.length; i++) alienBullets[i].destroy();
for (var i = 0; i < powerups.length; i++) powerups[i].destroy();
aliens = [];
playerBullets = [];
alienBullets = [];
powerups = [];
wave = 1;
score = 0;
lives = 3;
gameOver = false;
youWin = false;
updateGUI();
// Reset player
if (player) player.destroy();
player = new Player();
player.x = GAME_WIDTH / 2;
player.y = PLAYER_Y;
game.addChild(player);
startWave();
}
// Helper: show game over
function triggerGameOver() {
if (gameOver) return;
gameOver = true;
LK.getSound('loseLife').play();
LK.effects.flashScreen(0xff0000, 1200);
LK.showGameOver();
}
// Helper: show win
function triggerYouWin() {
if (youWin) return;
youWin = true;
LK.effects.flashScreen(0x00ff00, 1200);
LK.showYouWin();
}
// Helper: spawn powerup
function spawnPowerup() {
var p = new Powerup();
p.x = 200 + Math.random() * (GAME_WIDTH - 400);
p.y = 200;
powerups.push(p);
game.addChild(p);
}
// --- Start Screen Implementation ---
var startScreenOverlay = new Container();
var startBg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: GAME_WIDTH / 2,
y: GAME_HEIGHT / 2,
scaleX: 16,
scaleY: 22,
tint: 0x000010
});
startScreenOverlay.addChild(startBg);
var titleTxt = new Text2('SPACE INVADERS', {
size: 220,
fill: 0xFFFF00
});
titleTxt.anchor.set(0.5, 0.5);
titleTxt.x = GAME_WIDTH / 2;
titleTxt.y = GAME_HEIGHT / 2 - 320;
startScreenOverlay.addChild(titleTxt);
// Decorative player ship (centered, above button)
var decorPlayer = LK.getAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5,
x: GAME_WIDTH / 2,
y: GAME_HEIGHT / 2 - 80,
scaleX: 1.2,
scaleY: 1.2
});
startScreenOverlay.addChild(decorPlayer);
// Decorative powerups (left and right of player ship)
var decorPowerupLeft = LK.getAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
x: GAME_WIDTH / 2 - 220,
y: GAME_HEIGHT / 2 - 80,
scaleX: 0.9,
scaleY: 0.9
});
var decorPowerupRight = LK.getAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
x: GAME_WIDTH / 2 + 220,
y: GAME_HEIGHT / 2 - 80,
scaleX: 0.9,
scaleY: 0.9
});
startScreenOverlay.addChild(decorPowerupLeft);
startScreenOverlay.addChild(decorPowerupRight);
// Start button
var startBtn = new Text2('Start', {
size: 140,
fill: 0x00FFCC,
background: 0x222222,
padding: 60,
radius: 60
});
startBtn.anchor.set(0.5, 0.5);
startBtn.x = GAME_WIDTH / 2;
startBtn.y = GAME_HEIGHT / 2 + 120;
startScreenOverlay.addChild(startBtn);
// Start button press handler
startBtn.down = function (x, y, obj) {
if (!gameStarted) {
gameStarted = true;
startScreenOverlay.visible = false;
resetGame();
LK.playMusic('arcadebg', {
fade: {
start: 0,
end: 1,
duration: 1200
}
});
}
};
// Decorative aliens removed from start screen
var creditsTxt = new Text2('by FRVR', {
size: 80,
fill: 0x00FFCC
});
creditsTxt.anchor.set(0.5, 0.5);
creditsTxt.x = GAME_WIDTH / 2;
creditsTxt.y = GAME_HEIGHT / 2 + 320;
startScreenOverlay.addChild(creditsTxt);
// No aliens on start screen!
game.addChild(startScreenOverlay);
// Ensure no aliens are deleted from the game on the start screen
for (var i = 0; i < aliens.length; i++) {
if (aliens[i]) {
aliens[i].destroy();
}
}
aliens = [];
var gameStarted = false;
// Only allow tap to start when on start screen
game.down = function (x, y, obj) {
if (gameOver || youWin) return;
// Check if touch is on player ship
if (player && y > player.y - player.height / 2 && y < player.y + player.height / 2 && x > player.x - player.width / 2 && x < player.x + player.width / 2) {
draggingPlayer = true;
dragOffsetX = x - player.x;
} else {
// Tap elsewhere: do nothing (auto-shoot enabled)
}
};
// --- End Start Screen Implementation ---
// Drag-to-move and tap-to-shoot controls
var draggingPlayer = false;
var dragOffsetX = 0;
game.down = function (x, y, obj) {
if (gameOver || youWin) return;
// Check if touch is on player ship
if (player && y > player.y - player.height / 2 && y < player.y + player.height / 2 && x > player.x - player.width / 2 && x < player.x + player.width / 2) {
draggingPlayer = true;
dragOffsetX = x - player.x;
} else {
// Tap elsewhere: do nothing (auto-shoot enabled)
}
};
game.move = function (x, y, obj) {
if (draggingPlayer && !gameOver && !youWin) {
// Clamp player within screen bounds
var minX = player.width / 2;
var maxX = GAME_WIDTH - player.width / 2;
var newX = Math.max(minX, Math.min(x - dragOffsetX, maxX));
player.x = newX;
}
};
game.up = function (x, y, obj) {
draggingPlayer = false;
};
// Main game loop
game.update = function () {
if (gameOver || youWin) return;
// Player auto-shooting
if (player && !player.canShoot) {
player.shootCooldown--;
if (player.shootCooldown <= 0) player.canShoot = true;
}
if (player && player.canShoot) {
player.shoot();
}
// Powerup timer
if (player && player.poweredUp) {
player.powerupTimer--;
if (player.powerupTimer <= 0) {
player.poweredUp = false;
}
}
// Invincibility timer
if (player && player.invincible) {
player.invincibleTimer--;
// Flicker effect
player.alpha = LK.ticks % 10 < 5 ? 0.4 : 1;
if (player.invincibleTimer <= 0) {
player.invincible = false;
player.alpha = 1;
}
}
// Move aliens
var leftmost = GAME_WIDTH,
rightmost = 0,
bottommost = 0;
for (var i = 0; i < aliens.length; i++) {
var a = aliens[i];
if (!a.alive) continue;
a.x += moveDir * alienSpeed;
if (a.x - a.width / 2 < leftmost) leftmost = a.x - a.width / 2;
if (a.x + a.width / 2 > rightmost) rightmost = a.x + a.width / 2;
if (a.y + a.height / 2 > bottommost) bottommost = a.y + a.height / 2;
}
// Change direction if at edge
if (!moveDownPending && (leftmost < ALIEN_X_MARGIN || rightmost > GAME_WIDTH - ALIEN_X_MARGIN)) {
moveDir *= -1;
moveDownPending = true;
}
if (moveDownPending) {
for (var i = 0; i < aliens.length; i++) {
var a = aliens[i];
if (!a.alive) continue;
a.y += ALIEN_MOVE_DOWN;
}
moveDownPending = false;
}
// Aliens shoot randomly, but only bottom-most alive in each column can shoot
var bottomAliens = {};
for (var i = 0; i < aliens.length; i++) {
var a = aliens[i];
if (!a.alive) continue;
// Track the bottom-most alive alien in each column
if (!bottomAliens[a.col] || a.y > bottomAliens[a.col].y) {
bottomAliens[a.col] = a;
}
}
// Only allow a few (e.g. 2) random bottom aliens to shoot per tick
var shootableAliens = [];
for (var col in bottomAliens) {
shootableAliens.push(bottomAliens[col]);
}
var maxShooters = 2;
for (var s = 0; s < maxShooters && shootableAliens.length > 0; s++) {
var idx = Math.floor(Math.random() * shootableAliens.length);
var a = shootableAliens[idx];
if (Math.random() < ALIEN_SHOOT_CHANCE + 0.001 * wave) {
a.shoot();
}
shootableAliens.splice(idx, 1);
}
// Update player bullets
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 aliens
for (var j = 0; j < aliens.length; j++) {
var a = aliens[j];
if (!a.alive) continue;
if (b.intersects(a)) {
a.alive = false;
a.visible = false;
b.destroy();
playerBullets.splice(i, 1);
LK.getSound('alienExplode').play();
score += 10;
updateGUI();
break;
}
}
}
// Update alien bullets
for (var i = alienBullets.length - 1; i >= 0; i--) {
var b = alienBullets[i];
b.update();
// Remove if off screen
if (b.y > GAME_HEIGHT + b.height) {
b.destroy();
alienBullets.splice(i, 1);
continue;
}
// Check collision with player
if (player && !player.invincible && b.intersects(player)) {
b.destroy();
alienBullets.splice(i, 1);
// Lose life
lives--;
updateGUI();
LK.getSound('hit').play();
if (lives <= 0) {
triggerGameOver();
return;
} else {
player.setInvincible(90); // 1.5s invincibility
}
}
}
// Update powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var p = powerups[i];
p.update();
if (p.y > GAME_HEIGHT + p.height) {
p.destroy();
powerups.splice(i, 1);
continue;
}
if (p.intersects(player)) {
LK.getSound('powerup').play();
// Only restore up to 3 hearts
if (lives < 3) {
lives = 3;
updateGUI();
}
p.destroy();
powerups.splice(i, 1);
}
}
// Powerup spawn
if (powerups.length === 0 && Math.random() < POWERUP_CHANCE) {
spawnPowerup();
}
// Check if aliens reach player
for (var i = 0; i < aliens.length; i++) {
var a = aliens[i];
if (!a.alive) continue;
if (player && a.y + a.height / 2 >= player.y - player.height / 2) {
triggerGameOver();
return;
}
}
// Next wave if all aliens dead
var anyAlive = false;
for (var i = 0; i < aliens.length; i++) {
if (aliens[i].alive) {
anyAlive = true;
break;
}
}
if (!anyAlive) {
wave++;
if (wave > 10) {
triggerYouWin();
return;
}
startWave();
}
};
// Clean up on game over or reset
game.on('destroy', function () {
LK.stopMusic();
});