/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Alien = Container.expand(function () {
var self = Container.call(this);
var alienGraphics = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.2,
scaleY: 2.2
});
self.width = alienGraphics.width * 2.0;
self.height = alienGraphics.height * 2.0;
self.active = true;
self.points = 10;
self.canShoot = true;
self.shotsFired = 0; // Counter for shots fired
// Add a subtle pulsing animation to the aliens
tween(alienGraphics, {
scaleX: 2.4,
scaleY: 2.4
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(alienGraphics, {
scaleX: 2.2,
scaleY: 2.2
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.active) {
// Repeat the animation if alien is still active
tween(alienGraphics, {
scaleX: 2.4,
scaleY: 2.4
}, {
duration: 1000,
easing: tween.easeInOut
});
}
}
});
}
});
self.hit = function () {
if (self.active) {
self.active = false;
LK.getSound('alienExplode').play();
LK.effects.flashObject(self, 0xffffff, 100);
tween(self, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
return self.points;
}
return 0;
};
return self;
});
var AlienBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('alienBullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 1.8
});
self.speed = 8;
self.active = true;
self.width = bulletGraphics.width;
self.height = bulletGraphics.height;
self.update = function () {
self.y += self.speed;
if (self.y > 2800) {
self.active = false;
}
};
return self;
});
var BossAlien = Container.expand(function () {
var self = Container.call(this);
var alienGraphics = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4.0,
scaleY: 4.0,
tint: 0xff0000 // Red tint for boss
});
self.width = alienGraphics.width * 2.5;
self.height = alienGraphics.height * 2.5;
self.active = true;
self.points = 50; // More points than regular aliens
self.canShoot = true;
self.shotsFired = 0;
self.health = 10; // Takes 10 shots to defeat
self.lastHitTime = 0;
// Add a pulsing animation for the boss
tween(alienGraphics, {
scaleX: 4.2,
scaleY: 4.2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(alienGraphics, {
scaleX: 4.0,
scaleY: 4.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.active) {
tween(alienGraphics, {
scaleX: 4.2,
scaleY: 4.2
}, {
duration: 800,
easing: tween.easeInOut
});
}
}
});
}
});
self.hit = function () {
if (self.active) {
LK.getSound('alienExplode').play();
LK.effects.flashObject(self, 0xffffff, 100);
self.health--;
self.lastHitTime = Date.now();
// Create visual feedback for hits
tween(alienGraphics, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
tween(alienGraphics, {
tint: 0xff0000
}, {
duration: 100
});
}
});
// Only destroy when health reaches 0
if (self.health <= 0) {
self.active = false;
tween(self, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
self.destroy();
}
});
return self.points;
}
return 0; // Return 0 points if not destroyed yet
}
return 0;
};
self.update = function () {
// Boss-specific update logic can be added here
};
return self;
});
var ExplosiveAlienBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('alienBullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.2,
scaleY: 2.2,
tint: 0xff5500 // Orange-red color for explosive bullets
});
self.speed = 8;
self.active = true;
self.width = bulletGraphics.width;
self.height = bulletGraphics.height;
self.isExplosive = true; // Flag to identify explosive bullets
// Add pulsing effect to show it's explosive
tween(bulletGraphics, {
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(bulletGraphics, {
scaleX: 2.2,
scaleY: 2.2
}, {
duration: 300,
easing: tween.easeInOut,
repeat: true
});
}
});
self.update = function () {
self.y += self.speed;
if (self.y > 2800) {
self.active = false;
}
};
return self;
});
var FastAlien = Container.expand(function () {
var self = Container.call(this);
var alienGraphics = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0,
tint: 0x00ffff // Cyan tint for fast aliens
});
self.width = alienGraphics.width * 2.0;
self.height = alienGraphics.height * 2.0;
self.active = true;
self.points = 50; // Worth more points than regular aliens
self.speed = 20; // Very fast horizontal movement
self.direction = Math.random() > 0.5 ? 1 : -1; // Random direction (left or right)
// Add a stretching effect to show speed
tween(alienGraphics, {
scaleX: 2.3,
scaleY: 1.8
}, {
duration: 300,
easing: tween.easeInOut,
repeat: true,
yoyo: true
});
self.update = function () {
self.x += self.speed * self.direction;
// If off screen, mark as inactive
if (self.direction > 0 && self.x > gameWidth + 100 || self.direction < 0 && self.x < -100) {
self.active = false;
}
};
self.hit = function () {
if (self.active) {
self.active = false;
LK.getSound('alienExplode').play();
LK.effects.flashObject(self, 0xffffff, 100);
tween(self, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
return self.points;
}
return 0;
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8.0,
scaleY: 8.0
});
self.speed = -15;
self.active = true;
self.width = bulletGraphics.width * 2;
self.height = bulletGraphics.height * 2;
self.update = function () {
self.y += self.speed;
if (self.y < -50) {
self.active = false;
}
};
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 80.0,
scaleY: 80.0
});
self.speed = 12;
self.lives = 3;
self.hasShield = true;
self.multiShot = false;
self.width = shipGraphics.width * 2;
self.height = shipGraphics.height * 2;
self.shield = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
y: -40,
alpha: 0.7,
scaleX: 5.0,
scaleY: 5.0
});
self.activateShield = function () {
self.hasShield = true;
self.shield.alpha = 0.7;
};
self.deactivateShield = function () {
self.hasShield = false;
self.shield.alpha = 0;
};
self.hit = function () {
if (self.hasShield) {
self.deactivateShield();
return false;
} else {
LK.getSound('playerHit').play();
self.lives--;
LK.effects.flashObject(self, 0xff0000, 500);
return true;
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 1.8
});
self.type = Math.floor(Math.random() * 3); // 0: shield, 1: multishot, 2: extra life
self.speed = 5;
self.active = true;
self.width = powerUpGraphics.width;
self.height = powerUpGraphics.height;
// Change color based on type
if (self.type === 0) {
powerUpGraphics.tint = 0x9b59b6; // Shield - purple
} else if (self.type === 1) {
powerUpGraphics.tint = 0xf39c12; // Multishot - orange
} else {
powerUpGraphics.tint = 0x2ecc71; // Extra life - green
}
// Add a pulsing animation for level completion power-ups
if (self.type === 2) {
// Extra life power-up
tween(powerUpGraphics, {
scaleX: 2.2,
scaleY: 2.2
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(powerUpGraphics, {
scaleX: 1.8,
scaleY: 1.8
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.active) {
// Repeat the animation if still active
tween(powerUpGraphics, {
scaleX: 2.2,
scaleY: 2.2
}, {
duration: 500,
easing: tween.easeInOut
});
}
}
});
}
});
}
self.update = function () {
self.y += self.speed;
if (self.y > 2800) {
self.active = false;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game state variables
var playerShip;
var playerBullets = [];
var aliens = [];
var alienBullets = [];
var powerUps = [];
var shields = [];
var gameActive = true;
var score = 0;
var level = 1;
var alienDirection = 1; // 1 = right, -1 = left
var alienMoveSpeed = 1;
var alienDropAmount = 40;
var alienShootChance = 0.01;
var powerUpChance = 0.1;
var lastShootTime = 0;
var shootCooldown = 300; // ms
var multiShotTimer = 0;
var gameWidth = 2048;
var gameHeight = 2732;
var aliensKilled = 0;
var bossActive = false;
var boss = null;
var bossSpawnThreshold = 10; // Spawn boss after 10 aliens killed
// UI elements
var scoreTxt;
var levelTxt;
var livesTxt;
// Initialize game
function initGame() {
// Reset game state
playerBullets = [];
aliens = [];
alienBullets = [];
powerUps = [];
shields = [];
gameActive = true;
score = 0;
level = 1;
alienDirection = 1;
alienMoveSpeed = 1;
alienShootChance = 0.01;
multiShotTimer = 0;
aliensKilled = 0;
bossActive = false;
boss = null;
// Set score
LK.setScore(0);
// Create player ship
playerShip = new PlayerShip();
playerShip.x = gameWidth / 2;
playerShip.y = gameHeight - 150;
game.addChild(playerShip);
playerShip.activateShield(); // Activate shield immediately
// Create shields
createShields();
// Create UI
createUI();
// Create aliens for first level
createAlienWave();
// Play background music
LK.playMusic('backgroundMusic');
}
function createUI() {
// Score text
scoreTxt = new Text2('Score: 0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(scoreTxt);
scoreTxt.x = 120; // Keep away from the top left menu area
// Level text
levelTxt = new Text2('Level: 1', {
size: 100,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
// Lives text
livesTxt = new Text2('Lives: 3', {
size: 100,
fill: 0xFFFFFF
});
livesTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(livesTxt);
}
function createShields() {
// Create 4 shields across the bottom
var shieldCount = 4;
var shieldSpacing = gameWidth / (shieldCount + 1);
for (var i = 0; i < shieldCount; i++) {
var shield = game.addChild(LK.getAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
}));
shield.x = shieldSpacing * (i + 1);
shield.y = gameHeight - 300;
shield.health = 10;
shields.push(shield);
}
}
function createAlienWave() {
// Clear any remaining aliens
for (var i = aliens.length - 1; i >= 0; i--) {
aliens[i].destroy();
}
aliens = [];
// Increase difficulty with level
alienMoveSpeed = 1 + level * 0.5;
alienShootChance = 0.01 + level * 0.005;
// Create alien grid - rows based on level, 1 row for level 1, 2 rows for level 2, etc. up to 5
var rows = Math.min(level, 5); // Level 1-5 has corresponding number of rows
var cols = 6 + Math.min(level, 4); // Max 10 columns
var alienWidth = 200; // Further increased width to account for larger aliens
var alienHeight = 160; // Further increased height to account for larger aliens
var startX = (gameWidth - cols * alienWidth) / 2 + alienWidth / 2;
var startY = 200;
for (var row = 0; row < rows; row++) {
for (var col = 0; col < cols; col++) {
var alien = new Alien();
alien.x = startX + col * alienWidth;
alien.y = startY + row * alienHeight;
alien.row = row;
alien.col = col;
alien.points = (rows - row) * 10; // More points for aliens at the top
game.addChild(alien);
aliens.push(alien);
}
}
}
function playerShoot() {
var now = Date.now();
if (now - lastShootTime < shootCooldown) {
return;
}
lastShootTime = now;
// Create bullet
var bullet = new PlayerBullet();
bullet.x = playerShip.x;
bullet.y = playerShip.y - playerShip.height / 2;
game.addChild(bullet);
playerBullets.push(bullet);
// If player has multishot, create additional bullets
if (playerShip.multiShot) {
for (var i = -1; i <= 1; i += 2) {
var sideBullet = new PlayerBullet();
sideBullet.x = playerShip.x + i * 20;
sideBullet.y = playerShip.y - playerShip.height / 2;
game.addChild(sideBullet);
playerBullets.push(sideBullet);
}
}
LK.getSound('playerShoot').play();
}
function alienShoot() {
// Find shooting aliens (bottom row of each column)
var shootingAliens = [];
var colMap = {};
for (var i = 0; i < aliens.length; i++) {
var alien = aliens[i];
if (!alien.active) {
continue;
}
// If this alien is lower than the current lowest in its column, it becomes the shooter
if (!colMap[alien.col] || alien.row > colMap[alien.col].row) {
colMap[alien.col] = alien;
}
}
// Get all bottom aliens
for (var col in colMap) {
shootingAliens.push(colMap[col]);
}
// Randomly choose aliens to shoot based on difficulty
for (var i = 0; i < shootingAliens.length; i++) {
if (Math.random() < alienShootChance) {
var shooter = shootingAliens[i];
// Increment shotsFired counter for this alien
shooter.shotsFired = (shooter.shotsFired || 0) + 1;
// Every 10 shots, create an explosive bullet
var bullet;
if (shooter.shotsFired % 10 === 0) {
bullet = new ExplosiveAlienBullet();
// Add visual effect for explosive bullet firing
LK.effects.flashObject(shooter, 0xff5500, 100);
} else {
bullet = new AlienBullet();
}
bullet.x = shooter.x;
bullet.y = shooter.y + shooter.height / 2;
game.addChild(bullet);
alienBullets.push(bullet);
}
}
}
function checkAlienMovement() {
if (aliens.length === 0) {
return;
}
var moveDown = false;
var minX = gameWidth;
var maxX = 0;
// Find leftmost and rightmost aliens
for (var i = 0; i < aliens.length; i++) {
var alien = aliens[i];
if (alien.active) {
minX = Math.min(minX, alien.x);
maxX = Math.max(maxX, alien.x);
}
}
// Check if aliens need to change direction
if (maxX > gameWidth - 50 && alienDirection > 0 || minX < 50 && alienDirection < 0) {
alienDirection *= -1;
moveDown = true;
}
// Move aliens
for (var i = 0; i < aliens.length; i++) {
var alien = aliens[i];
if (alien.active) {
alien.x += alienDirection * alienMoveSpeed;
if (moveDown) {
alien.y += alienDropAmount;
// Check if aliens reached the bottom (game over condition)
if (alien.y > gameHeight - 200) {
gameOver();
return;
}
}
}
}
}
function spawnPowerUp(x, y) {
if (Math.random() < powerUpChance) {
var powerUp = new PowerUp();
powerUp.x = x;
powerUp.y = y;
game.addChild(powerUp);
powerUps.push(powerUp);
}
}
function checkCollisions() {
// Player bullets vs aliens
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (!bullet.active) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
var bulletHit = false;
// Check against aliens
for (var j = 0; j < aliens.length; j++) {
var alien = aliens[j];
if (alien.active && bullet.intersects(alien)) {
// Add points
var pointsEarned = alien.hit();
score += pointsEarned;
LK.setScore(score);
scoreTxt.setText('Score: ' + score);
// If hit is a fast alien, add extra score (on top of the 50 already earned)
if (alien instanceof FastAlien) {
// Add another 50 points for hitting a fast alien
score += 50;
LK.setScore(score);
scoreTxt.setText('Score: ' + score);
// Create visual feedback for the bonus
var bonusText = new Text2('+50!', {
size: 80,
fill: 0x00ffff
});
bonusText.x = alien.x;
bonusText.y = alien.y;
bonusText.anchor.set(0.5, 0.5);
game.addChild(bonusText);
tween(bonusText, {
y: bonusText.y - 100,
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
bonusText.destroy();
}
});
}
// Chance to spawn power up
spawnPowerUp(alien.x, alien.y);
// Remove alien from array if no longer active
if (!alien.active) {
aliens.splice(j, 1);
// Increment aliens killed counter
aliensKilled++;
// Check if we should spawn a boss
if (!bossActive && aliensKilled >= bossSpawnThreshold) {
spawnBoss();
}
}
// Remove bullet
bullet.destroy();
playerBullets.splice(i, 1);
bulletHit = true;
break;
}
}
// If already hit an alien, skip further checks
if (bulletHit) {
continue;
}
// Check against boss if active
if (bossActive && boss && boss.active && bullet.intersects(boss)) {
var bossPoints = boss.hit();
if (bossPoints > 0) {
// Boss was destroyed
score += bossPoints;
LK.setScore(score);
scoreTxt.setText('Score: ' + score);
// Spawn power up when boss is destroyed
spawnPowerUp(boss.x, boss.y);
spawnPowerUp(boss.x - 50, boss.y); // Extra powerups for boss
spawnPowerUp(boss.x + 50, boss.y);
bossActive = false;
boss = null;
}
bullet.destroy();
playerBullets.splice(i, 1);
bulletHit = true;
continue;
}
// Player bullets should pass through shields
// No need to check player bullets against shields
}
// Alien bullets vs player
for (var i = alienBullets.length - 1; i >= 0; i--) {
var bullet = alienBullets[i];
if (!bullet.active) {
bullet.destroy();
alienBullets.splice(i, 1);
continue;
}
// Check against player
if (bullet.intersects(playerShip)) {
var playerDamaged = playerShip.hit();
// Update lives display
livesTxt.setText('Lives: ' + playerShip.lives);
// Check for game over
if (playerShip.lives <= 0) {
gameOver();
}
bullet.destroy();
alienBullets.splice(i, 1);
continue;
}
// Check against shields
for (var j = 0; j < shields.length; j++) {
var shield = shields[j];
if (shield.health > 0 && bullet.intersects(shield)) {
// Explosive bullets do 2 damage instead of 1
if (bullet.isExplosive) {
shield.health -= 2;
// Visual explosion effect
LK.effects.flashObject(shield, 0xff5500, 200);
} else {
shield.health--;
}
shield.alpha = shield.health / 3;
if (shield.health <= 0) {
shield.alpha = 0;
}
bullet.destroy();
alienBullets.splice(i, 1);
break;
}
}
}
// Power-ups vs player
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (!powerUp.active) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
if (powerUp.intersects(playerShip)) {
LK.getSound('powerUpCollect').play();
// Apply power-up effect
if (powerUp.type === 0) {
// Shield
playerShip.activateShield();
} else if (powerUp.type === 1) {
// Multi-shot
playerShip.multiShot = true;
multiShotTimer = 300; // Duration in ticks (5 seconds at 60fps)
} else {
// Extra life
playerShip.lives++;
livesTxt.setText('Lives: ' + playerShip.lives);
}
powerUp.destroy();
powerUps.splice(i, 1);
}
}
}
function checkLevelComplete() {
// Check if there are any regular aliens left (not fast aliens)
var regularAliensLeft = false;
for (var i = 0; i < aliens.length; i++) {
if (!(aliens[i] instanceof FastAlien)) {
regularAliensLeft = true;
break;
}
}
if (!regularAliensLeft) {
level++;
levelTxt.setText('Level: ' + level);
// Spawn power-ups on both sides of the player after level completion
spawnLevelCompletionPowerUp();
createAlienWave();
}
}
function spawnLevelCompletionPowerUp() {
// Create two power-ups, one on each side of the player
var leftPowerUp = new PowerUp();
var rightPowerUp = new PowerUp();
// Force the type to be extra life (type 2)
leftPowerUp.type = 2;
rightPowerUp.type = 2;
// Set their color to green (extra life color)
leftPowerUp.getChildAt(0).tint = 0x2ecc71;
rightPowerUp.getChildAt(0).tint = 0x2ecc71;
// Position them on either side of the player
var offset = 200; // Distance from player
leftPowerUp.x = playerShip.x - offset;
leftPowerUp.y = playerShip.y;
rightPowerUp.x = playerShip.x + offset;
rightPowerUp.y = playerShip.y;
// Add them to the game
game.addChild(leftPowerUp);
game.addChild(rightPowerUp);
powerUps.push(leftPowerUp);
powerUps.push(rightPowerUp);
// Add a visual effect to highlight them
LK.effects.flashObject(leftPowerUp, 0x2ecc71, 500);
LK.effects.flashObject(rightPowerUp, 0x2ecc71, 500);
}
function gameOver() {
gameActive = false;
LK.effects.flashScreen(0xff0000, 1000);
LK.stopMusic();
LK.showGameOver();
}
// Touch controls
var touchX = null;
game.down = function (x, y, obj) {
touchX = x;
playerShoot();
};
game.up = function (x, y, obj) {
touchX = null;
};
game.move = function (x, y, obj) {
if (touchX !== null) {
touchX = x;
}
};
// Game update loop
game.update = function () {
if (!gameActive) {
return;
}
// Process player movement from touch
if (touchX !== null) {
// Move player toward touch position
var moveDir = touchX > playerShip.x ? 1 : -1;
if (Math.abs(touchX - playerShip.x) > 5) {
playerShip.x += moveDir * playerShip.speed;
}
// Keep player in bounds
if (playerShip.x < playerShip.width / 2) {
playerShip.x = playerShip.width / 2;
}
if (playerShip.x > gameWidth - playerShip.width / 2) {
playerShip.x = gameWidth - playerShip.width / 2;
}
}
// Update multishot timer
if (playerShip.multiShot) {
multiShotTimer--;
if (multiShotTimer <= 0) {
playerShip.multiShot = false;
}
}
// Update game objects
checkAlienMovement();
// Update fast aliens manually as they have their own movement pattern
for (var i = 0; i < aliens.length; i++) {
if (aliens[i] instanceof FastAlien && aliens[i].active) {
aliens[i].update();
}
}
// Boss update logic
if (bossActive && boss && boss.active) {
// Make boss move side to side independently
boss.x += Math.sin(LK.ticks / 60) * 3; // Gentle sine wave movement
// Make boss shoot more frequently
if (LK.ticks % 180 === 0) {
// Every 3 seconds
var bullet = new ExplosiveAlienBullet();
bullet.x = boss.x;
bullet.y = boss.y + boss.height / 2;
game.addChild(bullet);
alienBullets.push(bullet);
// Sometimes fire a spread of bullets
if (Math.random() < 0.5) {
for (var i = -1; i <= 1; i += 2) {
var sideBullet = new AlienBullet();
sideBullet.x = boss.x + i * 40;
sideBullet.y = boss.y + boss.height / 2;
game.addChild(sideBullet);
alienBullets.push(sideBullet);
}
}
}
// Update boss custom logic if any
if (boss.update) {
boss.update();
}
}
// Alien shooting
if (LK.ticks % 300 === 0) {
// Check every 5 seconds
alienShoot();
}
// Automatic player shooting every 2 seconds (120 ticks at 60fps)
if (LK.ticks % 120 === 0) {
playerShoot();
}
// Update bullets
for (var i = 0; i < playerBullets.length; i++) {
playerBullets[i].update();
}
for (var i = 0; i < alienBullets.length; i++) {
alienBullets[i].update();
}
// Update power-ups
for (var i = 0; i < powerUps.length; i++) {
powerUps[i].update();
}
// Check collisions
checkCollisions();
// Check if level is complete
checkLevelComplete();
};
// Initialize the game
initGame();
// Function to spawn fast aliens
function spawnFastAlien() {
var fastAlien = new FastAlien();
// Set starting position - either left or right edge of screen
if (fastAlien.direction > 0) {
// Moving right to left
fastAlien.x = -50;
} else {
// Moving left to right
fastAlien.x = gameWidth + 50;
}
// Random Y position in the top half of the screen
fastAlien.y = Math.random() * (gameHeight / 2) + 100;
game.addChild(fastAlien);
aliens.push(fastAlien);
// Visual effect for fast alien spawn
LK.effects.flashObject(fastAlien, 0x00ffff, 200);
}
// Set interval to spawn fast aliens every 5 seconds (300 frames at 60fps)
LK.setInterval(spawnFastAlien, 5000);
function spawnBoss() {
bossActive = true;
boss = new BossAlien();
// Find the back row position
var backRow = 0;
var startX = gameWidth / 2;
var startY = 200;
// If there are aliens, position the boss behind them
if (aliens.length > 0) {
for (var i = 0; i < aliens.length; i++) {
if (aliens[i].row < backRow) {
backRow = aliens[i].row;
}
}
backRow = backRow - 1; // Position boss one row behind furthest back row
if (backRow < 0) {
backRow = 0;
}
startY = 200 + backRow * 160; // Use same spacing as alien rows
}
boss.x = startX;
boss.y = startY;
boss.row = backRow;
boss.col = -1; // Special column marker for boss
game.addChild(boss);
// Visual effect for boss spawn
LK.effects.flashObject(boss, 0xffff00, 500);
} /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Alien = Container.expand(function () {
var self = Container.call(this);
var alienGraphics = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.2,
scaleY: 2.2
});
self.width = alienGraphics.width * 2.0;
self.height = alienGraphics.height * 2.0;
self.active = true;
self.points = 10;
self.canShoot = true;
self.shotsFired = 0; // Counter for shots fired
// Add a subtle pulsing animation to the aliens
tween(alienGraphics, {
scaleX: 2.4,
scaleY: 2.4
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(alienGraphics, {
scaleX: 2.2,
scaleY: 2.2
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.active) {
// Repeat the animation if alien is still active
tween(alienGraphics, {
scaleX: 2.4,
scaleY: 2.4
}, {
duration: 1000,
easing: tween.easeInOut
});
}
}
});
}
});
self.hit = function () {
if (self.active) {
self.active = false;
LK.getSound('alienExplode').play();
LK.effects.flashObject(self, 0xffffff, 100);
tween(self, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
return self.points;
}
return 0;
};
return self;
});
var AlienBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('alienBullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 1.8
});
self.speed = 8;
self.active = true;
self.width = bulletGraphics.width;
self.height = bulletGraphics.height;
self.update = function () {
self.y += self.speed;
if (self.y > 2800) {
self.active = false;
}
};
return self;
});
var BossAlien = Container.expand(function () {
var self = Container.call(this);
var alienGraphics = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4.0,
scaleY: 4.0,
tint: 0xff0000 // Red tint for boss
});
self.width = alienGraphics.width * 2.5;
self.height = alienGraphics.height * 2.5;
self.active = true;
self.points = 50; // More points than regular aliens
self.canShoot = true;
self.shotsFired = 0;
self.health = 10; // Takes 10 shots to defeat
self.lastHitTime = 0;
// Add a pulsing animation for the boss
tween(alienGraphics, {
scaleX: 4.2,
scaleY: 4.2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(alienGraphics, {
scaleX: 4.0,
scaleY: 4.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.active) {
tween(alienGraphics, {
scaleX: 4.2,
scaleY: 4.2
}, {
duration: 800,
easing: tween.easeInOut
});
}
}
});
}
});
self.hit = function () {
if (self.active) {
LK.getSound('alienExplode').play();
LK.effects.flashObject(self, 0xffffff, 100);
self.health--;
self.lastHitTime = Date.now();
// Create visual feedback for hits
tween(alienGraphics, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
tween(alienGraphics, {
tint: 0xff0000
}, {
duration: 100
});
}
});
// Only destroy when health reaches 0
if (self.health <= 0) {
self.active = false;
tween(self, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
self.destroy();
}
});
return self.points;
}
return 0; // Return 0 points if not destroyed yet
}
return 0;
};
self.update = function () {
// Boss-specific update logic can be added here
};
return self;
});
var ExplosiveAlienBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('alienBullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.2,
scaleY: 2.2,
tint: 0xff5500 // Orange-red color for explosive bullets
});
self.speed = 8;
self.active = true;
self.width = bulletGraphics.width;
self.height = bulletGraphics.height;
self.isExplosive = true; // Flag to identify explosive bullets
// Add pulsing effect to show it's explosive
tween(bulletGraphics, {
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(bulletGraphics, {
scaleX: 2.2,
scaleY: 2.2
}, {
duration: 300,
easing: tween.easeInOut,
repeat: true
});
}
});
self.update = function () {
self.y += self.speed;
if (self.y > 2800) {
self.active = false;
}
};
return self;
});
var FastAlien = Container.expand(function () {
var self = Container.call(this);
var alienGraphics = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0,
tint: 0x00ffff // Cyan tint for fast aliens
});
self.width = alienGraphics.width * 2.0;
self.height = alienGraphics.height * 2.0;
self.active = true;
self.points = 50; // Worth more points than regular aliens
self.speed = 20; // Very fast horizontal movement
self.direction = Math.random() > 0.5 ? 1 : -1; // Random direction (left or right)
// Add a stretching effect to show speed
tween(alienGraphics, {
scaleX: 2.3,
scaleY: 1.8
}, {
duration: 300,
easing: tween.easeInOut,
repeat: true,
yoyo: true
});
self.update = function () {
self.x += self.speed * self.direction;
// If off screen, mark as inactive
if (self.direction > 0 && self.x > gameWidth + 100 || self.direction < 0 && self.x < -100) {
self.active = false;
}
};
self.hit = function () {
if (self.active) {
self.active = false;
LK.getSound('alienExplode').play();
LK.effects.flashObject(self, 0xffffff, 100);
tween(self, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
return self.points;
}
return 0;
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8.0,
scaleY: 8.0
});
self.speed = -15;
self.active = true;
self.width = bulletGraphics.width * 2;
self.height = bulletGraphics.height * 2;
self.update = function () {
self.y += self.speed;
if (self.y < -50) {
self.active = false;
}
};
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 80.0,
scaleY: 80.0
});
self.speed = 12;
self.lives = 3;
self.hasShield = true;
self.multiShot = false;
self.width = shipGraphics.width * 2;
self.height = shipGraphics.height * 2;
self.shield = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
y: -40,
alpha: 0.7,
scaleX: 5.0,
scaleY: 5.0
});
self.activateShield = function () {
self.hasShield = true;
self.shield.alpha = 0.7;
};
self.deactivateShield = function () {
self.hasShield = false;
self.shield.alpha = 0;
};
self.hit = function () {
if (self.hasShield) {
self.deactivateShield();
return false;
} else {
LK.getSound('playerHit').play();
self.lives--;
LK.effects.flashObject(self, 0xff0000, 500);
return true;
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 1.8
});
self.type = Math.floor(Math.random() * 3); // 0: shield, 1: multishot, 2: extra life
self.speed = 5;
self.active = true;
self.width = powerUpGraphics.width;
self.height = powerUpGraphics.height;
// Change color based on type
if (self.type === 0) {
powerUpGraphics.tint = 0x9b59b6; // Shield - purple
} else if (self.type === 1) {
powerUpGraphics.tint = 0xf39c12; // Multishot - orange
} else {
powerUpGraphics.tint = 0x2ecc71; // Extra life - green
}
// Add a pulsing animation for level completion power-ups
if (self.type === 2) {
// Extra life power-up
tween(powerUpGraphics, {
scaleX: 2.2,
scaleY: 2.2
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(powerUpGraphics, {
scaleX: 1.8,
scaleY: 1.8
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.active) {
// Repeat the animation if still active
tween(powerUpGraphics, {
scaleX: 2.2,
scaleY: 2.2
}, {
duration: 500,
easing: tween.easeInOut
});
}
}
});
}
});
}
self.update = function () {
self.y += self.speed;
if (self.y > 2800) {
self.active = false;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game state variables
var playerShip;
var playerBullets = [];
var aliens = [];
var alienBullets = [];
var powerUps = [];
var shields = [];
var gameActive = true;
var score = 0;
var level = 1;
var alienDirection = 1; // 1 = right, -1 = left
var alienMoveSpeed = 1;
var alienDropAmount = 40;
var alienShootChance = 0.01;
var powerUpChance = 0.1;
var lastShootTime = 0;
var shootCooldown = 300; // ms
var multiShotTimer = 0;
var gameWidth = 2048;
var gameHeight = 2732;
var aliensKilled = 0;
var bossActive = false;
var boss = null;
var bossSpawnThreshold = 10; // Spawn boss after 10 aliens killed
// UI elements
var scoreTxt;
var levelTxt;
var livesTxt;
// Initialize game
function initGame() {
// Reset game state
playerBullets = [];
aliens = [];
alienBullets = [];
powerUps = [];
shields = [];
gameActive = true;
score = 0;
level = 1;
alienDirection = 1;
alienMoveSpeed = 1;
alienShootChance = 0.01;
multiShotTimer = 0;
aliensKilled = 0;
bossActive = false;
boss = null;
// Set score
LK.setScore(0);
// Create player ship
playerShip = new PlayerShip();
playerShip.x = gameWidth / 2;
playerShip.y = gameHeight - 150;
game.addChild(playerShip);
playerShip.activateShield(); // Activate shield immediately
// Create shields
createShields();
// Create UI
createUI();
// Create aliens for first level
createAlienWave();
// Play background music
LK.playMusic('backgroundMusic');
}
function createUI() {
// Score text
scoreTxt = new Text2('Score: 0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(scoreTxt);
scoreTxt.x = 120; // Keep away from the top left menu area
// Level text
levelTxt = new Text2('Level: 1', {
size: 100,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
// Lives text
livesTxt = new Text2('Lives: 3', {
size: 100,
fill: 0xFFFFFF
});
livesTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(livesTxt);
}
function createShields() {
// Create 4 shields across the bottom
var shieldCount = 4;
var shieldSpacing = gameWidth / (shieldCount + 1);
for (var i = 0; i < shieldCount; i++) {
var shield = game.addChild(LK.getAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
}));
shield.x = shieldSpacing * (i + 1);
shield.y = gameHeight - 300;
shield.health = 10;
shields.push(shield);
}
}
function createAlienWave() {
// Clear any remaining aliens
for (var i = aliens.length - 1; i >= 0; i--) {
aliens[i].destroy();
}
aliens = [];
// Increase difficulty with level
alienMoveSpeed = 1 + level * 0.5;
alienShootChance = 0.01 + level * 0.005;
// Create alien grid - rows based on level, 1 row for level 1, 2 rows for level 2, etc. up to 5
var rows = Math.min(level, 5); // Level 1-5 has corresponding number of rows
var cols = 6 + Math.min(level, 4); // Max 10 columns
var alienWidth = 200; // Further increased width to account for larger aliens
var alienHeight = 160; // Further increased height to account for larger aliens
var startX = (gameWidth - cols * alienWidth) / 2 + alienWidth / 2;
var startY = 200;
for (var row = 0; row < rows; row++) {
for (var col = 0; col < cols; col++) {
var alien = new Alien();
alien.x = startX + col * alienWidth;
alien.y = startY + row * alienHeight;
alien.row = row;
alien.col = col;
alien.points = (rows - row) * 10; // More points for aliens at the top
game.addChild(alien);
aliens.push(alien);
}
}
}
function playerShoot() {
var now = Date.now();
if (now - lastShootTime < shootCooldown) {
return;
}
lastShootTime = now;
// Create bullet
var bullet = new PlayerBullet();
bullet.x = playerShip.x;
bullet.y = playerShip.y - playerShip.height / 2;
game.addChild(bullet);
playerBullets.push(bullet);
// If player has multishot, create additional bullets
if (playerShip.multiShot) {
for (var i = -1; i <= 1; i += 2) {
var sideBullet = new PlayerBullet();
sideBullet.x = playerShip.x + i * 20;
sideBullet.y = playerShip.y - playerShip.height / 2;
game.addChild(sideBullet);
playerBullets.push(sideBullet);
}
}
LK.getSound('playerShoot').play();
}
function alienShoot() {
// Find shooting aliens (bottom row of each column)
var shootingAliens = [];
var colMap = {};
for (var i = 0; i < aliens.length; i++) {
var alien = aliens[i];
if (!alien.active) {
continue;
}
// If this alien is lower than the current lowest in its column, it becomes the shooter
if (!colMap[alien.col] || alien.row > colMap[alien.col].row) {
colMap[alien.col] = alien;
}
}
// Get all bottom aliens
for (var col in colMap) {
shootingAliens.push(colMap[col]);
}
// Randomly choose aliens to shoot based on difficulty
for (var i = 0; i < shootingAliens.length; i++) {
if (Math.random() < alienShootChance) {
var shooter = shootingAliens[i];
// Increment shotsFired counter for this alien
shooter.shotsFired = (shooter.shotsFired || 0) + 1;
// Every 10 shots, create an explosive bullet
var bullet;
if (shooter.shotsFired % 10 === 0) {
bullet = new ExplosiveAlienBullet();
// Add visual effect for explosive bullet firing
LK.effects.flashObject(shooter, 0xff5500, 100);
} else {
bullet = new AlienBullet();
}
bullet.x = shooter.x;
bullet.y = shooter.y + shooter.height / 2;
game.addChild(bullet);
alienBullets.push(bullet);
}
}
}
function checkAlienMovement() {
if (aliens.length === 0) {
return;
}
var moveDown = false;
var minX = gameWidth;
var maxX = 0;
// Find leftmost and rightmost aliens
for (var i = 0; i < aliens.length; i++) {
var alien = aliens[i];
if (alien.active) {
minX = Math.min(minX, alien.x);
maxX = Math.max(maxX, alien.x);
}
}
// Check if aliens need to change direction
if (maxX > gameWidth - 50 && alienDirection > 0 || minX < 50 && alienDirection < 0) {
alienDirection *= -1;
moveDown = true;
}
// Move aliens
for (var i = 0; i < aliens.length; i++) {
var alien = aliens[i];
if (alien.active) {
alien.x += alienDirection * alienMoveSpeed;
if (moveDown) {
alien.y += alienDropAmount;
// Check if aliens reached the bottom (game over condition)
if (alien.y > gameHeight - 200) {
gameOver();
return;
}
}
}
}
}
function spawnPowerUp(x, y) {
if (Math.random() < powerUpChance) {
var powerUp = new PowerUp();
powerUp.x = x;
powerUp.y = y;
game.addChild(powerUp);
powerUps.push(powerUp);
}
}
function checkCollisions() {
// Player bullets vs aliens
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (!bullet.active) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
var bulletHit = false;
// Check against aliens
for (var j = 0; j < aliens.length; j++) {
var alien = aliens[j];
if (alien.active && bullet.intersects(alien)) {
// Add points
var pointsEarned = alien.hit();
score += pointsEarned;
LK.setScore(score);
scoreTxt.setText('Score: ' + score);
// If hit is a fast alien, add extra score (on top of the 50 already earned)
if (alien instanceof FastAlien) {
// Add another 50 points for hitting a fast alien
score += 50;
LK.setScore(score);
scoreTxt.setText('Score: ' + score);
// Create visual feedback for the bonus
var bonusText = new Text2('+50!', {
size: 80,
fill: 0x00ffff
});
bonusText.x = alien.x;
bonusText.y = alien.y;
bonusText.anchor.set(0.5, 0.5);
game.addChild(bonusText);
tween(bonusText, {
y: bonusText.y - 100,
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
bonusText.destroy();
}
});
}
// Chance to spawn power up
spawnPowerUp(alien.x, alien.y);
// Remove alien from array if no longer active
if (!alien.active) {
aliens.splice(j, 1);
// Increment aliens killed counter
aliensKilled++;
// Check if we should spawn a boss
if (!bossActive && aliensKilled >= bossSpawnThreshold) {
spawnBoss();
}
}
// Remove bullet
bullet.destroy();
playerBullets.splice(i, 1);
bulletHit = true;
break;
}
}
// If already hit an alien, skip further checks
if (bulletHit) {
continue;
}
// Check against boss if active
if (bossActive && boss && boss.active && bullet.intersects(boss)) {
var bossPoints = boss.hit();
if (bossPoints > 0) {
// Boss was destroyed
score += bossPoints;
LK.setScore(score);
scoreTxt.setText('Score: ' + score);
// Spawn power up when boss is destroyed
spawnPowerUp(boss.x, boss.y);
spawnPowerUp(boss.x - 50, boss.y); // Extra powerups for boss
spawnPowerUp(boss.x + 50, boss.y);
bossActive = false;
boss = null;
}
bullet.destroy();
playerBullets.splice(i, 1);
bulletHit = true;
continue;
}
// Player bullets should pass through shields
// No need to check player bullets against shields
}
// Alien bullets vs player
for (var i = alienBullets.length - 1; i >= 0; i--) {
var bullet = alienBullets[i];
if (!bullet.active) {
bullet.destroy();
alienBullets.splice(i, 1);
continue;
}
// Check against player
if (bullet.intersects(playerShip)) {
var playerDamaged = playerShip.hit();
// Update lives display
livesTxt.setText('Lives: ' + playerShip.lives);
// Check for game over
if (playerShip.lives <= 0) {
gameOver();
}
bullet.destroy();
alienBullets.splice(i, 1);
continue;
}
// Check against shields
for (var j = 0; j < shields.length; j++) {
var shield = shields[j];
if (shield.health > 0 && bullet.intersects(shield)) {
// Explosive bullets do 2 damage instead of 1
if (bullet.isExplosive) {
shield.health -= 2;
// Visual explosion effect
LK.effects.flashObject(shield, 0xff5500, 200);
} else {
shield.health--;
}
shield.alpha = shield.health / 3;
if (shield.health <= 0) {
shield.alpha = 0;
}
bullet.destroy();
alienBullets.splice(i, 1);
break;
}
}
}
// Power-ups vs player
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (!powerUp.active) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
if (powerUp.intersects(playerShip)) {
LK.getSound('powerUpCollect').play();
// Apply power-up effect
if (powerUp.type === 0) {
// Shield
playerShip.activateShield();
} else if (powerUp.type === 1) {
// Multi-shot
playerShip.multiShot = true;
multiShotTimer = 300; // Duration in ticks (5 seconds at 60fps)
} else {
// Extra life
playerShip.lives++;
livesTxt.setText('Lives: ' + playerShip.lives);
}
powerUp.destroy();
powerUps.splice(i, 1);
}
}
}
function checkLevelComplete() {
// Check if there are any regular aliens left (not fast aliens)
var regularAliensLeft = false;
for (var i = 0; i < aliens.length; i++) {
if (!(aliens[i] instanceof FastAlien)) {
regularAliensLeft = true;
break;
}
}
if (!regularAliensLeft) {
level++;
levelTxt.setText('Level: ' + level);
// Spawn power-ups on both sides of the player after level completion
spawnLevelCompletionPowerUp();
createAlienWave();
}
}
function spawnLevelCompletionPowerUp() {
// Create two power-ups, one on each side of the player
var leftPowerUp = new PowerUp();
var rightPowerUp = new PowerUp();
// Force the type to be extra life (type 2)
leftPowerUp.type = 2;
rightPowerUp.type = 2;
// Set their color to green (extra life color)
leftPowerUp.getChildAt(0).tint = 0x2ecc71;
rightPowerUp.getChildAt(0).tint = 0x2ecc71;
// Position them on either side of the player
var offset = 200; // Distance from player
leftPowerUp.x = playerShip.x - offset;
leftPowerUp.y = playerShip.y;
rightPowerUp.x = playerShip.x + offset;
rightPowerUp.y = playerShip.y;
// Add them to the game
game.addChild(leftPowerUp);
game.addChild(rightPowerUp);
powerUps.push(leftPowerUp);
powerUps.push(rightPowerUp);
// Add a visual effect to highlight them
LK.effects.flashObject(leftPowerUp, 0x2ecc71, 500);
LK.effects.flashObject(rightPowerUp, 0x2ecc71, 500);
}
function gameOver() {
gameActive = false;
LK.effects.flashScreen(0xff0000, 1000);
LK.stopMusic();
LK.showGameOver();
}
// Touch controls
var touchX = null;
game.down = function (x, y, obj) {
touchX = x;
playerShoot();
};
game.up = function (x, y, obj) {
touchX = null;
};
game.move = function (x, y, obj) {
if (touchX !== null) {
touchX = x;
}
};
// Game update loop
game.update = function () {
if (!gameActive) {
return;
}
// Process player movement from touch
if (touchX !== null) {
// Move player toward touch position
var moveDir = touchX > playerShip.x ? 1 : -1;
if (Math.abs(touchX - playerShip.x) > 5) {
playerShip.x += moveDir * playerShip.speed;
}
// Keep player in bounds
if (playerShip.x < playerShip.width / 2) {
playerShip.x = playerShip.width / 2;
}
if (playerShip.x > gameWidth - playerShip.width / 2) {
playerShip.x = gameWidth - playerShip.width / 2;
}
}
// Update multishot timer
if (playerShip.multiShot) {
multiShotTimer--;
if (multiShotTimer <= 0) {
playerShip.multiShot = false;
}
}
// Update game objects
checkAlienMovement();
// Update fast aliens manually as they have their own movement pattern
for (var i = 0; i < aliens.length; i++) {
if (aliens[i] instanceof FastAlien && aliens[i].active) {
aliens[i].update();
}
}
// Boss update logic
if (bossActive && boss && boss.active) {
// Make boss move side to side independently
boss.x += Math.sin(LK.ticks / 60) * 3; // Gentle sine wave movement
// Make boss shoot more frequently
if (LK.ticks % 180 === 0) {
// Every 3 seconds
var bullet = new ExplosiveAlienBullet();
bullet.x = boss.x;
bullet.y = boss.y + boss.height / 2;
game.addChild(bullet);
alienBullets.push(bullet);
// Sometimes fire a spread of bullets
if (Math.random() < 0.5) {
for (var i = -1; i <= 1; i += 2) {
var sideBullet = new AlienBullet();
sideBullet.x = boss.x + i * 40;
sideBullet.y = boss.y + boss.height / 2;
game.addChild(sideBullet);
alienBullets.push(sideBullet);
}
}
}
// Update boss custom logic if any
if (boss.update) {
boss.update();
}
}
// Alien shooting
if (LK.ticks % 300 === 0) {
// Check every 5 seconds
alienShoot();
}
// Automatic player shooting every 2 seconds (120 ticks at 60fps)
if (LK.ticks % 120 === 0) {
playerShoot();
}
// Update bullets
for (var i = 0; i < playerBullets.length; i++) {
playerBullets[i].update();
}
for (var i = 0; i < alienBullets.length; i++) {
alienBullets[i].update();
}
// Update power-ups
for (var i = 0; i < powerUps.length; i++) {
powerUps[i].update();
}
// Check collisions
checkCollisions();
// Check if level is complete
checkLevelComplete();
};
// Initialize the game
initGame();
// Function to spawn fast aliens
function spawnFastAlien() {
var fastAlien = new FastAlien();
// Set starting position - either left or right edge of screen
if (fastAlien.direction > 0) {
// Moving right to left
fastAlien.x = -50;
} else {
// Moving left to right
fastAlien.x = gameWidth + 50;
}
// Random Y position in the top half of the screen
fastAlien.y = Math.random() * (gameHeight / 2) + 100;
game.addChild(fastAlien);
aliens.push(fastAlien);
// Visual effect for fast alien spawn
LK.effects.flashObject(fastAlien, 0x00ffff, 200);
}
// Set interval to spawn fast aliens every 5 seconds (300 frames at 60fps)
LK.setInterval(spawnFastAlien, 5000);
function spawnBoss() {
bossActive = true;
boss = new BossAlien();
// Find the back row position
var backRow = 0;
var startX = gameWidth / 2;
var startY = 200;
// If there are aliens, position the boss behind them
if (aliens.length > 0) {
for (var i = 0; i < aliens.length; i++) {
if (aliens[i].row < backRow) {
backRow = aliens[i].row;
}
}
backRow = backRow - 1; // Position boss one row behind furthest back row
if (backRow < 0) {
backRow = 0;
}
startY = 200 + backRow * 160; // Use same spacing as alien rows
}
boss.x = startX;
boss.y = startY;
boss.row = backRow;
boss.col = -1; // Special column marker for boss
game.addChild(boss);
// Visual effect for boss spawn
LK.effects.flashObject(boss, 0xffff00, 500);
}
Steel beam. In-Game asset. 2d. High contrast. No shadows
Bullet. In-Game asset. 2d. High contrast. No shadows
Military Tank. In-Game asset. 2d. High contrast. No shadows
Medkit. In-Game asset. 2d. High contrast. No shadows
Blue alien in a UFO, he’s mad and his body is inside the ufo. In-Game asset. 2d. High contrast. No shadows