/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Asteroid = Container.expand(function () {
var self = Container.call(this);
var asteroidGraphics = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5
});
var size = 0.5 + Math.random() * 1.5; // Random size between 0.5 and 2.0
asteroidGraphics.scale.set(size, size);
self.speed = 2 + Math.random() * 4; // Speed between 2 and 6
self.rotationSpeed = (Math.random() - 0.5) * 0.1; // Random rotation
self.update = function () {
self.y += self.speed;
self.rotation += self.rotationSpeed;
};
return self;
});
var Bullet = Container.expand(function (isEnemy) {
var self = Container.call(this);
self.isEnemy = isEnemy || false;
var assetId = self.isEnemy ? 'enemyBullet' : 'bullet';
var bulletGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: self.isEnemy ? 1 : 3,
scaleY: self.isEnemy ? 1 : 3
});
self.speed = self.isEnemy ? 8 : -15;
self.update = function () {
self.y += self.speed;
};
return self;
});
var EnemyShip = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'basic';
var shipGraphics = self.attachAsset('enemyShip', {
anchorX: 0.5,
anchorY: 0.5
});
// Configure enemy based on type
switch (self.type) {
case 'basic':
self.health = 1;
self.speed = 3;
self.points = 10;
self.fireRate = 0; // Doesn't shoot
break;
case 'shooter':
self.health = 2;
self.speed = 2;
self.points = 20;
self.fireRate = 120; // Frames between shots
shipGraphics.tint = 0x9b59b6; // Purple
break;
case 'elite':
self.health = 3;
self.speed = 4;
self.points = 30;
self.fireRate = 90; // Frames between shots
shipGraphics.tint = 0xf39c12; // Orange
break;
}
self.fireCounter = Math.floor(Math.random() * self.fireRate);
self.movePattern = Math.floor(Math.random() * 3); // 0: straight, 1: zigzag, 2: sine
self.patternStep = 0;
self.initialX = 0;
self.canFire = function () {
if (self.fireRate === 0) {
return false;
}
if (self.fireCounter <= 0) {
self.fireCounter = self.fireRate;
return true;
}
return false;
};
self.hit = function () {
self.health--;
if (self.health <= 0) {
return true; // Enemy destroyed
}
LK.effects.flashObject(self, 0xffffff, 200);
return false; // Enemy still alive
};
self.update = function () {
// Move downward
self.y += self.speed;
// Apply movement pattern
if (self.movePattern === 1) {
// Zigzag
if (self.patternStep < 60) {
self.x += 1;
} else if (self.patternStep < 120) {
self.x -= 1;
} else {
self.patternStep = 0;
}
self.patternStep++;
} else if (self.movePattern === 2) {
// Sine wave
if (self.initialX === 0) {
self.initialX = self.x;
}
self.x = self.initialX + Math.sin(self.patternStep * 0.05) * 100;
self.patternStep++;
}
// Update fire counter
if (self.fireCounter > 0) {
self.fireCounter--;
}
};
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.shield = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.speed = 12;
self.fireRate = 20; // Frames between shots
self.fireCounter = 0;
self.hasShield = false;
self.hasDoubleFire = false;
self.health = 3;
self.activateShield = function () {
self.hasShield = true;
self.shield.alpha = 0.4;
// Shield expires after 10 seconds
LK.setTimeout(function () {
self.hasShield = false;
tween(self.shield, {
alpha: 0
}, {
duration: 500
});
}, 10000);
};
self.hit = function () {
if (self.hasShield) {
self.hasShield = false;
tween(self.shield, {
alpha: 0
}, {
duration: 500
});
return false; // No damage taken
} else {
self.health--;
LK.getSound('playerHit').play();
LK.effects.flashObject(self, 0xff0000, 500);
return true; // Damage taken
}
};
self.activateDoubleFire = function () {
self.hasDoubleFire = true;
// Double fire expires after 8 seconds
LK.setTimeout(function () {
self.hasDoubleFire = false;
}, 8000);
};
self.canFire = function () {
if (self.fireCounter <= 0) {
self.fireCounter = self.fireRate;
return true;
}
return false;
};
self.update = function () {
if (self.fireCounter > 0) {
self.fireCounter--;
}
};
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || Math.random() < 0.5 ? 'shield' : 'doubleFire';
var powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
// Set color based on type
if (self.type === 'shield') {
powerUpGraphics.tint = 0x3498db; // Blue
} else if (self.type === 'doubleFire') {
powerUpGraphics.tint = 0xf1c40f; // Yellow
}
self.speed = 3;
self.pulseDirection = 1;
self.pulseStep = 0;
self.update = function () {
self.y += self.speed;
// Pulse animation
self.pulseStep += 0.05 * self.pulseDirection;
if (self.pulseStep >= 1) {
self.pulseDirection = -1;
} else if (self.pulseStep <= 0) {
self.pulseDirection = 1;
}
powerUpGraphics.alpha = 0.7 + self.pulseStep * 0.3;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game state
var gameActive = true;
var score = 0;
var wave = 1;
var enemiesDefeated = 0;
var enemiesRequired = 10; // Enemies to defeat to advance to next wave
// Game elements
var player;
var bullets = [];
var enemyBullets = [];
var enemies = [];
var asteroids = [];
var powerUps = [];
// Background stars
var stars = [];
var starCount = 50;
// Game dimensions
var gameWidth = 2048;
var gameHeight = 2732;
var playerBoundaryLeft = 50;
var playerBoundaryRight = gameWidth - 50;
var playerBoundaryTop = 100;
var playerBoundaryBottom = gameHeight - 200;
// UI elements
var scoreTxt;
var waveTxt;
var healthTxt;
// Spawn timers
var enemySpawnTimer;
var asteroidSpawnTimer;
var powerUpSpawnTimer;
// Initialize player
function initPlayer() {
player = new PlayerShip();
player.x = gameWidth / 2;
player.y = gameHeight - 300;
game.addChild(player);
}
// Initialize UI
function initUI() {
// Wave text
waveTxt = new Text2('Wave: 1', {
size: 60,
fill: 0xFFFFFF
});
waveTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(waveTxt);
// Score text
scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.y = 70; // Position below the wave text
LK.gui.top.addChild(scoreTxt);
// Health text
healthTxt = new Text2('❤️❤️❤️', {
size: 60,
fill: 0xFFFFFF
});
healthTxt.anchor.set(0.5, 0);
healthTxt.y = 140; // Position below the score text
LK.gui.top.addChild(healthTxt);
}
// Initialize stars background
function initStars() {
for (var i = 0; i < starCount; i++) {
var star = LK.getAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1 + Math.random() * 0.1,
scaleY: 0.1 + Math.random() * 0.1,
alpha: 0.3 + Math.random() * 0.5
});
star.x = Math.random() * gameWidth;
star.y = Math.random() * gameHeight;
star.speed = 0.5 + Math.random() * 1.5;
game.addChild(star);
stars.push(star);
}
}
// Spawn timers
function initSpawnTimers() {
// Enemy spawn timer (adjusted by wave)
enemySpawnTimer = LK.setInterval(function () {
spawnEnemy();
}, 2000 - (wave * 100 > 1500 ? 1500 : wave * 100));
// Asteroid spawn timer
asteroidSpawnTimer = LK.setInterval(function () {
spawnAsteroid();
}, 3000);
// Power-up spawn timer
powerUpSpawnTimer = LK.setInterval(function () {
if (Math.random() < 0.3) {
// 30% chance to spawn power-up
spawnPowerUp();
}
}, 10000);
}
// Spawn an enemy
function spawnEnemy() {
if (!gameActive) {
return;
}
var enemyType = 'basic';
var rand = Math.random();
// Adjust enemy type probability based on wave
if (wave >= 3) {
if (rand < 0.3) {
enemyType = 'shooter';
} else if (wave >= 5 && rand < 0.5) {
enemyType = 'elite';
}
}
var enemy = new EnemyShip(enemyType);
enemy.x = 100 + Math.random() * (gameWidth - 200);
enemy.y = -100;
game.addChild(enemy);
enemies.push(enemy);
}
// Spawn an asteroid
function spawnAsteroid() {
if (!gameActive) {
return;
}
var asteroid = new Asteroid();
asteroid.x = Math.random() * gameWidth;
asteroid.y = -100;
game.addChild(asteroid);
asteroids.push(asteroid);
}
// Spawn a power-up
function spawnPowerUp() {
if (!gameActive) {
return;
}
var powerUp = new PowerUp();
powerUp.x = 100 + Math.random() * (gameWidth - 200);
powerUp.y = -100;
game.addChild(powerUp);
powerUps.push(powerUp);
}
// Fire player bullets
function firePlayerBullet() {
if (!player.canFire() || !gameActive) {
return;
}
LK.getSound('playerShoot').play();
if (player.hasDoubleFire) {
// Double fire - two bullets side by side
var bullet1 = new Bullet();
bullet1.x = player.x - 20;
bullet1.y = player.y - 30;
game.addChild(bullet1);
bullets.push(bullet1);
var bullet2 = new Bullet();
bullet2.x = player.x + 20;
bullet2.y = player.y - 30;
game.addChild(bullet2);
bullets.push(bullet2);
} else {
// Normal fire - single bullet
var bullet = new Bullet();
bullet.x = player.x;
bullet.y = player.y - 30;
game.addChild(bullet);
bullets.push(bullet);
}
}
// Fire enemy bullet
function fireEnemyBullet(enemy) {
if (!gameActive) {
return;
}
var bullet = new Bullet(true);
bullet.x = enemy.x;
bullet.y = enemy.y + 40;
game.addChild(bullet);
enemyBullets.push(bullet);
LK.getSound('enemyShoot').play();
}
// Handle collision between two game objects
function checkCollision(obj1, obj2) {
return obj1.intersects(obj2);
}
// Handle player movement
function movePlayer(x, y) {
if (!gameActive || !player) {
return;
}
// Keep player within boundaries
if (x < playerBoundaryLeft) {
x = playerBoundaryLeft;
}
if (x > playerBoundaryRight) {
x = playerBoundaryRight;
}
// Only change x position, keep y position fixed
player.x = x;
// Do not change y position anymore
}
// Update UI
function updateUI() {
scoreTxt.setText('Score: ' + score);
waveTxt.setText('Wave: ' + wave);
// Display health as heart emojis
var hearts = '';
for (var i = 0; i < player.health; i++) {
hearts += '❤️';
}
healthTxt.setText(hearts);
}
// Check if wave is complete
function checkWaveProgress() {
if (enemiesDefeated >= enemiesRequired) {
wave++;
enemiesDefeated = 0;
enemiesRequired = Math.min(10 + wave * 5, 50); // Increase required enemies, max 50
waveTxt.setText('Wave: ' + wave);
// Reset spawn timers with new rates
LK.clearInterval(enemySpawnTimer);
enemySpawnTimer = LK.setInterval(function () {
spawnEnemy();
}, Math.max(2000 - wave * 100, 500)); // Minimum 500ms
}
}
// Game over check
function checkGameOver() {
if (player.health <= 0) {
gameActive = false;
// Check for high score
if (score > storage.highScore) {
storage.highScore = score;
}
// Show game over screen
LK.setScore(score);
LK.showGameOver();
}
}
// Initialize game
function initGame() {
// Set background color
game.setBackgroundColor(0x0a0a2a); // Dark blue space color
// Reset game state
gameActive = true;
score = 0;
wave = 1;
enemiesDefeated = 0;
enemiesRequired = 10;
LK.setScore(0);
// Initialize game elements
initPlayer();
initUI();
initStars();
initSpawnTimers();
// Play background music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
}
// Start the game
initGame();
// Game touch controls
var isDragging = false;
game.down = function (x, y) {
isDragging = true;
movePlayer(x, y);
// Fire a bullet when player touches the screen
firePlayerBullet();
};
game.up = function () {
isDragging = false;
};
game.move = function (x, y) {
if (isDragging) {
movePlayer(x, y);
}
};
// Game update loop
game.update = function () {
if (!gameActive) {
return;
}
// Update player
if (player) {
player.update();
}
// Update stars
for (var i = 0; i < stars.length; i++) {
stars[i].y += stars[i].speed;
// Reset star when it goes off-screen
if (stars[i].y > gameHeight) {
stars[i].y = -10;
stars[i].x = Math.random() * gameWidth;
}
}
// Update player bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
bullet.update();
// Remove bullets that go off-screen
if (bullet.y < -50) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check bullet collisions with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (checkCollision(bullet, enemy)) {
// Enemy hit
if (enemy.hit()) {
// Enemy destroyed
score += enemy.points;
LK.setScore(score);
enemiesDefeated++;
LK.getSound('explosion').play();
LK.effects.flashObject(enemy, 0xffffff, 100);
enemy.destroy();
enemies.splice(j, 1);
}
// Remove bullet
bullet.destroy();
bullets.splice(i, 1);
break;
}
}
// Check bullet collisions with asteroids
if (bullets[i]) {
// Make sure bullet wasn't removed in enemy collision check
for (var j = asteroids.length - 1; j >= 0; j--) {
var asteroid = asteroids[j];
if (checkCollision(bullet, asteroid)) {
// Asteroid destroyed
score += 5;
LK.setScore(score);
LK.getSound('explosion').play();
LK.effects.flashObject(asteroid, 0xffffff, 100);
asteroid.destroy();
asteroids.splice(j, 1);
// Remove bullet
bullet.destroy();
bullets.splice(i, 1);
break;
}
}
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
bullet.update();
// Remove bullets that go off-screen
if (bullet.y > gameHeight + 50) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check bullet collisions with player
if (player && checkCollision(bullet, player)) {
if (player.hit()) {
// Player damaged, check game over
checkGameOver();
}
// Remove bullet
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Reduce health if enemies reach the bottom
if (enemy.y > gameHeight - 50) {
player.health--;
updateUI();
checkGameOver();
LK.getSound('playerHit').play();
LK.effects.flashObject(player, 0xff0000, 500);
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Remove enemies that go off-screen
if (enemy.y > gameHeight + 100) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Fire enemy bullets
if (enemy.canFire()) {
fireEnemyBullet(enemy);
}
// Check collisions with player
if (player && checkCollision(enemy, player)) {
if (player.hit()) {
// Player damaged, check game over
checkGameOver();
}
// Remove enemy
enemy.destroy();
enemies.splice(i, 1);
// Add to score and enemy count
score += enemy.points;
LK.setScore(score);
enemiesDefeated++;
LK.getSound('explosion').play();
continue;
}
}
// Update asteroids
for (var i = asteroids.length - 1; i >= 0; i--) {
var asteroid = asteroids[i];
asteroid.update();
// Reduce health if asteroids reach the bottom
if (asteroid.y > gameHeight - 50) {
player.health--;
updateUI();
checkGameOver();
LK.getSound('playerHit').play();
LK.effects.flashObject(player, 0xff0000, 500);
asteroid.destroy();
asteroids.splice(i, 1);
continue;
}
// Remove asteroids that go off-screen
if (asteroid.y > gameHeight + 100) {
asteroid.destroy();
asteroids.splice(i, 1);
continue;
}
// Check collisions with player
if (player && checkCollision(asteroid, player)) {
if (player.hit()) {
// Player damaged, check game over
checkGameOver();
}
// Remove asteroid
asteroid.destroy();
asteroids.splice(i, 1);
continue;
}
}
// Update power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
powerUp.update();
// Remove power-ups that go off-screen
if (powerUp.y > gameHeight + 100) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
// Check collisions with player
if (player && checkCollision(powerUp, player)) {
// Apply power-up effect
if (powerUp.type === 'shield') {
player.activateShield();
} else if (powerUp.type === 'doubleFire') {
player.activateDoubleFire();
}
LK.getSound('powerUpCollect').play();
// Remove power-up
powerUp.destroy();
powerUps.splice(i, 1);
}
}
// Auto-fire if player is dragging (every 0.3 seconds)
if (isDragging && LK.ticks % 18 === 0) {
firePlayerBullet();
}
// Update UI
updateUI();
// Check wave progress
checkWaveProgress();
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Asteroid = Container.expand(function () {
var self = Container.call(this);
var asteroidGraphics = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5
});
var size = 0.5 + Math.random() * 1.5; // Random size between 0.5 and 2.0
asteroidGraphics.scale.set(size, size);
self.speed = 2 + Math.random() * 4; // Speed between 2 and 6
self.rotationSpeed = (Math.random() - 0.5) * 0.1; // Random rotation
self.update = function () {
self.y += self.speed;
self.rotation += self.rotationSpeed;
};
return self;
});
var Bullet = Container.expand(function (isEnemy) {
var self = Container.call(this);
self.isEnemy = isEnemy || false;
var assetId = self.isEnemy ? 'enemyBullet' : 'bullet';
var bulletGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: self.isEnemy ? 1 : 3,
scaleY: self.isEnemy ? 1 : 3
});
self.speed = self.isEnemy ? 8 : -15;
self.update = function () {
self.y += self.speed;
};
return self;
});
var EnemyShip = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'basic';
var shipGraphics = self.attachAsset('enemyShip', {
anchorX: 0.5,
anchorY: 0.5
});
// Configure enemy based on type
switch (self.type) {
case 'basic':
self.health = 1;
self.speed = 3;
self.points = 10;
self.fireRate = 0; // Doesn't shoot
break;
case 'shooter':
self.health = 2;
self.speed = 2;
self.points = 20;
self.fireRate = 120; // Frames between shots
shipGraphics.tint = 0x9b59b6; // Purple
break;
case 'elite':
self.health = 3;
self.speed = 4;
self.points = 30;
self.fireRate = 90; // Frames between shots
shipGraphics.tint = 0xf39c12; // Orange
break;
}
self.fireCounter = Math.floor(Math.random() * self.fireRate);
self.movePattern = Math.floor(Math.random() * 3); // 0: straight, 1: zigzag, 2: sine
self.patternStep = 0;
self.initialX = 0;
self.canFire = function () {
if (self.fireRate === 0) {
return false;
}
if (self.fireCounter <= 0) {
self.fireCounter = self.fireRate;
return true;
}
return false;
};
self.hit = function () {
self.health--;
if (self.health <= 0) {
return true; // Enemy destroyed
}
LK.effects.flashObject(self, 0xffffff, 200);
return false; // Enemy still alive
};
self.update = function () {
// Move downward
self.y += self.speed;
// Apply movement pattern
if (self.movePattern === 1) {
// Zigzag
if (self.patternStep < 60) {
self.x += 1;
} else if (self.patternStep < 120) {
self.x -= 1;
} else {
self.patternStep = 0;
}
self.patternStep++;
} else if (self.movePattern === 2) {
// Sine wave
if (self.initialX === 0) {
self.initialX = self.x;
}
self.x = self.initialX + Math.sin(self.patternStep * 0.05) * 100;
self.patternStep++;
}
// Update fire counter
if (self.fireCounter > 0) {
self.fireCounter--;
}
};
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.shield = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.speed = 12;
self.fireRate = 20; // Frames between shots
self.fireCounter = 0;
self.hasShield = false;
self.hasDoubleFire = false;
self.health = 3;
self.activateShield = function () {
self.hasShield = true;
self.shield.alpha = 0.4;
// Shield expires after 10 seconds
LK.setTimeout(function () {
self.hasShield = false;
tween(self.shield, {
alpha: 0
}, {
duration: 500
});
}, 10000);
};
self.hit = function () {
if (self.hasShield) {
self.hasShield = false;
tween(self.shield, {
alpha: 0
}, {
duration: 500
});
return false; // No damage taken
} else {
self.health--;
LK.getSound('playerHit').play();
LK.effects.flashObject(self, 0xff0000, 500);
return true; // Damage taken
}
};
self.activateDoubleFire = function () {
self.hasDoubleFire = true;
// Double fire expires after 8 seconds
LK.setTimeout(function () {
self.hasDoubleFire = false;
}, 8000);
};
self.canFire = function () {
if (self.fireCounter <= 0) {
self.fireCounter = self.fireRate;
return true;
}
return false;
};
self.update = function () {
if (self.fireCounter > 0) {
self.fireCounter--;
}
};
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || Math.random() < 0.5 ? 'shield' : 'doubleFire';
var powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
// Set color based on type
if (self.type === 'shield') {
powerUpGraphics.tint = 0x3498db; // Blue
} else if (self.type === 'doubleFire') {
powerUpGraphics.tint = 0xf1c40f; // Yellow
}
self.speed = 3;
self.pulseDirection = 1;
self.pulseStep = 0;
self.update = function () {
self.y += self.speed;
// Pulse animation
self.pulseStep += 0.05 * self.pulseDirection;
if (self.pulseStep >= 1) {
self.pulseDirection = -1;
} else if (self.pulseStep <= 0) {
self.pulseDirection = 1;
}
powerUpGraphics.alpha = 0.7 + self.pulseStep * 0.3;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game state
var gameActive = true;
var score = 0;
var wave = 1;
var enemiesDefeated = 0;
var enemiesRequired = 10; // Enemies to defeat to advance to next wave
// Game elements
var player;
var bullets = [];
var enemyBullets = [];
var enemies = [];
var asteroids = [];
var powerUps = [];
// Background stars
var stars = [];
var starCount = 50;
// Game dimensions
var gameWidth = 2048;
var gameHeight = 2732;
var playerBoundaryLeft = 50;
var playerBoundaryRight = gameWidth - 50;
var playerBoundaryTop = 100;
var playerBoundaryBottom = gameHeight - 200;
// UI elements
var scoreTxt;
var waveTxt;
var healthTxt;
// Spawn timers
var enemySpawnTimer;
var asteroidSpawnTimer;
var powerUpSpawnTimer;
// Initialize player
function initPlayer() {
player = new PlayerShip();
player.x = gameWidth / 2;
player.y = gameHeight - 300;
game.addChild(player);
}
// Initialize UI
function initUI() {
// Wave text
waveTxt = new Text2('Wave: 1', {
size: 60,
fill: 0xFFFFFF
});
waveTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(waveTxt);
// Score text
scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.y = 70; // Position below the wave text
LK.gui.top.addChild(scoreTxt);
// Health text
healthTxt = new Text2('❤️❤️❤️', {
size: 60,
fill: 0xFFFFFF
});
healthTxt.anchor.set(0.5, 0);
healthTxt.y = 140; // Position below the score text
LK.gui.top.addChild(healthTxt);
}
// Initialize stars background
function initStars() {
for (var i = 0; i < starCount; i++) {
var star = LK.getAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1 + Math.random() * 0.1,
scaleY: 0.1 + Math.random() * 0.1,
alpha: 0.3 + Math.random() * 0.5
});
star.x = Math.random() * gameWidth;
star.y = Math.random() * gameHeight;
star.speed = 0.5 + Math.random() * 1.5;
game.addChild(star);
stars.push(star);
}
}
// Spawn timers
function initSpawnTimers() {
// Enemy spawn timer (adjusted by wave)
enemySpawnTimer = LK.setInterval(function () {
spawnEnemy();
}, 2000 - (wave * 100 > 1500 ? 1500 : wave * 100));
// Asteroid spawn timer
asteroidSpawnTimer = LK.setInterval(function () {
spawnAsteroid();
}, 3000);
// Power-up spawn timer
powerUpSpawnTimer = LK.setInterval(function () {
if (Math.random() < 0.3) {
// 30% chance to spawn power-up
spawnPowerUp();
}
}, 10000);
}
// Spawn an enemy
function spawnEnemy() {
if (!gameActive) {
return;
}
var enemyType = 'basic';
var rand = Math.random();
// Adjust enemy type probability based on wave
if (wave >= 3) {
if (rand < 0.3) {
enemyType = 'shooter';
} else if (wave >= 5 && rand < 0.5) {
enemyType = 'elite';
}
}
var enemy = new EnemyShip(enemyType);
enemy.x = 100 + Math.random() * (gameWidth - 200);
enemy.y = -100;
game.addChild(enemy);
enemies.push(enemy);
}
// Spawn an asteroid
function spawnAsteroid() {
if (!gameActive) {
return;
}
var asteroid = new Asteroid();
asteroid.x = Math.random() * gameWidth;
asteroid.y = -100;
game.addChild(asteroid);
asteroids.push(asteroid);
}
// Spawn a power-up
function spawnPowerUp() {
if (!gameActive) {
return;
}
var powerUp = new PowerUp();
powerUp.x = 100 + Math.random() * (gameWidth - 200);
powerUp.y = -100;
game.addChild(powerUp);
powerUps.push(powerUp);
}
// Fire player bullets
function firePlayerBullet() {
if (!player.canFire() || !gameActive) {
return;
}
LK.getSound('playerShoot').play();
if (player.hasDoubleFire) {
// Double fire - two bullets side by side
var bullet1 = new Bullet();
bullet1.x = player.x - 20;
bullet1.y = player.y - 30;
game.addChild(bullet1);
bullets.push(bullet1);
var bullet2 = new Bullet();
bullet2.x = player.x + 20;
bullet2.y = player.y - 30;
game.addChild(bullet2);
bullets.push(bullet2);
} else {
// Normal fire - single bullet
var bullet = new Bullet();
bullet.x = player.x;
bullet.y = player.y - 30;
game.addChild(bullet);
bullets.push(bullet);
}
}
// Fire enemy bullet
function fireEnemyBullet(enemy) {
if (!gameActive) {
return;
}
var bullet = new Bullet(true);
bullet.x = enemy.x;
bullet.y = enemy.y + 40;
game.addChild(bullet);
enemyBullets.push(bullet);
LK.getSound('enemyShoot').play();
}
// Handle collision between two game objects
function checkCollision(obj1, obj2) {
return obj1.intersects(obj2);
}
// Handle player movement
function movePlayer(x, y) {
if (!gameActive || !player) {
return;
}
// Keep player within boundaries
if (x < playerBoundaryLeft) {
x = playerBoundaryLeft;
}
if (x > playerBoundaryRight) {
x = playerBoundaryRight;
}
// Only change x position, keep y position fixed
player.x = x;
// Do not change y position anymore
}
// Update UI
function updateUI() {
scoreTxt.setText('Score: ' + score);
waveTxt.setText('Wave: ' + wave);
// Display health as heart emojis
var hearts = '';
for (var i = 0; i < player.health; i++) {
hearts += '❤️';
}
healthTxt.setText(hearts);
}
// Check if wave is complete
function checkWaveProgress() {
if (enemiesDefeated >= enemiesRequired) {
wave++;
enemiesDefeated = 0;
enemiesRequired = Math.min(10 + wave * 5, 50); // Increase required enemies, max 50
waveTxt.setText('Wave: ' + wave);
// Reset spawn timers with new rates
LK.clearInterval(enemySpawnTimer);
enemySpawnTimer = LK.setInterval(function () {
spawnEnemy();
}, Math.max(2000 - wave * 100, 500)); // Minimum 500ms
}
}
// Game over check
function checkGameOver() {
if (player.health <= 0) {
gameActive = false;
// Check for high score
if (score > storage.highScore) {
storage.highScore = score;
}
// Show game over screen
LK.setScore(score);
LK.showGameOver();
}
}
// Initialize game
function initGame() {
// Set background color
game.setBackgroundColor(0x0a0a2a); // Dark blue space color
// Reset game state
gameActive = true;
score = 0;
wave = 1;
enemiesDefeated = 0;
enemiesRequired = 10;
LK.setScore(0);
// Initialize game elements
initPlayer();
initUI();
initStars();
initSpawnTimers();
// Play background music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
}
// Start the game
initGame();
// Game touch controls
var isDragging = false;
game.down = function (x, y) {
isDragging = true;
movePlayer(x, y);
// Fire a bullet when player touches the screen
firePlayerBullet();
};
game.up = function () {
isDragging = false;
};
game.move = function (x, y) {
if (isDragging) {
movePlayer(x, y);
}
};
// Game update loop
game.update = function () {
if (!gameActive) {
return;
}
// Update player
if (player) {
player.update();
}
// Update stars
for (var i = 0; i < stars.length; i++) {
stars[i].y += stars[i].speed;
// Reset star when it goes off-screen
if (stars[i].y > gameHeight) {
stars[i].y = -10;
stars[i].x = Math.random() * gameWidth;
}
}
// Update player bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
bullet.update();
// Remove bullets that go off-screen
if (bullet.y < -50) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check bullet collisions with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (checkCollision(bullet, enemy)) {
// Enemy hit
if (enemy.hit()) {
// Enemy destroyed
score += enemy.points;
LK.setScore(score);
enemiesDefeated++;
LK.getSound('explosion').play();
LK.effects.flashObject(enemy, 0xffffff, 100);
enemy.destroy();
enemies.splice(j, 1);
}
// Remove bullet
bullet.destroy();
bullets.splice(i, 1);
break;
}
}
// Check bullet collisions with asteroids
if (bullets[i]) {
// Make sure bullet wasn't removed in enemy collision check
for (var j = asteroids.length - 1; j >= 0; j--) {
var asteroid = asteroids[j];
if (checkCollision(bullet, asteroid)) {
// Asteroid destroyed
score += 5;
LK.setScore(score);
LK.getSound('explosion').play();
LK.effects.flashObject(asteroid, 0xffffff, 100);
asteroid.destroy();
asteroids.splice(j, 1);
// Remove bullet
bullet.destroy();
bullets.splice(i, 1);
break;
}
}
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
bullet.update();
// Remove bullets that go off-screen
if (bullet.y > gameHeight + 50) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check bullet collisions with player
if (player && checkCollision(bullet, player)) {
if (player.hit()) {
// Player damaged, check game over
checkGameOver();
}
// Remove bullet
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Reduce health if enemies reach the bottom
if (enemy.y > gameHeight - 50) {
player.health--;
updateUI();
checkGameOver();
LK.getSound('playerHit').play();
LK.effects.flashObject(player, 0xff0000, 500);
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Remove enemies that go off-screen
if (enemy.y > gameHeight + 100) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Fire enemy bullets
if (enemy.canFire()) {
fireEnemyBullet(enemy);
}
// Check collisions with player
if (player && checkCollision(enemy, player)) {
if (player.hit()) {
// Player damaged, check game over
checkGameOver();
}
// Remove enemy
enemy.destroy();
enemies.splice(i, 1);
// Add to score and enemy count
score += enemy.points;
LK.setScore(score);
enemiesDefeated++;
LK.getSound('explosion').play();
continue;
}
}
// Update asteroids
for (var i = asteroids.length - 1; i >= 0; i--) {
var asteroid = asteroids[i];
asteroid.update();
// Reduce health if asteroids reach the bottom
if (asteroid.y > gameHeight - 50) {
player.health--;
updateUI();
checkGameOver();
LK.getSound('playerHit').play();
LK.effects.flashObject(player, 0xff0000, 500);
asteroid.destroy();
asteroids.splice(i, 1);
continue;
}
// Remove asteroids that go off-screen
if (asteroid.y > gameHeight + 100) {
asteroid.destroy();
asteroids.splice(i, 1);
continue;
}
// Check collisions with player
if (player && checkCollision(asteroid, player)) {
if (player.hit()) {
// Player damaged, check game over
checkGameOver();
}
// Remove asteroid
asteroid.destroy();
asteroids.splice(i, 1);
continue;
}
}
// Update power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
powerUp.update();
// Remove power-ups that go off-screen
if (powerUp.y > gameHeight + 100) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
// Check collisions with player
if (player && checkCollision(powerUp, player)) {
// Apply power-up effect
if (powerUp.type === 'shield') {
player.activateShield();
} else if (powerUp.type === 'doubleFire') {
player.activateDoubleFire();
}
LK.getSound('powerUpCollect').play();
// Remove power-up
powerUp.destroy();
powerUps.splice(i, 1);
}
}
// Auto-fire if player is dragging (every 0.3 seconds)
if (isDragging && LK.ticks % 18 === 0) {
firePlayerBullet();
}
// Update UI
updateUI();
// Check wave progress
checkWaveProgress();
};