/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Alien 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.alive = true; self.shootCooldown = 0; self.update = function () { // No per-alien update needed; movement handled by global logic }; 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(); }; self.hit = function () { self.alive = false; LK.getSound('explosion').play(); LK.effects.flashObject(self, 0xffffff, 200); self.visible = false; }; 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 = 28; // Increased speed for harder gameplay 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 = -32; 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.canShoot = true; self.shootCooldown = 18; // frames between shots self.cooldownTimer = 0; self.lives = 3; self.invincible = false; self.invincibleTimer = 0; self.update = function () { if (self.cooldownTimer > 0) self.cooldownTimer--; if (self.invincible) { self.invincibleTimer--; if (self.invincibleTimer <= 0) { self.invincible = false; ship.alpha = 1; } else { ship.alpha = LK.ticks % 10 < 5 ? 0.4 : 1; } } }; self.shoot = function () { if (self.cooldownTimer === 0 && self.visible) { self.cooldownTimer = self.shootCooldown; 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.hit = function () { if (self.invincible) return; self.lives--; if (typeof updateLivesDisplay === "function") updateLivesDisplay(); if (self.lives <= 0) { LK.effects.flashScreen(0xff0000, 800); LK.getSound('explosion').play(); LK.showGameOver(); } else { self.invincible = true; self.invincibleTimer = 90; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Music // Sound effects // Powerup: purple ellipse // Alien bullet: red ellipse // Alien: green box // Player bullet: yellow ellipse // Player ship: blue box // Play music LK.playMusic('spacesong1', { loop: true }); // Score var score = 0; var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Lives display var livesTxt = new Text2('♥ x3', { size: 90, fill: 0xFF6666 }); livesTxt.anchor.set(0, 0); livesTxt.x = 120; livesTxt.y = 0; LK.gui.top.addChild(livesTxt); // Helper to update lives display function updateLivesDisplay() { livesTxt.setText('♥ x' + player.lives); } // Player var player = new PlayerShip(); player.x = 2048 / 2; player.y = 2732 - 180; game.addChild(player); if (typeof updateLivesDisplay === "function") updateLivesDisplay(); // Bullets and objects var playerBullets = []; var alienBullets = []; var aliens = []; // Alien grid var alienRows = 5; var alienCols = 8; var alienSpacingX = 180; var alienSpacingY = 120; var alienStartX = (2048 - (alienCols - 1) * alienSpacingX) / 2; var alienStartY = 320; var alienDir = 1; // 1: right, -1: left var alienSpeed = 12; // px per move var alienMoveDown = 60; // px to move down when hitting edge var alienMoveTimer = 0; var alienMoveInterval = 32; // frames between moves, decreases as aliens die var alienShootChance = 0.018; // chance per alien per move to shoot (increased for more frequent fire) function spawnAliens() { aliens.length = 0; for (var row = 0; row < alienRows; row++) { for (var col = 0; col < alienCols; col++) { var a = new Alien(); a.row = row; a.col = col; a.x = alienStartX + col * alienSpacingX; a.y = alienStartY + row * alienSpacingY; aliens.push(a); game.addChild(a); } } } spawnAliens(); // Dragging var dragging = false; var dragOffsetX = 0; // Move handler function handleMove(x, y, obj) { if (dragging) { var newX = x - dragOffsetX; // Clamp to screen var minX = player.width / 2 + 20; var maxX = 2048 - player.width / 2 - 20; player.x = Math.max(minX, Math.min(maxX, newX)); } } game.move = handleMove; game.down = function (x, y, obj) { // Only 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 = x - player.x; } }; game.up = function (x, y, obj) { dragging = false; }; // Tap to shoot game.tap = function (x, y, obj) { player.shoot(); }; // For mobile: allow tap anywhere to shoot game.down = function (x, y, obj) { // Drag if on player, else shoot 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 = x - player.x; } else { player.shoot(); } }; // Main update loop game.update = function () { // Player update player.update(); // Player bullets for (var i = playerBullets.length - 1; i >= 0; i--) { var b = playerBullets[i]; b.update(); if (b.y < -b.height) { b.destroy(); playerBullets.splice(i, 1); continue; } // Collide with aliens for (var j = 0; j < aliens.length; j++) { var a = aliens[j]; if (a.alive && b.intersects(a)) { a.hit(); b.destroy(); playerBullets.splice(i, 1); score += 100; scoreTxt.setText(score); break; } } } // Alien bullets for (var i = alienBullets.length - 1; i >= 0; i--) { var b = alienBullets[i]; b.update(); if (b.y > 2732 + b.height) { b.destroy(); alienBullets.splice(i, 1); continue; } // Collide with player if (b.intersects(player) && !player.invincible) { b.destroy(); alienBullets.splice(i, 1); player.hit(); break; } } // Aliens movement alienMoveTimer++; if (alienMoveTimer >= alienMoveInterval) { alienMoveTimer = 0; var minX = 99999, maxX = -99999; var minY = 99999, maxY = -99999; for (var i = 0; i < aliens.length; i++) { var a = aliens[i]; if (!a.alive) continue; minX = Math.min(minX, a.x - a.width / 2); maxX = Math.max(maxX, a.x + a.width / 2); minY = Math.min(minY, a.y - a.height / 2); maxY = Math.max(maxY, a.y + a.height / 2); } var edgeHit = false; if (alienDir === 1 && maxX + alienSpeed > 2048 - 40) edgeHit = true; if (alienDir === -1 && minX - alienSpeed < 40) edgeHit = true; if (edgeHit) { alienDir *= -1; for (var i = 0; i < aliens.length; i++) { var a = aliens[i]; if (a.alive) a.y += alienMoveDown; } } else { for (var i = 0; i < aliens.length; i++) { var a = aliens[i]; if (a.alive) a.x += alienDir * alienSpeed; } } // Aliens shoot for (var i = 0; i < aliens.length; i++) { var a = aliens[i]; if (!a.alive) continue; // Only bottom-most alien in column can shoot var isLowest = true; for (var j = 0; j < aliens.length; j++) { var b = aliens[j]; if (b.col === a.col && b.row > a.row && b.alive) { isLowest = false; break; } } if (isLowest && Math.random() < alienShootChance) { a.shoot(); } } // Check for aliens reaching bottom for (var i = 0; i < aliens.length; i++) { var a = aliens[i]; if (a.alive && a.y + a.height / 2 >= player.y - player.height / 2) { LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); return; } } // Speed up as aliens die var aliveCount = 0; for (var i = 0; i < aliens.length; i++) if (aliens[i].alive) aliveCount++; alienMoveInterval = Math.max(4, 32 - Math.floor((40 - aliveCount) / 2)); // Lower minimum interval for faster movement } // Infinite mode: respawn new wave and increase difficulty var allDead = true; for (var i = 0; i < aliens.length; i++) if (aliens[i].alive) allDead = false; if (allDead) { LK.effects.flashScreen(0x00ff00, 600); // Increase difficulty: more rows, faster, more chance to shoot if (alienRows < 8) alienRows++; if (alienCols < 12) alienCols++; alienShootChance = Math.min(0.06, alienShootChance + 0.004); // Increase max and ramp alienMoveInterval = Math.max(3, alienMoveInterval - 3); // Faster ramp spawnAliens(); // Remove all remaining alien bullets for (var i = alienBullets.length - 1; i >= 0; i--) { alienBullets[i].destroy(); alienBullets.splice(i, 1); } // Remove all player bullets for (var i = playerBullets.length - 1; i >= 0; i--) { playerBullets[i].destroy(); playerBullets.splice(i, 1); } // Reset alien movement alienMoveTimer = 0; // Give player a bonus life every 3 cleared waves (max 5) if (typeof wavesCleared === "undefined") wavesCleared = 0; wavesCleared++; if (wavesCleared % 3 === 0 && player.lives < 5) { player.lives++; LK.effects.flashObject(player, 0x66ff66, 800); if (typeof updateLivesDisplay === "function") updateLivesDisplay(); } return; } }; // Set initial score LK.setScore(0); scoreTxt.setText(0);
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Alien
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.alive = true;
self.shootCooldown = 0;
self.update = function () {
// No per-alien update needed; movement handled by global logic
};
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();
};
self.hit = function () {
self.alive = false;
LK.getSound('explosion').play();
LK.effects.flashObject(self, 0xffffff, 200);
self.visible = false;
};
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 = 28; // Increased speed for harder gameplay
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 = -32;
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.canShoot = true;
self.shootCooldown = 18; // frames between shots
self.cooldownTimer = 0;
self.lives = 3;
self.invincible = false;
self.invincibleTimer = 0;
self.update = function () {
if (self.cooldownTimer > 0) self.cooldownTimer--;
if (self.invincible) {
self.invincibleTimer--;
if (self.invincibleTimer <= 0) {
self.invincible = false;
ship.alpha = 1;
} else {
ship.alpha = LK.ticks % 10 < 5 ? 0.4 : 1;
}
}
};
self.shoot = function () {
if (self.cooldownTimer === 0 && self.visible) {
self.cooldownTimer = self.shootCooldown;
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.hit = function () {
if (self.invincible) return;
self.lives--;
if (typeof updateLivesDisplay === "function") updateLivesDisplay();
if (self.lives <= 0) {
LK.effects.flashScreen(0xff0000, 800);
LK.getSound('explosion').play();
LK.showGameOver();
} else {
self.invincible = true;
self.invincibleTimer = 90;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Music
// Sound effects
// Powerup: purple ellipse
// Alien bullet: red ellipse
// Alien: green box
// Player bullet: yellow ellipse
// Player ship: blue box
// Play music
LK.playMusic('spacesong1', {
loop: true
});
// Score
var score = 0;
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Lives display
var livesTxt = new Text2('♥ x3', {
size: 90,
fill: 0xFF6666
});
livesTxt.anchor.set(0, 0);
livesTxt.x = 120;
livesTxt.y = 0;
LK.gui.top.addChild(livesTxt);
// Helper to update lives display
function updateLivesDisplay() {
livesTxt.setText('♥ x' + player.lives);
}
// Player
var player = new PlayerShip();
player.x = 2048 / 2;
player.y = 2732 - 180;
game.addChild(player);
if (typeof updateLivesDisplay === "function") updateLivesDisplay();
// Bullets and objects
var playerBullets = [];
var alienBullets = [];
var aliens = [];
// Alien grid
var alienRows = 5;
var alienCols = 8;
var alienSpacingX = 180;
var alienSpacingY = 120;
var alienStartX = (2048 - (alienCols - 1) * alienSpacingX) / 2;
var alienStartY = 320;
var alienDir = 1; // 1: right, -1: left
var alienSpeed = 12; // px per move
var alienMoveDown = 60; // px to move down when hitting edge
var alienMoveTimer = 0;
var alienMoveInterval = 32; // frames between moves, decreases as aliens die
var alienShootChance = 0.018; // chance per alien per move to shoot (increased for more frequent fire)
function spawnAliens() {
aliens.length = 0;
for (var row = 0; row < alienRows; row++) {
for (var col = 0; col < alienCols; col++) {
var a = new Alien();
a.row = row;
a.col = col;
a.x = alienStartX + col * alienSpacingX;
a.y = alienStartY + row * alienSpacingY;
aliens.push(a);
game.addChild(a);
}
}
}
spawnAliens();
// Dragging
var dragging = false;
var dragOffsetX = 0;
// Move handler
function handleMove(x, y, obj) {
if (dragging) {
var newX = x - dragOffsetX;
// Clamp to screen
var minX = player.width / 2 + 20;
var maxX = 2048 - player.width / 2 - 20;
player.x = Math.max(minX, Math.min(maxX, newX));
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Only 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 = x - player.x;
}
};
game.up = function (x, y, obj) {
dragging = false;
};
// Tap to shoot
game.tap = function (x, y, obj) {
player.shoot();
};
// For mobile: allow tap anywhere to shoot
game.down = function (x, y, obj) {
// Drag if on player, else shoot
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 = x - player.x;
} else {
player.shoot();
}
};
// Main update loop
game.update = function () {
// Player update
player.update();
// Player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var b = playerBullets[i];
b.update();
if (b.y < -b.height) {
b.destroy();
playerBullets.splice(i, 1);
continue;
}
// Collide with aliens
for (var j = 0; j < aliens.length; j++) {
var a = aliens[j];
if (a.alive && b.intersects(a)) {
a.hit();
b.destroy();
playerBullets.splice(i, 1);
score += 100;
scoreTxt.setText(score);
break;
}
}
}
// Alien bullets
for (var i = alienBullets.length - 1; i >= 0; i--) {
var b = alienBullets[i];
b.update();
if (b.y > 2732 + b.height) {
b.destroy();
alienBullets.splice(i, 1);
continue;
}
// Collide with player
if (b.intersects(player) && !player.invincible) {
b.destroy();
alienBullets.splice(i, 1);
player.hit();
break;
}
}
// Aliens movement
alienMoveTimer++;
if (alienMoveTimer >= alienMoveInterval) {
alienMoveTimer = 0;
var minX = 99999,
maxX = -99999;
var minY = 99999,
maxY = -99999;
for (var i = 0; i < aliens.length; i++) {
var a = aliens[i];
if (!a.alive) continue;
minX = Math.min(minX, a.x - a.width / 2);
maxX = Math.max(maxX, a.x + a.width / 2);
minY = Math.min(minY, a.y - a.height / 2);
maxY = Math.max(maxY, a.y + a.height / 2);
}
var edgeHit = false;
if (alienDir === 1 && maxX + alienSpeed > 2048 - 40) edgeHit = true;
if (alienDir === -1 && minX - alienSpeed < 40) edgeHit = true;
if (edgeHit) {
alienDir *= -1;
for (var i = 0; i < aliens.length; i++) {
var a = aliens[i];
if (a.alive) a.y += alienMoveDown;
}
} else {
for (var i = 0; i < aliens.length; i++) {
var a = aliens[i];
if (a.alive) a.x += alienDir * alienSpeed;
}
}
// Aliens shoot
for (var i = 0; i < aliens.length; i++) {
var a = aliens[i];
if (!a.alive) continue;
// Only bottom-most alien in column can shoot
var isLowest = true;
for (var j = 0; j < aliens.length; j++) {
var b = aliens[j];
if (b.col === a.col && b.row > a.row && b.alive) {
isLowest = false;
break;
}
}
if (isLowest && Math.random() < alienShootChance) {
a.shoot();
}
}
// Check for aliens reaching bottom
for (var i = 0; i < aliens.length; i++) {
var a = aliens[i];
if (a.alive && a.y + a.height / 2 >= player.y - player.height / 2) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
// Speed up as aliens die
var aliveCount = 0;
for (var i = 0; i < aliens.length; i++) if (aliens[i].alive) aliveCount++;
alienMoveInterval = Math.max(4, 32 - Math.floor((40 - aliveCount) / 2)); // Lower minimum interval for faster movement
}
// Infinite mode: respawn new wave and increase difficulty
var allDead = true;
for (var i = 0; i < aliens.length; i++) if (aliens[i].alive) allDead = false;
if (allDead) {
LK.effects.flashScreen(0x00ff00, 600);
// Increase difficulty: more rows, faster, more chance to shoot
if (alienRows < 8) alienRows++;
if (alienCols < 12) alienCols++;
alienShootChance = Math.min(0.06, alienShootChance + 0.004); // Increase max and ramp
alienMoveInterval = Math.max(3, alienMoveInterval - 3); // Faster ramp
spawnAliens();
// Remove all remaining alien bullets
for (var i = alienBullets.length - 1; i >= 0; i--) {
alienBullets[i].destroy();
alienBullets.splice(i, 1);
}
// Remove all player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
playerBullets[i].destroy();
playerBullets.splice(i, 1);
}
// Reset alien movement
alienMoveTimer = 0;
// Give player a bonus life every 3 cleared waves (max 5)
if (typeof wavesCleared === "undefined") wavesCleared = 0;
wavesCleared++;
if (wavesCleared % 3 === 0 && player.lives < 5) {
player.lives++;
LK.effects.flashObject(player, 0x66ff66, 800);
if (typeof updateLivesDisplay === "function") updateLivesDisplay();
}
return;
}
};
// Set initial score
LK.setScore(0);
scoreTxt.setText(0);