/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphic = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -15;
self.active = true;
self.update = function () {
if (!self.active) {
return;
}
self.y += self.speed;
if (self.y < -50) {
self.active = false;
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphic = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.active = true;
self.movementPattern = "straight";
self.movementPhase = 0;
self.speed = Math.random() * 2 + 1;
self.fireRate = 180; // Frames between shots
self.fireCooldown = Math.floor(Math.random() * 180);
self.health = 1;
self.initialize = function (pattern, speed, health) {
self.movementPattern = pattern || "straight";
self.speed = speed || Math.random() * 2 + 1;
self.health = health || 1;
return self;
};
self.update = function () {
if (!self.active) {
return;
}
self.movementPhase += 0.02;
// Different movement patterns
switch (self.movementPattern) {
case "straight":
self.y += self.speed;
break;
case "sine":
self.y += self.speed;
self.x += Math.sin(self.movementPhase) * 3;
break;
case "zigzag":
self.y += self.speed;
self.x += Math.sin(self.movementPhase * 2) > 0 ? 2 : -2;
break;
}
// Check if off screen
if (self.y > 2732 + 50) {
self.active = false;
}
// Handle shooting
if (self.fireCooldown > 0) {
self.fireCooldown--;
} else {
self.shoot();
self.fireCooldown = self.fireRate;
}
};
self.shoot = function () {
if (player && Math.random() < 0.3) {
// 30% chance to shoot
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 25;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
self.hit = function () {
self.health--;
if (self.health <= 0) {
LK.getSound('enemyExplode').play();
LK.effects.flashObject(self, 0xffffff, 300);
// Chance to spawn powerup
if (Math.random() < 0.1) {
// 10% chance
spawnPowerup(self.x, self.y);
}
self.active = false;
return true;
}
return false;
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphic = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.active = true;
self.update = function () {
if (!self.active) {
return;
}
self.y += self.speed;
if (self.y > 2732 + 50) {
self.active = false;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphic = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.fireRate = 15; // Frames between shots
self.fireCooldown = 0;
self.lives = 3;
self.invulnerable = false;
self.invulnerableTime = 0;
self.powerupTime = 0;
self.hasPowerup = false;
self.update = function () {
if (self.fireCooldown > 0) {
self.fireCooldown--;
}
if (self.invulnerable) {
self.invulnerableTime--;
// Flash effect when invulnerable
self.alpha = Math.sin(LK.ticks * 0.5) * 0.5 + 0.5;
if (self.invulnerableTime <= 0) {
self.invulnerable = false;
self.alpha = 1;
}
}
if (self.hasPowerup) {
self.powerupTime--;
if (self.powerupTime <= 0) {
self.hasPowerup = false;
// Reset fire rate when powerup ends
self.fireRate = 15;
}
}
};
self.shoot = function () {
if (self.fireCooldown <= 0) {
LK.getSound('playerShoot').play();
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y - 30;
bullet.lastY = bullet.y;
bullets.push(bullet);
game.addChild(bullet);
// If player has powerup, create side bullets
if (self.hasPowerup) {
var bulletLeft = new Bullet();
bulletLeft.x = self.x - 30;
bulletLeft.y = self.y - 20;
bulletLeft.lastY = bulletLeft.y;
var bulletRight = new Bullet();
bulletRight.x = self.x + 30;
bulletRight.y = self.y - 20;
bulletRight.lastY = bulletRight.y;
bullets.push(bulletLeft, bulletRight);
game.addChild(bulletLeft, bulletRight);
}
self.fireCooldown = self.fireRate;
}
};
self.hit = function () {
if (self.invulnerable) {
return;
}
LK.getSound('playerHit').play();
self.lives--;
LK.effects.flashObject(self, 0xff0000, 500);
if (self.lives <= 0) {
// Game over handled by the game class
return true;
} else {
// Make player invulnerable for a short time
self.invulnerable = true;
self.invulnerableTime = 120; // 2 seconds at 60fps
return false;
}
};
self.activatePowerup = function () {
self.hasPowerup = true;
self.powerupTime = 600; // 10 seconds at 60fps
self.fireRate = 8; // Faster firing with powerup
};
return self;
});
var Powerup = Container.expand(function () {
var self = Container.call(this);
var powerupGraphic = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.active = true;
self.speed = 3;
self.update = function () {
if (!self.active) {
return;
}
self.y += self.speed;
// Gentle oscillation effect
self.x += Math.sin(LK.ticks * 0.05) * 0.5;
// Check if off screen
if (self.y > 2732 + 50) {
self.active = false;
}
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphic = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = Math.random() * 3 + 1;
self.update = function () {
self.y += self.speed;
if (self.y > 2732) {
self.y = -10;
self.x = Math.random() * 2048;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000022
});
/****
* Game Code
****/
// Game variables
var player;
var bullets = [];
var enemies = [];
var enemyBullets = [];
var powerups = [];
var stars = [];
var gameState = "playing";
var score = 0;
var level = 1;
var enemySpawnTimer = 0;
var levelTimer = 0;
var dragTarget = null;
// Game UI elements
var scoreTxt;
var livesText;
var levelText;
// Initialize game function
function initGame() {
// Reset game state
bullets = [];
enemies = [];
enemyBullets = [];
powerups = [];
score = 0;
level = 1;
gameState = "playing";
// Create player
player = new Player();
player.x = 2048 / 2;
player.y = 2732 - 200;
game.addChild(player);
// Create background stars
createStars();
// Initialize UI
initUI();
// Start game music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
}
function createStars() {
// Clear existing stars
for (var i = 0; i < stars.length; i++) {
if (stars[i].parent) {
stars[i].parent.removeChild(stars[i]);
}
}
stars = [];
// Create new stars
for (var i = 0; i < 100; i++) {
var star = new Star();
star.x = Math.random() * 2048;
star.y = Math.random() * 2732;
stars.push(star);
game.addChild(star);
}
}
function initUI() {
// Score text
scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -300; // Offset from right edge
// Lives text
livesText = new Text2('Lives: 3', {
size: 60,
fill: 0xFFFFFF
});
livesText.anchor.set(0, 0);
LK.gui.top.addChild(livesText);
livesText.x = -200; // Offset from center
// Level text
levelText = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(0, 0);
LK.gui.top.addChild(levelText);
levelText.x = 200; // Offset from center
}
function updateUI() {
scoreTxt.setText('Score: ' + score);
livesText.setText('Lives: ' + player.lives);
levelText.setText('Level: ' + level);
}
function spawnEnemy() {
var enemy = new Enemy();
// Set initial position
enemy.x = Math.random() * (2048 - 200) + 100;
enemy.y = -50;
// Set properties based on level
var pattern = "straight";
var health = 1;
var spd = 1 + level * 0.2;
// Higher levels get more complex enemies
if (level > 1) {
if (Math.random() < 0.3) {
pattern = "sine";
}
}
if (level > 3) {
if (Math.random() < 0.3) {
pattern = "zigzag";
}
if (Math.random() < 0.2) {
health = 2;
}
}
if (level > 5) {
spd += 1;
if (Math.random() < 0.3) {
health = 3;
}
}
enemy.initialize(pattern, spd, health);
enemies.push(enemy);
game.addChild(enemy);
}
function spawnPowerup(x, y) {
var powerup = new Powerup();
powerup.x = x;
powerup.y = y;
powerups.push(powerup);
game.addChild(powerup);
}
function handleCollisions() {
// Player bullets vs enemies
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (!bullet.active) {
continue;
}
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (!enemy.active) {
continue;
}
if (bullet.intersects(enemy)) {
bullet.active = false;
if (bullet.parent) {
bullet.parent.removeChild(bullet);
}
bullets.splice(i, 1);
if (enemy.hit()) {
score += 10 * level;
if (enemy.parent) {
enemy.parent.removeChild(enemy);
}
enemies.splice(j, 1);
}
break;
}
}
}
// Enemy bullets vs player
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (!bullet.active) {
continue;
}
if (player && bullet.intersects(player)) {
bullet.active = false;
if (bullet.parent) {
bullet.parent.removeChild(bullet);
}
enemyBullets.splice(i, 1);
if (player.hit()) {
// Game over
gameOver();
}
}
}
// Enemies vs player
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (!enemy.active) {
continue;
}
if (player && enemy.intersects(player)) {
enemy.active = false;
if (enemy.parent) {
enemy.parent.removeChild(enemy);
}
enemies.splice(i, 1);
if (player.hit()) {
// Game over
gameOver();
}
}
}
// Powerups vs player
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
if (!powerup.active) {
continue;
}
if (player && powerup.intersects(player)) {
powerup.active = false;
if (powerup.parent) {
powerup.parent.removeChild(powerup);
}
powerups.splice(i, 1);
// Activate powerup effect
player.activatePowerup();
LK.getSound('powerupCollect').play();
score += 50;
}
}
}
function clearInactiveObjects() {
// Clear inactive bullets
for (var i = bullets.length - 1; i >= 0; i--) {
if (!bullets[i].active) {
if (bullets[i].parent) {
bullets[i].parent.removeChild(bullets[i]);
}
bullets.splice(i, 1);
}
}
// Clear inactive enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
if (!enemyBullets[i].active) {
if (enemyBullets[i].parent) {
enemyBullets[i].parent.removeChild(enemyBullets[i]);
}
enemyBullets.splice(i, 1);
}
}
// Clear inactive enemies
for (var i = enemies.length - 1; i >= 0; i--) {
if (!enemies[i].active) {
if (enemies[i].parent) {
enemies[i].parent.removeChild(enemies[i]);
}
enemies.splice(i, 1);
}
}
// Clear inactive powerups
for (var i = powerups.length - 1; i >= 0; i--) {
if (!powerups[i].active) {
if (powerups[i].parent) {
powerups[i].parent.removeChild(powerups[i]);
}
powerups.splice(i, 1);
}
}
}
function gameOver() {
gameState = "over";
// Update high score if needed
if (score > storage.highScore) {
storage.highScore = score;
console.log("New high score: " + score);
}
// Fade out music
LK.playMusic('gameMusic', {
fade: {
start: 0.7,
end: 0,
duration: 1000
}
});
// Show game over
LK.effects.flashScreen(0xff0000, 800);
// Let the engine handle game over
LK.setScore(score);
LK.showGameOver();
}
function handleInput(x, y) {
if (player && gameState === "playing") {
player.x = x;
// Keep player in bounds
if (player.x < 50) {
player.x = 50;
}
if (player.x > 2048 - 50) {
player.x = 2048 - 50;
}
// Always shoot when moving
player.shoot();
}
}
// Event handlers
game.down = function (x, y, obj) {
dragTarget = player;
handleInput(x, y);
};
game.up = function (x, y, obj) {
dragTarget = null;
};
game.move = function (x, y, obj) {
if (dragTarget) {
handleInput(x, y);
}
};
// Main game update function
game.update = function () {
if (gameState !== "playing") {
return;
}
// Update player
if (player) {
player.update();
}
// Update all game objects
for (var i = 0; i < bullets.length; i++) {
bullets[i].update();
}
for (var i = 0; i < enemies.length; i++) {
enemies[i].update();
}
for (var i = 0; i < enemyBullets.length; i++) {
enemyBullets[i].update();
}
for (var i = 0; i < powerups.length; i++) {
powerups[i].update();
}
for (var i = 0; i < stars.length; i++) {
stars[i].update();
}
// Check for collisions
handleCollisions();
// Clean up inactive objects
clearInactiveObjects();
// Spawn enemies based on level
enemySpawnTimer--;
if (enemySpawnTimer <= 0) {
spawnEnemy();
// Spawn rate decreases (gets faster) with level
enemySpawnTimer = Math.max(20, 100 - level * 10);
}
// Level progression
levelTimer++;
if (levelTimer >= 1800) {
// 30 seconds at 60fps
level++;
levelTimer = 0;
// Spawn a powerup when leveling up
spawnPowerup(Math.random() * 2048, 100);
}
// Update UI
updateUI();
};
// Initialize the game
initGame(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphic = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -15;
self.active = true;
self.update = function () {
if (!self.active) {
return;
}
self.y += self.speed;
if (self.y < -50) {
self.active = false;
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphic = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.active = true;
self.movementPattern = "straight";
self.movementPhase = 0;
self.speed = Math.random() * 2 + 1;
self.fireRate = 180; // Frames between shots
self.fireCooldown = Math.floor(Math.random() * 180);
self.health = 1;
self.initialize = function (pattern, speed, health) {
self.movementPattern = pattern || "straight";
self.speed = speed || Math.random() * 2 + 1;
self.health = health || 1;
return self;
};
self.update = function () {
if (!self.active) {
return;
}
self.movementPhase += 0.02;
// Different movement patterns
switch (self.movementPattern) {
case "straight":
self.y += self.speed;
break;
case "sine":
self.y += self.speed;
self.x += Math.sin(self.movementPhase) * 3;
break;
case "zigzag":
self.y += self.speed;
self.x += Math.sin(self.movementPhase * 2) > 0 ? 2 : -2;
break;
}
// Check if off screen
if (self.y > 2732 + 50) {
self.active = false;
}
// Handle shooting
if (self.fireCooldown > 0) {
self.fireCooldown--;
} else {
self.shoot();
self.fireCooldown = self.fireRate;
}
};
self.shoot = function () {
if (player && Math.random() < 0.3) {
// 30% chance to shoot
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 25;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
self.hit = function () {
self.health--;
if (self.health <= 0) {
LK.getSound('enemyExplode').play();
LK.effects.flashObject(self, 0xffffff, 300);
// Chance to spawn powerup
if (Math.random() < 0.1) {
// 10% chance
spawnPowerup(self.x, self.y);
}
self.active = false;
return true;
}
return false;
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphic = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.active = true;
self.update = function () {
if (!self.active) {
return;
}
self.y += self.speed;
if (self.y > 2732 + 50) {
self.active = false;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphic = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.fireRate = 15; // Frames between shots
self.fireCooldown = 0;
self.lives = 3;
self.invulnerable = false;
self.invulnerableTime = 0;
self.powerupTime = 0;
self.hasPowerup = false;
self.update = function () {
if (self.fireCooldown > 0) {
self.fireCooldown--;
}
if (self.invulnerable) {
self.invulnerableTime--;
// Flash effect when invulnerable
self.alpha = Math.sin(LK.ticks * 0.5) * 0.5 + 0.5;
if (self.invulnerableTime <= 0) {
self.invulnerable = false;
self.alpha = 1;
}
}
if (self.hasPowerup) {
self.powerupTime--;
if (self.powerupTime <= 0) {
self.hasPowerup = false;
// Reset fire rate when powerup ends
self.fireRate = 15;
}
}
};
self.shoot = function () {
if (self.fireCooldown <= 0) {
LK.getSound('playerShoot').play();
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y - 30;
bullet.lastY = bullet.y;
bullets.push(bullet);
game.addChild(bullet);
// If player has powerup, create side bullets
if (self.hasPowerup) {
var bulletLeft = new Bullet();
bulletLeft.x = self.x - 30;
bulletLeft.y = self.y - 20;
bulletLeft.lastY = bulletLeft.y;
var bulletRight = new Bullet();
bulletRight.x = self.x + 30;
bulletRight.y = self.y - 20;
bulletRight.lastY = bulletRight.y;
bullets.push(bulletLeft, bulletRight);
game.addChild(bulletLeft, bulletRight);
}
self.fireCooldown = self.fireRate;
}
};
self.hit = function () {
if (self.invulnerable) {
return;
}
LK.getSound('playerHit').play();
self.lives--;
LK.effects.flashObject(self, 0xff0000, 500);
if (self.lives <= 0) {
// Game over handled by the game class
return true;
} else {
// Make player invulnerable for a short time
self.invulnerable = true;
self.invulnerableTime = 120; // 2 seconds at 60fps
return false;
}
};
self.activatePowerup = function () {
self.hasPowerup = true;
self.powerupTime = 600; // 10 seconds at 60fps
self.fireRate = 8; // Faster firing with powerup
};
return self;
});
var Powerup = Container.expand(function () {
var self = Container.call(this);
var powerupGraphic = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.active = true;
self.speed = 3;
self.update = function () {
if (!self.active) {
return;
}
self.y += self.speed;
// Gentle oscillation effect
self.x += Math.sin(LK.ticks * 0.05) * 0.5;
// Check if off screen
if (self.y > 2732 + 50) {
self.active = false;
}
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphic = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = Math.random() * 3 + 1;
self.update = function () {
self.y += self.speed;
if (self.y > 2732) {
self.y = -10;
self.x = Math.random() * 2048;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000022
});
/****
* Game Code
****/
// Game variables
var player;
var bullets = [];
var enemies = [];
var enemyBullets = [];
var powerups = [];
var stars = [];
var gameState = "playing";
var score = 0;
var level = 1;
var enemySpawnTimer = 0;
var levelTimer = 0;
var dragTarget = null;
// Game UI elements
var scoreTxt;
var livesText;
var levelText;
// Initialize game function
function initGame() {
// Reset game state
bullets = [];
enemies = [];
enemyBullets = [];
powerups = [];
score = 0;
level = 1;
gameState = "playing";
// Create player
player = new Player();
player.x = 2048 / 2;
player.y = 2732 - 200;
game.addChild(player);
// Create background stars
createStars();
// Initialize UI
initUI();
// Start game music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
}
function createStars() {
// Clear existing stars
for (var i = 0; i < stars.length; i++) {
if (stars[i].parent) {
stars[i].parent.removeChild(stars[i]);
}
}
stars = [];
// Create new stars
for (var i = 0; i < 100; i++) {
var star = new Star();
star.x = Math.random() * 2048;
star.y = Math.random() * 2732;
stars.push(star);
game.addChild(star);
}
}
function initUI() {
// Score text
scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -300; // Offset from right edge
// Lives text
livesText = new Text2('Lives: 3', {
size: 60,
fill: 0xFFFFFF
});
livesText.anchor.set(0, 0);
LK.gui.top.addChild(livesText);
livesText.x = -200; // Offset from center
// Level text
levelText = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(0, 0);
LK.gui.top.addChild(levelText);
levelText.x = 200; // Offset from center
}
function updateUI() {
scoreTxt.setText('Score: ' + score);
livesText.setText('Lives: ' + player.lives);
levelText.setText('Level: ' + level);
}
function spawnEnemy() {
var enemy = new Enemy();
// Set initial position
enemy.x = Math.random() * (2048 - 200) + 100;
enemy.y = -50;
// Set properties based on level
var pattern = "straight";
var health = 1;
var spd = 1 + level * 0.2;
// Higher levels get more complex enemies
if (level > 1) {
if (Math.random() < 0.3) {
pattern = "sine";
}
}
if (level > 3) {
if (Math.random() < 0.3) {
pattern = "zigzag";
}
if (Math.random() < 0.2) {
health = 2;
}
}
if (level > 5) {
spd += 1;
if (Math.random() < 0.3) {
health = 3;
}
}
enemy.initialize(pattern, spd, health);
enemies.push(enemy);
game.addChild(enemy);
}
function spawnPowerup(x, y) {
var powerup = new Powerup();
powerup.x = x;
powerup.y = y;
powerups.push(powerup);
game.addChild(powerup);
}
function handleCollisions() {
// Player bullets vs enemies
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (!bullet.active) {
continue;
}
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (!enemy.active) {
continue;
}
if (bullet.intersects(enemy)) {
bullet.active = false;
if (bullet.parent) {
bullet.parent.removeChild(bullet);
}
bullets.splice(i, 1);
if (enemy.hit()) {
score += 10 * level;
if (enemy.parent) {
enemy.parent.removeChild(enemy);
}
enemies.splice(j, 1);
}
break;
}
}
}
// Enemy bullets vs player
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (!bullet.active) {
continue;
}
if (player && bullet.intersects(player)) {
bullet.active = false;
if (bullet.parent) {
bullet.parent.removeChild(bullet);
}
enemyBullets.splice(i, 1);
if (player.hit()) {
// Game over
gameOver();
}
}
}
// Enemies vs player
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (!enemy.active) {
continue;
}
if (player && enemy.intersects(player)) {
enemy.active = false;
if (enemy.parent) {
enemy.parent.removeChild(enemy);
}
enemies.splice(i, 1);
if (player.hit()) {
// Game over
gameOver();
}
}
}
// Powerups vs player
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
if (!powerup.active) {
continue;
}
if (player && powerup.intersects(player)) {
powerup.active = false;
if (powerup.parent) {
powerup.parent.removeChild(powerup);
}
powerups.splice(i, 1);
// Activate powerup effect
player.activatePowerup();
LK.getSound('powerupCollect').play();
score += 50;
}
}
}
function clearInactiveObjects() {
// Clear inactive bullets
for (var i = bullets.length - 1; i >= 0; i--) {
if (!bullets[i].active) {
if (bullets[i].parent) {
bullets[i].parent.removeChild(bullets[i]);
}
bullets.splice(i, 1);
}
}
// Clear inactive enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
if (!enemyBullets[i].active) {
if (enemyBullets[i].parent) {
enemyBullets[i].parent.removeChild(enemyBullets[i]);
}
enemyBullets.splice(i, 1);
}
}
// Clear inactive enemies
for (var i = enemies.length - 1; i >= 0; i--) {
if (!enemies[i].active) {
if (enemies[i].parent) {
enemies[i].parent.removeChild(enemies[i]);
}
enemies.splice(i, 1);
}
}
// Clear inactive powerups
for (var i = powerups.length - 1; i >= 0; i--) {
if (!powerups[i].active) {
if (powerups[i].parent) {
powerups[i].parent.removeChild(powerups[i]);
}
powerups.splice(i, 1);
}
}
}
function gameOver() {
gameState = "over";
// Update high score if needed
if (score > storage.highScore) {
storage.highScore = score;
console.log("New high score: " + score);
}
// Fade out music
LK.playMusic('gameMusic', {
fade: {
start: 0.7,
end: 0,
duration: 1000
}
});
// Show game over
LK.effects.flashScreen(0xff0000, 800);
// Let the engine handle game over
LK.setScore(score);
LK.showGameOver();
}
function handleInput(x, y) {
if (player && gameState === "playing") {
player.x = x;
// Keep player in bounds
if (player.x < 50) {
player.x = 50;
}
if (player.x > 2048 - 50) {
player.x = 2048 - 50;
}
// Always shoot when moving
player.shoot();
}
}
// Event handlers
game.down = function (x, y, obj) {
dragTarget = player;
handleInput(x, y);
};
game.up = function (x, y, obj) {
dragTarget = null;
};
game.move = function (x, y, obj) {
if (dragTarget) {
handleInput(x, y);
}
};
// Main game update function
game.update = function () {
if (gameState !== "playing") {
return;
}
// Update player
if (player) {
player.update();
}
// Update all game objects
for (var i = 0; i < bullets.length; i++) {
bullets[i].update();
}
for (var i = 0; i < enemies.length; i++) {
enemies[i].update();
}
for (var i = 0; i < enemyBullets.length; i++) {
enemyBullets[i].update();
}
for (var i = 0; i < powerups.length; i++) {
powerups[i].update();
}
for (var i = 0; i < stars.length; i++) {
stars[i].update();
}
// Check for collisions
handleCollisions();
// Clean up inactive objects
clearInactiveObjects();
// Spawn enemies based on level
enemySpawnTimer--;
if (enemySpawnTimer <= 0) {
spawnEnemy();
// Spawn rate decreases (gets faster) with level
enemySpawnTimer = Math.max(20, 100 - level * 10);
}
// Level progression
levelTimer++;
if (levelTimer >= 1800) {
// 30 seconds at 60fps
level++;
levelTimer = 0;
// Spawn a powerup when leveling up
spawnPowerup(Math.random() * 2048, 100);
}
// Update UI
updateUI();
};
// Initialize the game
initGame();