/****
* 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);