/****
* 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 asteroid = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 2;
self.speed = {
y: 2 + Math.random() * 2,
x: (Math.random() - 0.5) * 2
};
self.rotation = Math.random() * 0.1 - 0.05;
self.scoreValue = 15;
// Random size variation
var scale = 0.7 + Math.random() * 0.8;
asteroid.scale.set(scale, scale);
self.damage = function (amount) {
self.health -= amount || 1;
tween(asteroid, {
tint: 0xffffff
}, {
duration: 200,
onFinish: function onFinish() {
asteroid.tint = 0x95a5a6;
}
});
return self.health <= 0;
};
self.update = function () {
self.y += self.speed.y;
self.x += self.speed.x;
asteroid.rotation += self.rotation;
};
return self;
});
var Boss = Container.expand(function (level) {
var self = Container.call(this);
var ship = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.level = level || 1;
self.maxHealth = 20 * self.level;
self.health = self.maxHealth;
self.scoreValue = 200 * self.level;
self.phase = 0;
self.phaseTime = 0;
self.patterns = ['side-to-side', 'charge', 'retreat'];
self.currentPattern = 0;
self.targetX = 0;
self.targetY = 0;
// Adjust boss based on level
if (self.level > 1) {
ship.tint = 0xcc00cc;
}
// Health bar
self.healthBar = new Container();
self.addChild(self.healthBar);
var healthBarBg = self.healthBar.attachAsset('playerLaser', {
anchorX: 0,
anchorY: 0.5,
scaleX: 2,
scaleY: 0.5
});
healthBarBg.tint = 0x333333;
healthBarBg.width = 200;
self.healthBarFill = self.healthBar.attachAsset('playerLaser', {
anchorX: 0,
anchorY: 0.5,
scaleX: 2,
scaleY: 0.4
});
self.healthBarFill.tint = 0xff3333;
self.healthBarFill.width = 200;
self.healthBar.y = -120;
self.damage = function (amount) {
self.health -= amount || 1;
// Update health bar
var healthPercent = self.health / self.maxHealth;
self.healthBarFill.width = 200 * healthPercent;
tween(ship, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
ship.tint = self.level > 1 ? 0xcc00cc : 0x9b59b6;
}
});
// Change patterns more quickly when damaged
if (self.health < self.maxHealth * 0.5 && self.phaseTime > 150) {
self.changePattern();
}
return self.health <= 0;
};
self.changePattern = function () {
self.currentPattern = (self.currentPattern + 1) % self.patterns.length;
self.phaseTime = 0;
self.phase = 0;
};
self.update = function () {
self.phaseTime++;
// Change pattern every so often
if (self.phaseTime > 300) {
self.changePattern();
}
var pattern = self.patterns[self.currentPattern];
switch (pattern) {
case 'side-to-side':
// Move side to side
self.targetX = 1024 + Math.sin(self.phaseTime * 0.02) * 800;
if (self.phaseTime < 60) {
self.targetY = Math.min(self.y + 2, 400);
} else {
self.targetY = 400;
}
break;
case 'charge':
// Charge down then back up
if (self.phase === 0) {
self.targetY = self.y + 5;
if (self.y > 800) {
self.phase = 1;
}
} else {
self.targetY = Math.max(self.y - 3, 300);
if (self.y <= 300) {
self.phase = 0;
}
}
self.targetX = 1024 + Math.sin(self.phaseTime * 0.03) * 500;
break;
case 'retreat':
// Stay near top and move quickly
self.targetY = 300;
self.targetX = 1024 + Math.sin(self.phaseTime * 0.05) * 900;
break;
}
// Move toward target position
self.x += (self.targetX - self.x) * 0.05;
self.y += (self.targetY - self.y) * 0.05;
};
return self;
});
var Enemy = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'basic';
var assetType = self.type === 'fast' ? 'enemy' : 'enemy';
var ship = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
// Different enemy types
if (self.type === 'basic') {
self.health = 1;
self.speed = 2;
self.scoreValue = 10;
self.shootChance = 0.01;
} else if (self.type === 'fast') {
self.health = 1;
self.speed = 3.5;
self.scoreValue = 15;
ship.scaleX = 0.8;
ship.scaleY = 0.8;
self.shootChance = 0.005;
ship.tint = 0xff9966;
} else if (self.type === 'tank') {
self.health = 3;
self.speed = 1.5;
self.scoreValue = 25;
ship.scaleX = 1.2;
ship.scaleY = 1.2;
self.shootChance = 0.015;
ship.tint = 0x66ff66;
}
self.movement = {
pattern: 'straight',
phase: Math.random() * Math.PI * 2,
amplitude: 60 + Math.random() * 60
};
self.initialX = 0;
self.damage = function (amount) {
self.health -= amount || 1;
tween(ship, {
tint: 0xffffff
}, {
duration: 200,
onFinish: function onFinish() {
ship.tint = self.type === 'fast' ? 0xff9966 : self.type === 'tank' ? 0x66ff66 : 0xe74c3c;
}
});
return self.health <= 0;
};
self.update = function () {
// Basic movement
self.y += self.speed;
// Pattern movement
if (self.movement.pattern === 'sine') {
self.x = self.initialX + Math.sin(LK.ticks * 0.05 + self.movement.phase) * self.movement.amplitude;
} else if (self.movement.pattern === 'zigzag') {
var timeScale = 0.02;
var t = LK.ticks * timeScale + self.movement.phase;
var triangleWave = Math.abs(t % 2 - 1) * 2 - 1;
self.x = self.initialX + triangleWave * self.movement.amplitude;
}
};
return self;
});
var EnemyLaser = Container.expand(function () {
var self = Container.call(this);
var laser = self.attachAsset('enemyLaser', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosion = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9
});
// Set up fade and scale
tween(explosion, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 500,
onFinish: function onFinish() {
self.destroy();
}
});
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var ship = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.shield = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.lives = 3;
self.shieldActive = false;
self.fireRate = 20;
self.lastShot = 0;
self.canShoot = true;
self.power = 1;
self.invulnerable = false;
self.activateShield = function (duration) {
self.shieldActive = true;
self.shield.alpha = 0.4;
LK.setTimeout(function () {
self.shieldActive = false;
tween(self.shield, {
alpha: 0
}, {
duration: 500
});
}, duration);
};
self.damage = function () {
if (self.invulnerable || self.shieldActive) {
return;
}
self.lives--;
LK.getSound('playerDamage').play();
// Make player temporarily invulnerable
self.invulnerable = true;
// Flash the player to show invulnerability
var flashCount = 0;
var flashInterval = LK.setInterval(function () {
ship.alpha = ship.alpha === 0.3 ? 1 : 0.3;
flashCount++;
if (flashCount >= 10) {
LK.clearInterval(flashInterval);
ship.alpha = 1;
self.invulnerable = false;
}
}, 150);
};
self.upgrade = function (type) {
LK.getSound('powerup').play();
if (type === 'shield') {
self.activateShield(8000);
} else if (type === 'power') {
self.power = Math.min(self.power + 1, 3);
// Reset power after some time
LK.setTimeout(function () {
self.power = Math.max(1, self.power - 1);
}, 10000);
} else if (type === 'life') {
self.lives = Math.min(self.lives + 1, 5);
} else if (type === 'speed') {
var oldFireRate = self.fireRate;
self.fireRate = Math.max(self.fireRate - 5, 10);
// Reset fire rate after some time
LK.setTimeout(function () {
self.fireRate = oldFireRate;
}, 10000);
}
};
return self;
});
var PlayerLaser = Container.expand(function () {
var self = Container.call(this);
var laser = self.attachAsset('playerLaser', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -15;
self.power = 1;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Powerup = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || ['shield', 'power', 'life', 'speed'][Math.floor(Math.random() * 4)];
var powerup = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
// Set color based on type
if (self.type === 'shield') {
powerup.tint = 0x3498db; // Blue
} else if (self.type === 'power') {
powerup.tint = 0xe74c3c; // Red
} else if (self.type === 'life') {
powerup.tint = 0x2ecc71; // Green
} else if (self.type === 'speed') {
powerup.tint = 0xf1c40f; // Yellow
}
self.speed = 3;
self.update = function () {
self.y += self.speed;
powerup.rotation += 0.05;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000022
});
/****
* Game Code
****/
// Game variables
var player;
var playerLasers = [];
var enemies = [];
var enemyLasers = [];
var asteroids = [];
var powerups = [];
var explosions = [];
var boss = null;
var gameState = 'playing';
var score = 0;
var waveNumber = 1;
var enemiesThisWave = 0;
var enemiesDefeated = 0;
var waveDelay = 0;
var bossWave = false;
var dragStartPosition = {
x: 0,
y: 0
};
// UI elements
var scoreTxt = new Text2('SCORE: 0', {
size: 40,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -250;
scoreTxt.y = 50;
var waveText = new Text2('WAVE: 1', {
size: 40,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
waveText.y = 50;
var livesText = new Text2('LIVES: 3', {
size: 40,
fill: 0xFFFFFF
});
livesText.anchor.set(0, 0);
LK.gui.topLeft.addChild(livesText);
livesText.x = 150; // Keep away from the top-left menu icon
livesText.y = 50;
// Create game elements
function initGame() {
// Reset game variables
playerLasers = [];
enemies = [];
enemyLasers = [];
asteroids = [];
powerups = [];
explosions = [];
boss = null;
gameState = 'playing';
score = 0;
waveNumber = 1;
enemiesThisWave = 10;
enemiesDefeated = 0;
waveDelay = 0;
bossWave = false;
// Update UI
scoreTxt.setText('SCORE: ' + score);
waveText.setText('WAVE: ' + waveNumber);
// Create player
player = new Player();
player.x = 1024;
player.y = 2200;
game.addChild(player);
livesText.setText('LIVES: ' + player.lives);
// Start with player moving up
tween(player, {
y: 2000
}, {
duration: 1000
});
// Start the music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
// Create first wave
createWave();
}
// Create a new wave of enemies
function createWave() {
waveNumber++;
waveText.setText('WAVE: ' + waveNumber);
// Every 5 waves is a boss wave
bossWave = waveNumber % 5 === 0;
if (bossWave) {
// Create a boss
var bossLevel = Math.ceil(waveNumber / 5);
LK.getSound('bossAlert').play();
boss = new Boss(bossLevel);
boss.x = 1024;
boss.y = -200;
game.addChild(boss);
tween(boss, {
y: 300
}, {
duration: 2000
});
// Show boss wave text
var bossText = new Text2('BOSS WAVE!', {
size: 80,
fill: 0xFF0000
});
bossText.anchor.set(0.5, 0.5);
bossText.x = 1024;
bossText.y = 800;
game.addChild(bossText);
tween(bossText, {
alpha: 0,
y: 700
}, {
duration: 2000,
onFinish: function onFinish() {
bossText.destroy();
}
});
return;
}
// Regular wave
enemiesThisWave = 10 + waveNumber * 2;
enemiesDefeated = 0;
// Show wave text
var newWaveText = new Text2('WAVE ' + waveNumber, {
size: 80,
fill: 0xFFFFFF
});
newWaveText.anchor.set(0.5, 0.5);
newWaveText.x = 1024;
newWaveText.y = 800;
game.addChild(newWaveText);
tween(newWaveText, {
alpha: 0,
y: 700
}, {
duration: 2000,
onFinish: function onFinish() {
newWaveText.destroy();
}
});
// Start spawning enemies after a short delay
waveDelay = 120;
}
// Create a new enemy
function spawnEnemy() {
var types = ['basic'];
// Add more enemy types as waves progress
if (waveNumber >= 2) {
types.push('fast');
}
if (waveNumber >= 3) {
types.push('tank');
}
var type = types[Math.floor(Math.random() * types.length)];
var enemy = new Enemy(type);
// Position the enemy
enemy.x = Math.random() * 1800 + 124;
enemy.y = -100;
enemy.initialX = enemy.x;
// Set random movement pattern
var patterns = ['straight'];
if (waveNumber >= 2) {
patterns.push('sine');
}
if (waveNumber >= 4) {
patterns.push('zigzag');
}
enemy.movement.pattern = patterns[Math.floor(Math.random() * patterns.length)];
// Add to game
enemies.push(enemy);
game.addChild(enemy);
}
// Create a new asteroid
function spawnAsteroid() {
var asteroid = new Asteroid();
// Position the asteroid
asteroid.x = Math.random() * 1800 + 124;
asteroid.y = -100;
// Add to game
asteroids.push(asteroid);
game.addChild(asteroid);
}
// Create a player laser
function firePlayerLaser() {
if (!player || !player.canShoot || player.lastShot + player.fireRate > LK.ticks) {
return;
}
player.lastShot = LK.ticks;
LK.getSound('playerShoot').play();
// Fire based on power level
if (player.power === 1) {
var laser = new PlayerLaser();
laser.x = player.x;
laser.y = player.y - 50;
laser.power = player.power;
playerLasers.push(laser);
game.addChild(laser);
} else if (player.power === 2) {
for (var i = -1; i <= 1; i += 2) {
var laser = new PlayerLaser();
laser.x = player.x + i * 30;
laser.y = player.y - 40;
laser.power = player.power;
playerLasers.push(laser);
game.addChild(laser);
}
} else if (player.power >= 3) {
var centerLaser = new PlayerLaser();
centerLaser.x = player.x;
centerLaser.y = player.y - 50;
centerLaser.power = player.power;
playerLasers.push(centerLaser);
game.addChild(centerLaser);
for (var i = -1; i <= 1; i += 2) {
var sideLaser = new PlayerLaser();
sideLaser.x = player.x + i * 40;
sideLaser.y = player.y - 30;
sideLaser.power = player.power - 1;
playerLasers.push(sideLaser);
game.addChild(sideLaser);
}
}
}
// Create an enemy laser
function fireEnemyLaser(enemy) {
var laser = new EnemyLaser();
laser.x = enemy.x;
laser.y = enemy.y + 40;
enemyLasers.push(laser);
game.addChild(laser);
LK.getSound('enemyShoot').play({
volume: 0.2
});
}
// Fire boss laser pattern
function fireBossLasers() {
if (!boss) {
return;
}
// Different patterns based on boss level and health
var healthPercent = boss.health / boss.maxHealth;
var pattern = 'spread';
if (boss.level >= 2 && healthPercent < 0.5) {
pattern = 'circle';
}
if (pattern === 'spread') {
for (var i = -2; i <= 2; i++) {
var laser = new EnemyLaser();
laser.x = boss.x + i * 50;
laser.y = boss.y + 80;
enemyLasers.push(laser);
game.addChild(laser);
}
} else if (pattern === 'circle') {
var numLasers = 8;
for (var i = 0; i < numLasers; i++) {
var angle = i / numLasers * Math.PI * 2;
var laser = new EnemyLaser();
laser.x = boss.x + Math.cos(angle) * 100;
laser.y = boss.y + Math.sin(angle) * 100;
enemyLasers.push(laser);
game.addChild(laser);
// Add directional motion
laser.update = function () {
var dx = this.x - boss.x;
var dy = this.y - boss.y;
var length = Math.sqrt(dx * dx + dy * dy);
this.x += dx / length * 5;
this.y += dy / length * 5;
};
}
}
LK.getSound('enemyShoot').play({
volume: 0.4
});
}
// Create explosion animation
function createExplosion(x, y, scale) {
var explosion = new Explosion();
explosion.x = x;
explosion.y = y;
if (scale) {
explosion.scale.set(scale, scale);
}
explosions.push(explosion);
game.addChild(explosion);
LK.getSound('explosion').play();
}
// Create a powerup
function spawnPowerup(x, y, type) {
var powerup = new Powerup(type);
powerup.x = x;
powerup.y = y;
powerups.push(powerup);
game.addChild(powerup);
}
// Handle player shooting and movement
function handlePlayerInput() {
// Keep player in bounds
player.x = Math.max(100, Math.min(player.x, 2048 - 100));
player.y = Math.max(100, Math.min(player.y, 2732 - 100));
// Auto-fire
if (LK.ticks % 10 === 0) {
firePlayerLaser();
}
}
// Handle collisions between game objects
function handleCollisions() {
// Player lasers vs enemies
for (var i = playerLasers.length - 1; i >= 0; i--) {
var laser = playerLasers[i];
var hitSomething = false;
// Check against enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (laser.intersects(enemy)) {
// Damage enemy
if (enemy.damage(laser.power)) {
// Enemy destroyed
createExplosion(enemy.x, enemy.y);
// Add score
score += enemy.scoreValue;
scoreTxt.setText('SCORE: ' + score);
// Count enemy as defeated
enemiesDefeated++;
// Chance to spawn powerup
if (Math.random() < 0.1) {
spawnPowerup(enemy.x, enemy.y);
}
enemy.destroy();
enemies.splice(j, 1);
}
// Remove laser
laser.destroy();
playerLasers.splice(i, 1);
hitSomething = true;
break;
}
}
// Only check other collisions if we haven't hit an enemy
if (!hitSomething) {
// Check against boss
if (boss && laser.intersects(boss)) {
// Damage boss
if (boss.damage(laser.power)) {
// Boss destroyed
createExplosion(boss.x, boss.y, 2);
// Add score
score += boss.scoreValue;
scoreTxt.setText('SCORE: ' + score);
// Spawn multiple powerups
for (var p = 0; p < 3; p++) {
var powerupType = ['shield', 'power', 'life', 'speed'][Math.floor(Math.random() * 4)];
spawnPowerup(boss.x + (Math.random() * 200 - 100), boss.y + (Math.random() * 200 - 100), powerupType);
}
boss.destroy();
boss = null;
// Move to next wave
createWave();
}
// Remove laser
laser.destroy();
playerLasers.splice(i, 1);
hitSomething = true;
}
// Check against asteroids
for (var k = asteroids.length - 1; k >= 0; k--) {
var asteroid = asteroids[k];
if (laser.intersects(asteroid)) {
// Damage asteroid
if (asteroid.damage(laser.power)) {
// Asteroid destroyed
createExplosion(asteroid.x, asteroid.y, 0.7);
// Add score
score += asteroid.scoreValue;
scoreTxt.setText('SCORE: ' + score);
asteroid.destroy();
asteroids.splice(k, 1);
}
// Remove laser
laser.destroy();
playerLasers.splice(i, 1);
hitSomething = true;
break;
}
}
}
// Remove laser if it's off screen
if (!hitSomething && laser.y < -50) {
laser.destroy();
playerLasers.splice(i, 1);
}
}
// Enemy lasers vs player
for (var i = enemyLasers.length - 1; i >= 0; i--) {
var laser = enemyLasers[i];
if (player && laser.intersects(player)) {
// Damage player
player.damage();
// Update UI
livesText.setText('LIVES: ' + player.lives);
// Check for game over
if (player.lives <= 0) {
// Game over
createExplosion(player.x, player.y, 1.5);
player.destroy();
player = null;
// Save high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
// Show game over after a delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
// Remove laser
laser.destroy();
enemyLasers.splice(i, 1);
} else if (laser.y > 2732 + 50) {
// Remove laser if it's off screen
laser.destroy();
enemyLasers.splice(i, 1);
}
}
// Player vs enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (player && player.intersects(enemy)) {
// Damage player
player.damage();
// Damage enemy
enemy.damage(1);
// Update UI
livesText.setText('LIVES: ' + player.lives);
// Check for enemy death
if (enemy.health <= 0) {
// Enemy destroyed
createExplosion(enemy.x, enemy.y);
// Add score
score += enemy.scoreValue;
scoreTxt.setText('SCORE: ' + score);
// Count enemy as defeated
enemiesDefeated++;
enemy.destroy();
enemies.splice(i, 1);
}
// Check for game over
if (player.lives <= 0) {
// Game over
createExplosion(player.x, player.y, 1.5);
player.destroy();
player = null;
// Save high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
// Show game over after a delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
// Remove enemy if it's off screen
if (enemy.y > 2732 + 100) {
enemy.destroy();
enemies.splice(i, 1);
}
}
// Player vs asteroids
for (var i = asteroids.length - 1; i >= 0; i--) {
var asteroid = asteroids[i];
if (player && player.intersects(asteroid)) {
// Damage player
player.damage();
// Damage asteroid
asteroid.damage(1);
// Update UI
livesText.setText('LIVES: ' + player.lives);
// Check for asteroid death
if (asteroid.health <= 0) {
// Asteroid destroyed
createExplosion(asteroid.x, asteroid.y, 0.7);
// Add score
score += asteroid.scoreValue;
scoreTxt.setText('SCORE: ' + score);
asteroid.destroy();
asteroids.splice(i, 1);
}
// Check for game over
if (player.lives <= 0) {
// Game over
createExplosion(player.x, player.y, 1.5);
player.destroy();
player = null;
// Save high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
// Show game over after a delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
// Remove asteroid if it's off screen
if (asteroid.y > 2732 + 100 || asteroid.x < -100 || asteroid.x > 2048 + 100) {
asteroid.destroy();
asteroids.splice(i, 1);
}
}
// Player vs powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
if (player && player.intersects(powerup)) {
// Apply powerup
player.upgrade(powerup.type);
// Update UI if life powerup
if (powerup.type === 'life') {
livesText.setText('LIVES: ' + player.lives);
}
// Remove powerup
powerup.destroy();
powerups.splice(i, 1);
} else if (powerup.y > 2732 + 50) {
// Remove powerup if it's off screen
powerup.destroy();
powerups.splice(i, 1);
}
}
// Player vs boss
if (player && boss && player.intersects(boss)) {
// Damage player
player.damage();
// Update UI
livesText.setText('LIVES: ' + player.lives);
// Check for game over
if (player.lives <= 0) {
// Game over
createExplosion(player.x, player.y, 1.5);
player.destroy();
player = null;
// Save high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
// Show game over after a delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
}
// Initialize the game
initGame();
// Game down event handler
game.down = function (x, y, obj) {
if (!player) {
return;
}
dragStartPosition.x = x;
dragStartPosition.y = y;
// Fire lasers on tap
firePlayerLaser();
};
// Game move event handler
game.move = function (x, y, obj) {
if (!player) {
return;
}
// Move player with drag
player.x = x;
player.y = y;
};
// Game update handler
game.update = function () {
if (gameState !== 'playing') {
return;
}
// Handle player input
if (player) {
handlePlayerInput();
}
// Handle wave creation
if (waveDelay > 0) {
waveDelay--;
} else if (!bossWave && enemies.length === 0 && enemiesDefeated >= enemiesThisWave) {
// All enemies for this wave defeated, create next wave
createWave();
} else if (!bossWave && enemies.length < 5 && enemiesDefeated < enemiesThisWave && LK.ticks % 30 === 0) {
// Spawn more enemies for this wave
spawnEnemy();
}
// Spawn asteroids occasionally
if (LK.ticks % 180 === 0 && Math.random() < 0.7) {
spawnAsteroid();
}
// Boss shooting
if (boss && LK.ticks % 90 === 0) {
fireBossLasers();
}
// Enemy shooting
for (var i = 0; i < enemies.length; i++) {
if (Math.random() < enemies[i].shootChance) {
fireEnemyLaser(enemies[i]);
}
}
// Collision detection
handleCollisions();
}; /****
* 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 asteroid = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 2;
self.speed = {
y: 2 + Math.random() * 2,
x: (Math.random() - 0.5) * 2
};
self.rotation = Math.random() * 0.1 - 0.05;
self.scoreValue = 15;
// Random size variation
var scale = 0.7 + Math.random() * 0.8;
asteroid.scale.set(scale, scale);
self.damage = function (amount) {
self.health -= amount || 1;
tween(asteroid, {
tint: 0xffffff
}, {
duration: 200,
onFinish: function onFinish() {
asteroid.tint = 0x95a5a6;
}
});
return self.health <= 0;
};
self.update = function () {
self.y += self.speed.y;
self.x += self.speed.x;
asteroid.rotation += self.rotation;
};
return self;
});
var Boss = Container.expand(function (level) {
var self = Container.call(this);
var ship = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.level = level || 1;
self.maxHealth = 20 * self.level;
self.health = self.maxHealth;
self.scoreValue = 200 * self.level;
self.phase = 0;
self.phaseTime = 0;
self.patterns = ['side-to-side', 'charge', 'retreat'];
self.currentPattern = 0;
self.targetX = 0;
self.targetY = 0;
// Adjust boss based on level
if (self.level > 1) {
ship.tint = 0xcc00cc;
}
// Health bar
self.healthBar = new Container();
self.addChild(self.healthBar);
var healthBarBg = self.healthBar.attachAsset('playerLaser', {
anchorX: 0,
anchorY: 0.5,
scaleX: 2,
scaleY: 0.5
});
healthBarBg.tint = 0x333333;
healthBarBg.width = 200;
self.healthBarFill = self.healthBar.attachAsset('playerLaser', {
anchorX: 0,
anchorY: 0.5,
scaleX: 2,
scaleY: 0.4
});
self.healthBarFill.tint = 0xff3333;
self.healthBarFill.width = 200;
self.healthBar.y = -120;
self.damage = function (amount) {
self.health -= amount || 1;
// Update health bar
var healthPercent = self.health / self.maxHealth;
self.healthBarFill.width = 200 * healthPercent;
tween(ship, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
ship.tint = self.level > 1 ? 0xcc00cc : 0x9b59b6;
}
});
// Change patterns more quickly when damaged
if (self.health < self.maxHealth * 0.5 && self.phaseTime > 150) {
self.changePattern();
}
return self.health <= 0;
};
self.changePattern = function () {
self.currentPattern = (self.currentPattern + 1) % self.patterns.length;
self.phaseTime = 0;
self.phase = 0;
};
self.update = function () {
self.phaseTime++;
// Change pattern every so often
if (self.phaseTime > 300) {
self.changePattern();
}
var pattern = self.patterns[self.currentPattern];
switch (pattern) {
case 'side-to-side':
// Move side to side
self.targetX = 1024 + Math.sin(self.phaseTime * 0.02) * 800;
if (self.phaseTime < 60) {
self.targetY = Math.min(self.y + 2, 400);
} else {
self.targetY = 400;
}
break;
case 'charge':
// Charge down then back up
if (self.phase === 0) {
self.targetY = self.y + 5;
if (self.y > 800) {
self.phase = 1;
}
} else {
self.targetY = Math.max(self.y - 3, 300);
if (self.y <= 300) {
self.phase = 0;
}
}
self.targetX = 1024 + Math.sin(self.phaseTime * 0.03) * 500;
break;
case 'retreat':
// Stay near top and move quickly
self.targetY = 300;
self.targetX = 1024 + Math.sin(self.phaseTime * 0.05) * 900;
break;
}
// Move toward target position
self.x += (self.targetX - self.x) * 0.05;
self.y += (self.targetY - self.y) * 0.05;
};
return self;
});
var Enemy = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'basic';
var assetType = self.type === 'fast' ? 'enemy' : 'enemy';
var ship = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
// Different enemy types
if (self.type === 'basic') {
self.health = 1;
self.speed = 2;
self.scoreValue = 10;
self.shootChance = 0.01;
} else if (self.type === 'fast') {
self.health = 1;
self.speed = 3.5;
self.scoreValue = 15;
ship.scaleX = 0.8;
ship.scaleY = 0.8;
self.shootChance = 0.005;
ship.tint = 0xff9966;
} else if (self.type === 'tank') {
self.health = 3;
self.speed = 1.5;
self.scoreValue = 25;
ship.scaleX = 1.2;
ship.scaleY = 1.2;
self.shootChance = 0.015;
ship.tint = 0x66ff66;
}
self.movement = {
pattern: 'straight',
phase: Math.random() * Math.PI * 2,
amplitude: 60 + Math.random() * 60
};
self.initialX = 0;
self.damage = function (amount) {
self.health -= amount || 1;
tween(ship, {
tint: 0xffffff
}, {
duration: 200,
onFinish: function onFinish() {
ship.tint = self.type === 'fast' ? 0xff9966 : self.type === 'tank' ? 0x66ff66 : 0xe74c3c;
}
});
return self.health <= 0;
};
self.update = function () {
// Basic movement
self.y += self.speed;
// Pattern movement
if (self.movement.pattern === 'sine') {
self.x = self.initialX + Math.sin(LK.ticks * 0.05 + self.movement.phase) * self.movement.amplitude;
} else if (self.movement.pattern === 'zigzag') {
var timeScale = 0.02;
var t = LK.ticks * timeScale + self.movement.phase;
var triangleWave = Math.abs(t % 2 - 1) * 2 - 1;
self.x = self.initialX + triangleWave * self.movement.amplitude;
}
};
return self;
});
var EnemyLaser = Container.expand(function () {
var self = Container.call(this);
var laser = self.attachAsset('enemyLaser', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosion = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9
});
// Set up fade and scale
tween(explosion, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 500,
onFinish: function onFinish() {
self.destroy();
}
});
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var ship = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.shield = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.lives = 3;
self.shieldActive = false;
self.fireRate = 20;
self.lastShot = 0;
self.canShoot = true;
self.power = 1;
self.invulnerable = false;
self.activateShield = function (duration) {
self.shieldActive = true;
self.shield.alpha = 0.4;
LK.setTimeout(function () {
self.shieldActive = false;
tween(self.shield, {
alpha: 0
}, {
duration: 500
});
}, duration);
};
self.damage = function () {
if (self.invulnerable || self.shieldActive) {
return;
}
self.lives--;
LK.getSound('playerDamage').play();
// Make player temporarily invulnerable
self.invulnerable = true;
// Flash the player to show invulnerability
var flashCount = 0;
var flashInterval = LK.setInterval(function () {
ship.alpha = ship.alpha === 0.3 ? 1 : 0.3;
flashCount++;
if (flashCount >= 10) {
LK.clearInterval(flashInterval);
ship.alpha = 1;
self.invulnerable = false;
}
}, 150);
};
self.upgrade = function (type) {
LK.getSound('powerup').play();
if (type === 'shield') {
self.activateShield(8000);
} else if (type === 'power') {
self.power = Math.min(self.power + 1, 3);
// Reset power after some time
LK.setTimeout(function () {
self.power = Math.max(1, self.power - 1);
}, 10000);
} else if (type === 'life') {
self.lives = Math.min(self.lives + 1, 5);
} else if (type === 'speed') {
var oldFireRate = self.fireRate;
self.fireRate = Math.max(self.fireRate - 5, 10);
// Reset fire rate after some time
LK.setTimeout(function () {
self.fireRate = oldFireRate;
}, 10000);
}
};
return self;
});
var PlayerLaser = Container.expand(function () {
var self = Container.call(this);
var laser = self.attachAsset('playerLaser', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -15;
self.power = 1;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Powerup = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || ['shield', 'power', 'life', 'speed'][Math.floor(Math.random() * 4)];
var powerup = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
// Set color based on type
if (self.type === 'shield') {
powerup.tint = 0x3498db; // Blue
} else if (self.type === 'power') {
powerup.tint = 0xe74c3c; // Red
} else if (self.type === 'life') {
powerup.tint = 0x2ecc71; // Green
} else if (self.type === 'speed') {
powerup.tint = 0xf1c40f; // Yellow
}
self.speed = 3;
self.update = function () {
self.y += self.speed;
powerup.rotation += 0.05;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000022
});
/****
* Game Code
****/
// Game variables
var player;
var playerLasers = [];
var enemies = [];
var enemyLasers = [];
var asteroids = [];
var powerups = [];
var explosions = [];
var boss = null;
var gameState = 'playing';
var score = 0;
var waveNumber = 1;
var enemiesThisWave = 0;
var enemiesDefeated = 0;
var waveDelay = 0;
var bossWave = false;
var dragStartPosition = {
x: 0,
y: 0
};
// UI elements
var scoreTxt = new Text2('SCORE: 0', {
size: 40,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -250;
scoreTxt.y = 50;
var waveText = new Text2('WAVE: 1', {
size: 40,
fill: 0xFFFFFF
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
waveText.y = 50;
var livesText = new Text2('LIVES: 3', {
size: 40,
fill: 0xFFFFFF
});
livesText.anchor.set(0, 0);
LK.gui.topLeft.addChild(livesText);
livesText.x = 150; // Keep away from the top-left menu icon
livesText.y = 50;
// Create game elements
function initGame() {
// Reset game variables
playerLasers = [];
enemies = [];
enemyLasers = [];
asteroids = [];
powerups = [];
explosions = [];
boss = null;
gameState = 'playing';
score = 0;
waveNumber = 1;
enemiesThisWave = 10;
enemiesDefeated = 0;
waveDelay = 0;
bossWave = false;
// Update UI
scoreTxt.setText('SCORE: ' + score);
waveText.setText('WAVE: ' + waveNumber);
// Create player
player = new Player();
player.x = 1024;
player.y = 2200;
game.addChild(player);
livesText.setText('LIVES: ' + player.lives);
// Start with player moving up
tween(player, {
y: 2000
}, {
duration: 1000
});
// Start the music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
// Create first wave
createWave();
}
// Create a new wave of enemies
function createWave() {
waveNumber++;
waveText.setText('WAVE: ' + waveNumber);
// Every 5 waves is a boss wave
bossWave = waveNumber % 5 === 0;
if (bossWave) {
// Create a boss
var bossLevel = Math.ceil(waveNumber / 5);
LK.getSound('bossAlert').play();
boss = new Boss(bossLevel);
boss.x = 1024;
boss.y = -200;
game.addChild(boss);
tween(boss, {
y: 300
}, {
duration: 2000
});
// Show boss wave text
var bossText = new Text2('BOSS WAVE!', {
size: 80,
fill: 0xFF0000
});
bossText.anchor.set(0.5, 0.5);
bossText.x = 1024;
bossText.y = 800;
game.addChild(bossText);
tween(bossText, {
alpha: 0,
y: 700
}, {
duration: 2000,
onFinish: function onFinish() {
bossText.destroy();
}
});
return;
}
// Regular wave
enemiesThisWave = 10 + waveNumber * 2;
enemiesDefeated = 0;
// Show wave text
var newWaveText = new Text2('WAVE ' + waveNumber, {
size: 80,
fill: 0xFFFFFF
});
newWaveText.anchor.set(0.5, 0.5);
newWaveText.x = 1024;
newWaveText.y = 800;
game.addChild(newWaveText);
tween(newWaveText, {
alpha: 0,
y: 700
}, {
duration: 2000,
onFinish: function onFinish() {
newWaveText.destroy();
}
});
// Start spawning enemies after a short delay
waveDelay = 120;
}
// Create a new enemy
function spawnEnemy() {
var types = ['basic'];
// Add more enemy types as waves progress
if (waveNumber >= 2) {
types.push('fast');
}
if (waveNumber >= 3) {
types.push('tank');
}
var type = types[Math.floor(Math.random() * types.length)];
var enemy = new Enemy(type);
// Position the enemy
enemy.x = Math.random() * 1800 + 124;
enemy.y = -100;
enemy.initialX = enemy.x;
// Set random movement pattern
var patterns = ['straight'];
if (waveNumber >= 2) {
patterns.push('sine');
}
if (waveNumber >= 4) {
patterns.push('zigzag');
}
enemy.movement.pattern = patterns[Math.floor(Math.random() * patterns.length)];
// Add to game
enemies.push(enemy);
game.addChild(enemy);
}
// Create a new asteroid
function spawnAsteroid() {
var asteroid = new Asteroid();
// Position the asteroid
asteroid.x = Math.random() * 1800 + 124;
asteroid.y = -100;
// Add to game
asteroids.push(asteroid);
game.addChild(asteroid);
}
// Create a player laser
function firePlayerLaser() {
if (!player || !player.canShoot || player.lastShot + player.fireRate > LK.ticks) {
return;
}
player.lastShot = LK.ticks;
LK.getSound('playerShoot').play();
// Fire based on power level
if (player.power === 1) {
var laser = new PlayerLaser();
laser.x = player.x;
laser.y = player.y - 50;
laser.power = player.power;
playerLasers.push(laser);
game.addChild(laser);
} else if (player.power === 2) {
for (var i = -1; i <= 1; i += 2) {
var laser = new PlayerLaser();
laser.x = player.x + i * 30;
laser.y = player.y - 40;
laser.power = player.power;
playerLasers.push(laser);
game.addChild(laser);
}
} else if (player.power >= 3) {
var centerLaser = new PlayerLaser();
centerLaser.x = player.x;
centerLaser.y = player.y - 50;
centerLaser.power = player.power;
playerLasers.push(centerLaser);
game.addChild(centerLaser);
for (var i = -1; i <= 1; i += 2) {
var sideLaser = new PlayerLaser();
sideLaser.x = player.x + i * 40;
sideLaser.y = player.y - 30;
sideLaser.power = player.power - 1;
playerLasers.push(sideLaser);
game.addChild(sideLaser);
}
}
}
// Create an enemy laser
function fireEnemyLaser(enemy) {
var laser = new EnemyLaser();
laser.x = enemy.x;
laser.y = enemy.y + 40;
enemyLasers.push(laser);
game.addChild(laser);
LK.getSound('enemyShoot').play({
volume: 0.2
});
}
// Fire boss laser pattern
function fireBossLasers() {
if (!boss) {
return;
}
// Different patterns based on boss level and health
var healthPercent = boss.health / boss.maxHealth;
var pattern = 'spread';
if (boss.level >= 2 && healthPercent < 0.5) {
pattern = 'circle';
}
if (pattern === 'spread') {
for (var i = -2; i <= 2; i++) {
var laser = new EnemyLaser();
laser.x = boss.x + i * 50;
laser.y = boss.y + 80;
enemyLasers.push(laser);
game.addChild(laser);
}
} else if (pattern === 'circle') {
var numLasers = 8;
for (var i = 0; i < numLasers; i++) {
var angle = i / numLasers * Math.PI * 2;
var laser = new EnemyLaser();
laser.x = boss.x + Math.cos(angle) * 100;
laser.y = boss.y + Math.sin(angle) * 100;
enemyLasers.push(laser);
game.addChild(laser);
// Add directional motion
laser.update = function () {
var dx = this.x - boss.x;
var dy = this.y - boss.y;
var length = Math.sqrt(dx * dx + dy * dy);
this.x += dx / length * 5;
this.y += dy / length * 5;
};
}
}
LK.getSound('enemyShoot').play({
volume: 0.4
});
}
// Create explosion animation
function createExplosion(x, y, scale) {
var explosion = new Explosion();
explosion.x = x;
explosion.y = y;
if (scale) {
explosion.scale.set(scale, scale);
}
explosions.push(explosion);
game.addChild(explosion);
LK.getSound('explosion').play();
}
// Create a powerup
function spawnPowerup(x, y, type) {
var powerup = new Powerup(type);
powerup.x = x;
powerup.y = y;
powerups.push(powerup);
game.addChild(powerup);
}
// Handle player shooting and movement
function handlePlayerInput() {
// Keep player in bounds
player.x = Math.max(100, Math.min(player.x, 2048 - 100));
player.y = Math.max(100, Math.min(player.y, 2732 - 100));
// Auto-fire
if (LK.ticks % 10 === 0) {
firePlayerLaser();
}
}
// Handle collisions between game objects
function handleCollisions() {
// Player lasers vs enemies
for (var i = playerLasers.length - 1; i >= 0; i--) {
var laser = playerLasers[i];
var hitSomething = false;
// Check against enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (laser.intersects(enemy)) {
// Damage enemy
if (enemy.damage(laser.power)) {
// Enemy destroyed
createExplosion(enemy.x, enemy.y);
// Add score
score += enemy.scoreValue;
scoreTxt.setText('SCORE: ' + score);
// Count enemy as defeated
enemiesDefeated++;
// Chance to spawn powerup
if (Math.random() < 0.1) {
spawnPowerup(enemy.x, enemy.y);
}
enemy.destroy();
enemies.splice(j, 1);
}
// Remove laser
laser.destroy();
playerLasers.splice(i, 1);
hitSomething = true;
break;
}
}
// Only check other collisions if we haven't hit an enemy
if (!hitSomething) {
// Check against boss
if (boss && laser.intersects(boss)) {
// Damage boss
if (boss.damage(laser.power)) {
// Boss destroyed
createExplosion(boss.x, boss.y, 2);
// Add score
score += boss.scoreValue;
scoreTxt.setText('SCORE: ' + score);
// Spawn multiple powerups
for (var p = 0; p < 3; p++) {
var powerupType = ['shield', 'power', 'life', 'speed'][Math.floor(Math.random() * 4)];
spawnPowerup(boss.x + (Math.random() * 200 - 100), boss.y + (Math.random() * 200 - 100), powerupType);
}
boss.destroy();
boss = null;
// Move to next wave
createWave();
}
// Remove laser
laser.destroy();
playerLasers.splice(i, 1);
hitSomething = true;
}
// Check against asteroids
for (var k = asteroids.length - 1; k >= 0; k--) {
var asteroid = asteroids[k];
if (laser.intersects(asteroid)) {
// Damage asteroid
if (asteroid.damage(laser.power)) {
// Asteroid destroyed
createExplosion(asteroid.x, asteroid.y, 0.7);
// Add score
score += asteroid.scoreValue;
scoreTxt.setText('SCORE: ' + score);
asteroid.destroy();
asteroids.splice(k, 1);
}
// Remove laser
laser.destroy();
playerLasers.splice(i, 1);
hitSomething = true;
break;
}
}
}
// Remove laser if it's off screen
if (!hitSomething && laser.y < -50) {
laser.destroy();
playerLasers.splice(i, 1);
}
}
// Enemy lasers vs player
for (var i = enemyLasers.length - 1; i >= 0; i--) {
var laser = enemyLasers[i];
if (player && laser.intersects(player)) {
// Damage player
player.damage();
// Update UI
livesText.setText('LIVES: ' + player.lives);
// Check for game over
if (player.lives <= 0) {
// Game over
createExplosion(player.x, player.y, 1.5);
player.destroy();
player = null;
// Save high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
// Show game over after a delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
// Remove laser
laser.destroy();
enemyLasers.splice(i, 1);
} else if (laser.y > 2732 + 50) {
// Remove laser if it's off screen
laser.destroy();
enemyLasers.splice(i, 1);
}
}
// Player vs enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (player && player.intersects(enemy)) {
// Damage player
player.damage();
// Damage enemy
enemy.damage(1);
// Update UI
livesText.setText('LIVES: ' + player.lives);
// Check for enemy death
if (enemy.health <= 0) {
// Enemy destroyed
createExplosion(enemy.x, enemy.y);
// Add score
score += enemy.scoreValue;
scoreTxt.setText('SCORE: ' + score);
// Count enemy as defeated
enemiesDefeated++;
enemy.destroy();
enemies.splice(i, 1);
}
// Check for game over
if (player.lives <= 0) {
// Game over
createExplosion(player.x, player.y, 1.5);
player.destroy();
player = null;
// Save high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
// Show game over after a delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
// Remove enemy if it's off screen
if (enemy.y > 2732 + 100) {
enemy.destroy();
enemies.splice(i, 1);
}
}
// Player vs asteroids
for (var i = asteroids.length - 1; i >= 0; i--) {
var asteroid = asteroids[i];
if (player && player.intersects(asteroid)) {
// Damage player
player.damage();
// Damage asteroid
asteroid.damage(1);
// Update UI
livesText.setText('LIVES: ' + player.lives);
// Check for asteroid death
if (asteroid.health <= 0) {
// Asteroid destroyed
createExplosion(asteroid.x, asteroid.y, 0.7);
// Add score
score += asteroid.scoreValue;
scoreTxt.setText('SCORE: ' + score);
asteroid.destroy();
asteroids.splice(i, 1);
}
// Check for game over
if (player.lives <= 0) {
// Game over
createExplosion(player.x, player.y, 1.5);
player.destroy();
player = null;
// Save high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
// Show game over after a delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
// Remove asteroid if it's off screen
if (asteroid.y > 2732 + 100 || asteroid.x < -100 || asteroid.x > 2048 + 100) {
asteroid.destroy();
asteroids.splice(i, 1);
}
}
// Player vs powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
if (player && player.intersects(powerup)) {
// Apply powerup
player.upgrade(powerup.type);
// Update UI if life powerup
if (powerup.type === 'life') {
livesText.setText('LIVES: ' + player.lives);
}
// Remove powerup
powerup.destroy();
powerups.splice(i, 1);
} else if (powerup.y > 2732 + 50) {
// Remove powerup if it's off screen
powerup.destroy();
powerups.splice(i, 1);
}
}
// Player vs boss
if (player && boss && player.intersects(boss)) {
// Damage player
player.damage();
// Update UI
livesText.setText('LIVES: ' + player.lives);
// Check for game over
if (player.lives <= 0) {
// Game over
createExplosion(player.x, player.y, 1.5);
player.destroy();
player = null;
// Save high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
// Show game over after a delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
}
// Initialize the game
initGame();
// Game down event handler
game.down = function (x, y, obj) {
if (!player) {
return;
}
dragStartPosition.x = x;
dragStartPosition.y = y;
// Fire lasers on tap
firePlayerLaser();
};
// Game move event handler
game.move = function (x, y, obj) {
if (!player) {
return;
}
// Move player with drag
player.x = x;
player.y = y;
};
// Game update handler
game.update = function () {
if (gameState !== 'playing') {
return;
}
// Handle player input
if (player) {
handlePlayerInput();
}
// Handle wave creation
if (waveDelay > 0) {
waveDelay--;
} else if (!bossWave && enemies.length === 0 && enemiesDefeated >= enemiesThisWave) {
// All enemies for this wave defeated, create next wave
createWave();
} else if (!bossWave && enemies.length < 5 && enemiesDefeated < enemiesThisWave && LK.ticks % 30 === 0) {
// Spawn more enemies for this wave
spawnEnemy();
}
// Spawn asteroids occasionally
if (LK.ticks % 180 === 0 && Math.random() < 0.7) {
spawnAsteroid();
}
// Boss shooting
if (boss && LK.ticks % 90 === 0) {
fireBossLasers();
}
// Enemy shooting
for (var i = 0; i < enemies.length; i++) {
if (Math.random() < enemies[i].shootChance) {
fireEnemyLaser(enemies[i]);
}
}
// Collision detection
handleCollisions();
};
space ship. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
asteroid. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
space enemy. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
explosion. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
shield. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
powerup. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
space boss ufo. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
green laser. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
red laser. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat