/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0, level: 1 }); /**** * Classes ****/ var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.width = enemyGraphics.width; self.height = enemyGraphics.height; self.hp = 1; self.scoreValue = 100; self.canShoot = true; self.movingRight = true; self.moveSpeed = 2; self.dropDistance = 40; self.shoot = function () { if (!self.canShoot || Math.random() > 0.01) { return; } // Random chance to shoot var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y + self.height / 2; game.addChild(bullet); enemyBullets.push(bullet); // Cooldown between shots self.canShoot = false; LK.setTimeout(function () { self.canShoot = true; }, 2000); }; self.takeDamage = function () { self.hp--; if (self.hp <= 0) { // Update score LK.setScore(LK.getScore() + self.scoreValue); scoreTxt.setText(LK.getScore()); // Chance to drop power-up if (Math.random() < 0.1) { // 10% chance var powerUp = new PowerUp(); powerUp.x = self.x; powerUp.y = self.y; game.addChild(powerUp); powerUps.push(powerUp); } // Play sound LK.getSound('enemyDestroyed').play(); // Visual effect LK.effects.flashObject(self, 0xffff00, 300); // Remove enemy self.destroy(); var index = enemies.indexOf(self); if (index > -1) { enemies.splice(index, 1); } // Check if level complete if (enemies.length === 0) { levelComplete(); } } else { // Visual effect for damage LK.effects.flashObject(self, 0xffff00, 200); } }; return self; }); var Boss = Enemy.expand(function () { var self = Enemy.call(this); // Replace graphics with boss graphics self.removeChildAt(0); var bossGraphics = self.attachAsset('boss', { anchorX: 0.5, anchorY: 0.5 }); self.width = bossGraphics.width; self.height = bossGraphics.height; self.hp = 20; self.scoreValue = 2000; self.moveSpeed = 3; self.attackPattern = 0; self.attackTimer = null; self.startAttackPattern = function () { self.attackTimer = LK.setInterval(function () { self.performAttack(); }, 2000); }; self.performAttack = function () { self.attackPattern = (self.attackPattern + 1) % 3; switch (self.attackPattern) { case 0: // Single strong shot var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y + self.height / 2; bullet.speed = 8; bullet.scale.set(2, 2); game.addChild(bullet); enemyBullets.push(bullet); break; case 1: // Multiple shots in a spread for (var i = -2; i <= 2; i++) { var bullet = new EnemyBullet(); bullet.x = self.x + i * 40; bullet.y = self.y + self.height / 2; game.addChild(bullet); enemyBullets.push(bullet); } break; case 2: // Wave pattern of bullets var interval = LK.setInterval(function () { var bullet = new EnemyBullet(); bullet.x = self.x + (Math.random() * 200 - 100); bullet.y = self.y + self.height / 2; game.addChild(bullet); enemyBullets.push(bullet); }, 200); LK.setTimeout(function () { LK.clearInterval(interval); }, 1000); break; } }; var parentTakeDamage = self.takeDamage; self.takeDamage = function () { parentTakeDamage.call(self); // When boss is destroyed, clear the attack timer if (self.hp <= 0 && self.attackTimer) { LK.clearInterval(self.attackTimer); } }; return self; }); var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 6; self.update = function () { self.y += self.speed; // Destroy if out of bounds if (self.y > 2732 + 50) { self.destroy(); var index = enemyBullets.indexOf(self); if (index > -1) { enemyBullets.splice(index, 1); } } }; return self; }); var PlayerBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -15; // Negative because moving upward self.update = function () { self.y += self.speed; // Destroy if out of bounds if (self.y < -50) { self.destroy(); var index = bullets.indexOf(self); if (index > -1) { bullets.splice(index, 1); } } }; return self; }); var PlayerShip = Container.expand(function () { var self = Container.call(this); var shipGraphics = self.attachAsset('playerShip', { anchorX: 0.5, anchorY: 0.5, flipX: 1 // Flip the spaceship horizontally }); self.width = shipGraphics.width; self.height = shipGraphics.height; self.lives = 3; self.speed = 15; self.canShoot = true; self.shootCooldown = 300; // milliseconds self.invulnerable = false; self.powerUpActive = false; self.startShootCooldown = function () { self.canShoot = false; LK.setTimeout(function () { self.canShoot = true; }, self.shootCooldown); }; self.shoot = function () { if (!self.canShoot) { return; } var bullet = new PlayerBullet(); bullet.x = self.x; bullet.y = self.y - self.height / 2; game.addChild(bullet); bullets.push(bullet); LK.getSound('shoot').play(); self.startShootCooldown(); // Create double bullet when power-up is active if (self.powerUpActive) { var bulletLeft = new PlayerBullet(); bulletLeft.x = self.x - 20; bulletLeft.y = self.y - self.height / 2; var bulletRight = new PlayerBullet(); bulletRight.x = self.x + 20; bulletRight.y = self.y - self.height / 2; game.addChild(bulletLeft); game.addChild(bulletRight); bullets.push(bulletLeft); bullets.push(bulletRight); } }; self.hit = function () { if (self.invulnerable) { return; } self.lives--; LK.getSound('playerHit').play(); // Flash player ship to indicate damage LK.effects.flashObject(self, 0xff0000, 1000); // Make player temporarily invulnerable self.invulnerable = true; LK.setTimeout(function () { self.invulnerable = false; }, 2000); // Check for game over if (self.lives <= 0) { LK.showGameOver(); } }; self.activatePowerUp = function (type) { LK.getSound('powerUpCollected').play(); switch (type) { case 'rapidFire': var oldCooldown = self.shootCooldown; self.shootCooldown = 150; LK.setTimeout(function () { self.shootCooldown = oldCooldown; }, 5000); break; case 'doubleBullet': self.powerUpActive = true; LK.setTimeout(function () { self.powerUpActive = false; }, 8000); break; case 'shield': // Create shield createShield(); break; } }; self.update = function () { // Movement logic handled in game.update }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerUpGraphics = self.attachAsset('powerUp', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3; self.type = ['rapidFire', 'doubleBullet', 'shield'][Math.floor(Math.random() * 3)]; // Set color based on power-up type switch (self.type) { case 'rapidFire': powerUpGraphics.tint = 0xff0000; // Red break; case 'doubleBullet': powerUpGraphics.tint = 0x00ff00; // Green break; case 'shield': powerUpGraphics.tint = 0x0000ff; // Blue break; } self.update = function () { self.y += self.speed; // Destroy if out of bounds if (self.y > 2732 + 50) { self.destroy(); var index = powerUps.indexOf(self); if (index > -1) { powerUps.splice(index, 1); } } }; return self; }); var Shield = Container.expand(function () { var self = Container.call(this); var shieldGraphics = self.attachAsset('shield', { anchorX: 0.5, anchorY: 0.5 }); self.hp = 3; self.takeDamage = function () { self.hp--; // Visual feedback LK.effects.flashObject(self, 0x2980b9, 200); // Adjust opacity based on remaining HP self.alpha = self.hp / 3; if (self.hp <= 0) { self.destroy(); var index = shields.indexOf(self); if (index > -1) { shields.splice(index, 1); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var GAME_MARGIN = 100; var ENEMY_ROWS = 5; var ENEMY_COLUMNS = 8; var ENEMY_SPACING_X = 150; var ENEMY_SPACING_Y = 120; var ENEMY_START_Y = 300; var GROUP_MOVE_AMOUNT = 15; var GROUP_DROP_AMOUNT = 40; var MOVE_INTERVAL = 800; // ms // Game variables var level = storage.level || 1; var player; var bullets = []; var enemies = []; var enemyBullets = []; var shields = []; var powerUps = []; var enemyMoveTimer; var movingRight = true; var bossActive = false; var touchX = null; // Create UI elements var scoreTxt = new Text2('0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(scoreTxt); scoreTxt.x = -250; // Offset from the right edge var levelTxt = new Text2('LEVEL ' + level, { size: 60, fill: 0xFFFFFF }); levelTxt.anchor.set(0.5, 0); LK.gui.top.addChild(levelTxt); var livesTxt = new Text2('LIVES: 3', { size: 60, fill: 0xFFFFFF }); livesTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(livesTxt); livesTxt.x = 120; // Ensure we don't place this in the top-left 100x100 area // Game functions function initializeGame() { // Reset game state clearArrays(); // Set difficulty based on level var enemyHp = Math.min(Math.floor(level / 3) + 1, 3); var enemySpeed = Math.min(2 + level * 0.5, 8); var moveInterval = Math.max(MOVE_INTERVAL - level * 50, 300); // Add space background var spaceBackground = LK.getAsset('spaceBackground', { anchorX: 0.5, anchorY: 0.5 }); spaceBackground.x = GAME_WIDTH / 2; spaceBackground.y = GAME_HEIGHT / 2; game.addChild(spaceBackground); // Create player if not already created if (!player) { player = new PlayerShip(); player.x = GAME_WIDTH / 2; player.y = GAME_HEIGHT - 200; game.addChild(player); } // Create enemies createEnemies(enemyHp); // Start enemy movement startEnemyMovement(moveInterval); // Reset score if starting a new game if (level === 1) { LK.setScore(0); } // Update UI scoreTxt.setText(LK.getScore()); levelTxt.setText('LEVEL ' + level); // Play music LK.playMusic('gameMusic', { fade: { start: 0, end: 0.8, duration: 1000 } }); } function clearArrays() { // Clear existing game objects for (var i = bullets.length - 1; i >= 0; i--) { bullets[i].destroy(); } for (var i = enemies.length - 1; i >= 0; i--) { enemies[i].destroy(); } for (var i = enemyBullets.length - 1; i >= 0; i--) { enemyBullets[i].destroy(); } for (var i = shields.length - 1; i >= 0; i--) { shields[i].destroy(); } for (var i = powerUps.length - 1; i >= 0; i--) { powerUps[i].destroy(); } bullets = []; enemies = []; enemyBullets = []; shields = []; powerUps = []; // Clear any existing timers if (enemyMoveTimer) { LK.clearInterval(enemyMoveTimer); } } function createEnemies(hp) { bossActive = false; // Boss level every 5 levels if (level % 5 === 0) { createBoss(); return; } // Create grid of enemies var startX = (GAME_WIDTH - (ENEMY_COLUMNS - 1) * ENEMY_SPACING_X) / 2; for (var row = 0; row < ENEMY_ROWS; row++) { for (var col = 0; col < ENEMY_COLUMNS; col++) { var enemy = new Enemy(); // Different types/strength based on row if (row === 0) { enemy.hp = hp + 1; enemy.scoreValue = 300; enemy.tint = 0xff0000; // Red top row } else if (row === 1 || row === 2) { enemy.hp = hp; enemy.scoreValue = 200; enemy.tint = 0x00ff00; // Green middle rows } else { enemy.hp = Math.max(1, hp - 1); enemy.scoreValue = 100; enemy.tint = 0x0000ff; // Blue bottom rows } enemy.x = startX + col * ENEMY_SPACING_X; enemy.y = ENEMY_START_Y + row * ENEMY_SPACING_Y; game.addChild(enemy); enemies.push(enemy); } } } function createBoss() { bossActive = true; var boss = new Boss(); boss.x = GAME_WIDTH / 2; boss.y = 300; boss.hp = 15 + level / 5 * 5; // Increases with level game.addChild(boss); enemies.push(boss); boss.startAttackPattern(); } function startEnemyMovement(interval) { enemyMoveTimer = LK.setInterval(function () { moveEnemyGroup(); }, interval); } function moveEnemyGroup() { if (enemies.length === 0) { return; } var reachedEdge = false; var moveAmount = bossActive ? GROUP_MOVE_AMOUNT * 1.5 : GROUP_MOVE_AMOUNT; // Check if any enemy would go beyond screen edge for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; if (movingRight && enemy.x + enemy.width / 2 + moveAmount > GAME_WIDTH - GAME_MARGIN || !movingRight && enemy.x - enemy.width / 2 - moveAmount < GAME_MARGIN) { reachedEdge = true; break; } } // Move group horizontally or drop and change direction if (reachedEdge) { movingRight = !movingRight; // Move all enemies down for (var i = 0; i < enemies.length; i++) { enemies[i].y += GROUP_DROP_AMOUNT; } // Check if enemies reached player's area checkEnemiesBottom(); } else { // Move enemies sideways for (var i = 0; i < enemies.length; i++) { enemies[i].x += movingRight ? moveAmount : -moveAmount; } } // Try to make some enemies shoot for (var i = 0; i < enemies.length; i++) { enemies[i].shoot(); } } function checkEnemiesBottom() { for (var i = 0; i < enemies.length; i++) { if (enemies[i].y + enemies[i].height / 2 > player.y - 100) { // Game over if enemies get too close to bottom LK.showGameOver(); return; } } } function createShield() { var shield = new Shield(); shield.x = player.x; shield.y = player.y - 80; game.addChild(shield); shields.push(shield); } function levelComplete() { LK.getSound('levelComplete').play(); // Save high score if it's better than previous if (LK.getScore() > storage.highScore) { storage.highScore = LK.getScore(); } // Increment level level++; storage.level = level; // Show level transition var levelCompleteTxt = new Text2('LEVEL COMPLETE!', { size: 120, fill: 0xFFFFFF }); levelCompleteTxt.anchor.set(0.5, 0.5); levelCompleteTxt.x = GAME_WIDTH / 2; levelCompleteTxt.y = GAME_HEIGHT / 2; game.addChild(levelCompleteTxt); // Fade out current level tween(levelCompleteTxt, { alpha: 0 }, { duration: 2000, onFinish: function onFinish() { levelCompleteTxt.destroy(); // Start next level initializeGame(); } }); } function checkCollisions() { // Player bullets vs enemies for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { // Handle hit enemy.takeDamage(); // Remove bullet bullet.destroy(); bullets.splice(i, 1); break; } } } // Enemy bullets vs player for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; // Check for shield hits first var hitShield = false; for (var j = shields.length - 1; j >= 0; j--) { var shield = shields[j]; if (bullet.intersects(shield)) { shield.takeDamage(); // Remove bullet bullet.destroy(); enemyBullets.splice(i, 1); hitShield = true; break; } } if (hitShield) { continue; } // Check for player hit if (bullet.intersects(player)) { player.hit(); // Remove bullet bullet.destroy(); enemyBullets.splice(i, 1); } } // Player vs power-ups for (var i = powerUps.length - 1; i >= 0; i--) { var powerUp = powerUps[i]; if (powerUp.intersects(player)) { player.activatePowerUp(powerUp.type); // Remove power-up powerUp.destroy(); powerUps.splice(i, 1); } } // Update lives display livesTxt.setText('LIVES: ' + player.lives); } function movePlayer() { // If touch input is active, move towards it if (touchX !== null) { var moveSpeed = player.speed; var distanceToTouch = touchX - player.x; if (Math.abs(distanceToTouch) < moveSpeed) { player.x = touchX; } else if (distanceToTouch > 0) { player.x += moveSpeed; } else { player.x -= moveSpeed; } } // Keep player within screen bounds if (player.x < GAME_MARGIN + player.width / 2) { player.x = GAME_MARGIN + player.width / 2; } else if (player.x > GAME_WIDTH - GAME_MARGIN - player.width / 2) { player.x = GAME_WIDTH - GAME_MARGIN - player.width / 2; } } // Handle touch/mouse input game.down = function (x, y, obj) { touchX = x; // Shoot when tapping player.shoot(); }; game.move = function (x, y, obj) { touchX = x; }; game.up = function (x, y, obj) { touchX = null; }; // Game update loop game.update = function () { movePlayer(); // Update all game objects for (var i = 0; i < bullets.length; i++) { bullets[i].update(); } for (var i = 0; i < enemyBullets.length; i++) { enemyBullets[i].update(); } for (var i = 0; i < powerUps.length; i++) { powerUps[i].update(); } // Check for collisions checkCollisions(); }; // Initialize the game initializeGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
level: 1
});
/****
* Classes
****/
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = enemyGraphics.width;
self.height = enemyGraphics.height;
self.hp = 1;
self.scoreValue = 100;
self.canShoot = true;
self.movingRight = true;
self.moveSpeed = 2;
self.dropDistance = 40;
self.shoot = function () {
if (!self.canShoot || Math.random() > 0.01) {
return;
} // Random chance to shoot
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + self.height / 2;
game.addChild(bullet);
enemyBullets.push(bullet);
// Cooldown between shots
self.canShoot = false;
LK.setTimeout(function () {
self.canShoot = true;
}, 2000);
};
self.takeDamage = function () {
self.hp--;
if (self.hp <= 0) {
// Update score
LK.setScore(LK.getScore() + self.scoreValue);
scoreTxt.setText(LK.getScore());
// Chance to drop power-up
if (Math.random() < 0.1) {
// 10% chance
var powerUp = new PowerUp();
powerUp.x = self.x;
powerUp.y = self.y;
game.addChild(powerUp);
powerUps.push(powerUp);
}
// Play sound
LK.getSound('enemyDestroyed').play();
// Visual effect
LK.effects.flashObject(self, 0xffff00, 300);
// Remove enemy
self.destroy();
var index = enemies.indexOf(self);
if (index > -1) {
enemies.splice(index, 1);
}
// Check if level complete
if (enemies.length === 0) {
levelComplete();
}
} else {
// Visual effect for damage
LK.effects.flashObject(self, 0xffff00, 200);
}
};
return self;
});
var Boss = Enemy.expand(function () {
var self = Enemy.call(this);
// Replace graphics with boss graphics
self.removeChildAt(0);
var bossGraphics = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = bossGraphics.width;
self.height = bossGraphics.height;
self.hp = 20;
self.scoreValue = 2000;
self.moveSpeed = 3;
self.attackPattern = 0;
self.attackTimer = null;
self.startAttackPattern = function () {
self.attackTimer = LK.setInterval(function () {
self.performAttack();
}, 2000);
};
self.performAttack = function () {
self.attackPattern = (self.attackPattern + 1) % 3;
switch (self.attackPattern) {
case 0:
// Single strong shot
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + self.height / 2;
bullet.speed = 8;
bullet.scale.set(2, 2);
game.addChild(bullet);
enemyBullets.push(bullet);
break;
case 1:
// Multiple shots in a spread
for (var i = -2; i <= 2; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x + i * 40;
bullet.y = self.y + self.height / 2;
game.addChild(bullet);
enemyBullets.push(bullet);
}
break;
case 2:
// Wave pattern of bullets
var interval = LK.setInterval(function () {
var bullet = new EnemyBullet();
bullet.x = self.x + (Math.random() * 200 - 100);
bullet.y = self.y + self.height / 2;
game.addChild(bullet);
enemyBullets.push(bullet);
}, 200);
LK.setTimeout(function () {
LK.clearInterval(interval);
}, 1000);
break;
}
};
var parentTakeDamage = self.takeDamage;
self.takeDamage = function () {
parentTakeDamage.call(self);
// When boss is destroyed, clear the attack timer
if (self.hp <= 0 && self.attackTimer) {
LK.clearInterval(self.attackTimer);
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.update = function () {
self.y += self.speed;
// Destroy if out of bounds
if (self.y > 2732 + 50) {
self.destroy();
var index = enemyBullets.indexOf(self);
if (index > -1) {
enemyBullets.splice(index, 1);
}
}
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -15; // Negative because moving upward
self.update = function () {
self.y += self.speed;
// Destroy if out of bounds
if (self.y < -50) {
self.destroy();
var index = bullets.indexOf(self);
if (index > -1) {
bullets.splice(index, 1);
}
}
};
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5,
flipX: 1 // Flip the spaceship horizontally
});
self.width = shipGraphics.width;
self.height = shipGraphics.height;
self.lives = 3;
self.speed = 15;
self.canShoot = true;
self.shootCooldown = 300; // milliseconds
self.invulnerable = false;
self.powerUpActive = false;
self.startShootCooldown = function () {
self.canShoot = false;
LK.setTimeout(function () {
self.canShoot = true;
}, self.shootCooldown);
};
self.shoot = function () {
if (!self.canShoot) {
return;
}
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - self.height / 2;
game.addChild(bullet);
bullets.push(bullet);
LK.getSound('shoot').play();
self.startShootCooldown();
// Create double bullet when power-up is active
if (self.powerUpActive) {
var bulletLeft = new PlayerBullet();
bulletLeft.x = self.x - 20;
bulletLeft.y = self.y - self.height / 2;
var bulletRight = new PlayerBullet();
bulletRight.x = self.x + 20;
bulletRight.y = self.y - self.height / 2;
game.addChild(bulletLeft);
game.addChild(bulletRight);
bullets.push(bulletLeft);
bullets.push(bulletRight);
}
};
self.hit = function () {
if (self.invulnerable) {
return;
}
self.lives--;
LK.getSound('playerHit').play();
// Flash player ship to indicate damage
LK.effects.flashObject(self, 0xff0000, 1000);
// Make player temporarily invulnerable
self.invulnerable = true;
LK.setTimeout(function () {
self.invulnerable = false;
}, 2000);
// Check for game over
if (self.lives <= 0) {
LK.showGameOver();
}
};
self.activatePowerUp = function (type) {
LK.getSound('powerUpCollected').play();
switch (type) {
case 'rapidFire':
var oldCooldown = self.shootCooldown;
self.shootCooldown = 150;
LK.setTimeout(function () {
self.shootCooldown = oldCooldown;
}, 5000);
break;
case 'doubleBullet':
self.powerUpActive = true;
LK.setTimeout(function () {
self.powerUpActive = false;
}, 8000);
break;
case 'shield':
// Create shield
createShield();
break;
}
};
self.update = function () {
// Movement logic handled in game.update
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.type = ['rapidFire', 'doubleBullet', 'shield'][Math.floor(Math.random() * 3)];
// Set color based on power-up type
switch (self.type) {
case 'rapidFire':
powerUpGraphics.tint = 0xff0000; // Red
break;
case 'doubleBullet':
powerUpGraphics.tint = 0x00ff00; // Green
break;
case 'shield':
powerUpGraphics.tint = 0x0000ff; // Blue
break;
}
self.update = function () {
self.y += self.speed;
// Destroy if out of bounds
if (self.y > 2732 + 50) {
self.destroy();
var index = powerUps.indexOf(self);
if (index > -1) {
powerUps.splice(index, 1);
}
}
};
return self;
});
var Shield = Container.expand(function () {
var self = Container.call(this);
var shieldGraphics = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5
});
self.hp = 3;
self.takeDamage = function () {
self.hp--;
// Visual feedback
LK.effects.flashObject(self, 0x2980b9, 200);
// Adjust opacity based on remaining HP
self.alpha = self.hp / 3;
if (self.hp <= 0) {
self.destroy();
var index = shields.indexOf(self);
if (index > -1) {
shields.splice(index, 1);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var GAME_MARGIN = 100;
var ENEMY_ROWS = 5;
var ENEMY_COLUMNS = 8;
var ENEMY_SPACING_X = 150;
var ENEMY_SPACING_Y = 120;
var ENEMY_START_Y = 300;
var GROUP_MOVE_AMOUNT = 15;
var GROUP_DROP_AMOUNT = 40;
var MOVE_INTERVAL = 800; // ms
// Game variables
var level = storage.level || 1;
var player;
var bullets = [];
var enemies = [];
var enemyBullets = [];
var shields = [];
var powerUps = [];
var enemyMoveTimer;
var movingRight = true;
var bossActive = false;
var touchX = null;
// Create UI elements
var scoreTxt = new Text2('0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -250; // Offset from the right edge
var levelTxt = new Text2('LEVEL ' + level, {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
var livesTxt = new Text2('LIVES: 3', {
size: 60,
fill: 0xFFFFFF
});
livesTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(livesTxt);
livesTxt.x = 120; // Ensure we don't place this in the top-left 100x100 area
// Game functions
function initializeGame() {
// Reset game state
clearArrays();
// Set difficulty based on level
var enemyHp = Math.min(Math.floor(level / 3) + 1, 3);
var enemySpeed = Math.min(2 + level * 0.5, 8);
var moveInterval = Math.max(MOVE_INTERVAL - level * 50, 300);
// Add space background
var spaceBackground = LK.getAsset('spaceBackground', {
anchorX: 0.5,
anchorY: 0.5
});
spaceBackground.x = GAME_WIDTH / 2;
spaceBackground.y = GAME_HEIGHT / 2;
game.addChild(spaceBackground);
// Create player if not already created
if (!player) {
player = new PlayerShip();
player.x = GAME_WIDTH / 2;
player.y = GAME_HEIGHT - 200;
game.addChild(player);
}
// Create enemies
createEnemies(enemyHp);
// Start enemy movement
startEnemyMovement(moveInterval);
// Reset score if starting a new game
if (level === 1) {
LK.setScore(0);
}
// Update UI
scoreTxt.setText(LK.getScore());
levelTxt.setText('LEVEL ' + level);
// Play music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.8,
duration: 1000
}
});
}
function clearArrays() {
// Clear existing game objects
for (var i = bullets.length - 1; i >= 0; i--) {
bullets[i].destroy();
}
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
}
for (var i = enemyBullets.length - 1; i >= 0; i--) {
enemyBullets[i].destroy();
}
for (var i = shields.length - 1; i >= 0; i--) {
shields[i].destroy();
}
for (var i = powerUps.length - 1; i >= 0; i--) {
powerUps[i].destroy();
}
bullets = [];
enemies = [];
enemyBullets = [];
shields = [];
powerUps = [];
// Clear any existing timers
if (enemyMoveTimer) {
LK.clearInterval(enemyMoveTimer);
}
}
function createEnemies(hp) {
bossActive = false;
// Boss level every 5 levels
if (level % 5 === 0) {
createBoss();
return;
}
// Create grid of enemies
var startX = (GAME_WIDTH - (ENEMY_COLUMNS - 1) * ENEMY_SPACING_X) / 2;
for (var row = 0; row < ENEMY_ROWS; row++) {
for (var col = 0; col < ENEMY_COLUMNS; col++) {
var enemy = new Enemy();
// Different types/strength based on row
if (row === 0) {
enemy.hp = hp + 1;
enemy.scoreValue = 300;
enemy.tint = 0xff0000; // Red top row
} else if (row === 1 || row === 2) {
enemy.hp = hp;
enemy.scoreValue = 200;
enemy.tint = 0x00ff00; // Green middle rows
} else {
enemy.hp = Math.max(1, hp - 1);
enemy.scoreValue = 100;
enemy.tint = 0x0000ff; // Blue bottom rows
}
enemy.x = startX + col * ENEMY_SPACING_X;
enemy.y = ENEMY_START_Y + row * ENEMY_SPACING_Y;
game.addChild(enemy);
enemies.push(enemy);
}
}
}
function createBoss() {
bossActive = true;
var boss = new Boss();
boss.x = GAME_WIDTH / 2;
boss.y = 300;
boss.hp = 15 + level / 5 * 5; // Increases with level
game.addChild(boss);
enemies.push(boss);
boss.startAttackPattern();
}
function startEnemyMovement(interval) {
enemyMoveTimer = LK.setInterval(function () {
moveEnemyGroup();
}, interval);
}
function moveEnemyGroup() {
if (enemies.length === 0) {
return;
}
var reachedEdge = false;
var moveAmount = bossActive ? GROUP_MOVE_AMOUNT * 1.5 : GROUP_MOVE_AMOUNT;
// Check if any enemy would go beyond screen edge
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (movingRight && enemy.x + enemy.width / 2 + moveAmount > GAME_WIDTH - GAME_MARGIN || !movingRight && enemy.x - enemy.width / 2 - moveAmount < GAME_MARGIN) {
reachedEdge = true;
break;
}
}
// Move group horizontally or drop and change direction
if (reachedEdge) {
movingRight = !movingRight;
// Move all enemies down
for (var i = 0; i < enemies.length; i++) {
enemies[i].y += GROUP_DROP_AMOUNT;
}
// Check if enemies reached player's area
checkEnemiesBottom();
} else {
// Move enemies sideways
for (var i = 0; i < enemies.length; i++) {
enemies[i].x += movingRight ? moveAmount : -moveAmount;
}
}
// Try to make some enemies shoot
for (var i = 0; i < enemies.length; i++) {
enemies[i].shoot();
}
}
function checkEnemiesBottom() {
for (var i = 0; i < enemies.length; i++) {
if (enemies[i].y + enemies[i].height / 2 > player.y - 100) {
// Game over if enemies get too close to bottom
LK.showGameOver();
return;
}
}
}
function createShield() {
var shield = new Shield();
shield.x = player.x;
shield.y = player.y - 80;
game.addChild(shield);
shields.push(shield);
}
function levelComplete() {
LK.getSound('levelComplete').play();
// Save high score if it's better than previous
if (LK.getScore() > storage.highScore) {
storage.highScore = LK.getScore();
}
// Increment level
level++;
storage.level = level;
// Show level transition
var levelCompleteTxt = new Text2('LEVEL COMPLETE!', {
size: 120,
fill: 0xFFFFFF
});
levelCompleteTxt.anchor.set(0.5, 0.5);
levelCompleteTxt.x = GAME_WIDTH / 2;
levelCompleteTxt.y = GAME_HEIGHT / 2;
game.addChild(levelCompleteTxt);
// Fade out current level
tween(levelCompleteTxt, {
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
levelCompleteTxt.destroy();
// Start next level
initializeGame();
}
});
}
function checkCollisions() {
// Player bullets vs enemies
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
// Handle hit
enemy.takeDamage();
// Remove bullet
bullet.destroy();
bullets.splice(i, 1);
break;
}
}
}
// Enemy bullets vs player
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
// Check for shield hits first
var hitShield = false;
for (var j = shields.length - 1; j >= 0; j--) {
var shield = shields[j];
if (bullet.intersects(shield)) {
shield.takeDamage();
// Remove bullet
bullet.destroy();
enemyBullets.splice(i, 1);
hitShield = true;
break;
}
}
if (hitShield) {
continue;
}
// Check for player hit
if (bullet.intersects(player)) {
player.hit();
// Remove bullet
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
// Player vs power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (powerUp.intersects(player)) {
player.activatePowerUp(powerUp.type);
// Remove power-up
powerUp.destroy();
powerUps.splice(i, 1);
}
}
// Update lives display
livesTxt.setText('LIVES: ' + player.lives);
}
function movePlayer() {
// If touch input is active, move towards it
if (touchX !== null) {
var moveSpeed = player.speed;
var distanceToTouch = touchX - player.x;
if (Math.abs(distanceToTouch) < moveSpeed) {
player.x = touchX;
} else if (distanceToTouch > 0) {
player.x += moveSpeed;
} else {
player.x -= moveSpeed;
}
}
// Keep player within screen bounds
if (player.x < GAME_MARGIN + player.width / 2) {
player.x = GAME_MARGIN + player.width / 2;
} else if (player.x > GAME_WIDTH - GAME_MARGIN - player.width / 2) {
player.x = GAME_WIDTH - GAME_MARGIN - player.width / 2;
}
}
// Handle touch/mouse input
game.down = function (x, y, obj) {
touchX = x;
// Shoot when tapping
player.shoot();
};
game.move = function (x, y, obj) {
touchX = x;
};
game.up = function (x, y, obj) {
touchX = null;
};
// Game update loop
game.update = function () {
movePlayer();
// Update all game objects
for (var i = 0; i < bullets.length; i++) {
bullets[i].update();
}
for (var i = 0; i < enemyBullets.length; i++) {
enemyBullets[i].update();
}
for (var i = 0; i < powerUps.length; i++) {
powerUps[i].update();
}
// Check for collisions
checkCollisions();
};
// Initialize the game
initializeGame();