/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BossJet = Container.expand(function () {
var self = Container.call(this);
var jetGraphics = self.attachAsset('bossJet', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 500;
self.maxHealth = 500;
self.damage = 25;
self.speed = 2;
self.shootTimer = 0;
self.shootDelay = 180;
self.moveTimer = 0;
self.phase = 1;
self.missileTimer = 0;
self.missileDelay = 200;
self.laserTimer = 0;
self.laserDelay = 280;
self.update = function () {
self.moveTimer++;
if (self.y < 300) {
self.y += self.speed;
} else {
// Enhanced movement pattern with more variation
var movementIntensity = 3 + (self.phase - 1) * 2;
var movementSpeed = 0.05 + (self.phase - 1) * 0.02;
self.x += Math.sin(self.moveTimer * movementSpeed) * movementIntensity;
// Add occasional position changes for more unpredictable movement
if (self.moveTimer % 180 === 0) {
var targetX = 400 + Math.random() * 1248;
var deltaX = targetX - self.x;
self.x += deltaX * 0.1;
}
if (self.x < 200) self.x = 200;
if (self.x > 1848) self.x = 1848;
}
if (self.shootTimer > 0) {
self.shootTimer--;
} else {
self.shoot();
}
if (self.missileTimer > 0) {
self.missileTimer--;
} else if (self.phase >= 1) {
self.shootMissile();
}
if (self.laserTimer > 0) {
self.laserTimer--;
} else if (self.phase >= 2) {
self.shootLaser();
}
if (self.health < self.maxHealth * 0.5 && self.phase === 1) {
self.phase = 2;
self.shootDelay = 85;
self.missileDelay = 100;
jetGraphics.tint = 0xFF6B6B;
}
};
self.shoot = function () {
for (var i = -1; i <= 1; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x + i * 40;
bullet.y = self.y + 60;
bullet.damage = self.damage;
enemyBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('shoot').play();
self.shootTimer = self.shootDelay;
};
self.shootMissile = function () {
var missile = new BossMissile();
missile.x = self.x;
missile.y = self.y + 60;
missile.targetPlayer = player;
missile.damage = 30;
bossMissiles.push(missile);
game.addChild(missile);
self.missileTimer = self.missileDelay;
};
self.shootLaser = function () {
var laser = new BossLaser();
laser.x = player.x;
laser.y = -200;
laser.moveDown = true;
bossLasers.push(laser);
game.addChild(laser);
self.laserTimer = self.laserDelay;
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
LK.getSound('enemyHit').play();
var bossDropPowerUp = new PowerUpBoss();
bossDropPowerUp.x = self.x;
bossDropPowerUp.y = self.y;
powerUps.push(bossDropPowerUp);
game.addChild(bossDropPowerUp);
self.destroy();
bossDefeated = true;
LK.setScore(LK.getScore() + 1000);
scoreText.setText('Score: ' + LK.getScore());
}
};
return self;
});
var BossLaser = Container.expand(function () {
var self = Container.call(this);
var laserGraphics = self.attachAsset('bossLaser', {
anchorX: 0.5,
anchorY: 0
});
self.damage = 50;
self.duration = 120;
self.timer = 0;
self.warningTimer = 60;
self.active = false;
self.moveDown = false;
laserGraphics.alpha = 0;
self.update = function () {
self.timer++;
if (self.moveDown) {
self.y += 5;
}
if (self.timer < self.warningTimer) {
// Warning phase - red tint and flashing
laserGraphics.alpha = 0.3 + Math.sin(self.timer * 0.3) * 0.2;
laserGraphics.tint = 0xff0000;
} else if (self.timer < self.duration) {
// Active laser phase
if (!self.active) {
self.active = true;
laserGraphics.tint = 0x00ff00;
laserGraphics.alpha = 0.8;
}
} else {
self.destroy();
}
};
return self;
});
var BossMissile = Container.expand(function () {
var self = Container.call(this);
var missileGraphics = self.attachAsset('bossMissile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6.5;
self.damage = 30;
self.turnSpeed = 0.05;
self.targetPlayer = null;
self.update = function () {
if (self.targetPlayer) {
var dx = self.targetPlayer.x - self.x;
var dy = self.targetPlayer.y - self.y;
var targetAngle = Math.atan2(dy, dx);
var currentAngle = self.rotation;
var angleDiff = targetAngle - currentAngle;
while (angleDiff > Math.PI) angleDiff -= Math.PI * 2;
while (angleDiff < -Math.PI) angleDiff += Math.PI * 2;
self.rotation += angleDiff * self.turnSpeed;
self.x += Math.cos(self.rotation) * self.speed;
self.y += Math.sin(self.rotation) * self.speed;
} else {
self.y += self.speed;
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 7;
self.damage = 15;
self.update = function () {
self.y += self.speed;
};
return self;
});
var EnemyJet = Container.expand(function () {
var self = Container.call(this);
var jetGraphics = self.attachAsset('enemyJet', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 40;
self.damage = 15;
self.speed = 1.2;
self.shootTimer = 0;
self.shootDelay = 85;
self.movePattern = 'straight';
self.moveTimer = 0;
self.update = function () {
self.moveTimer++;
if (self.movePattern === 'straight') {
self.y += self.speed;
// Keep enemy within screen bounds
if (self.y > 2600) {
self.y = 2600;
self.speed = -Math.abs(self.speed); // Reverse direction
} else if (self.y < 100) {
self.y = 100;
self.speed = Math.abs(self.speed); // Move down again
}
} else if (self.movePattern === 'zigzag') {
self.y += self.speed;
self.x += Math.sin(self.moveTimer * 0.1) * 2;
// Keep enemy within screen bounds
if (self.y > 2600) {
self.y = 2600;
self.speed = -Math.abs(self.speed); // Reverse direction
} else if (self.y < 100) {
self.y = 100;
self.speed = Math.abs(self.speed); // Move down again
}
// Keep X position within bounds for zigzag pattern
if (self.x < 100) self.x = 100;
if (self.x > 1948) self.x = 1948;
}
if (self.shootTimer > 0) {
self.shootTimer--;
} else if (self.y > 200 && self.y < 2000) {
self.shoot();
}
};
self.shoot = function () {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 40;
bullet.damage = self.damage;
enemyBullets.push(bullet);
game.addChild(bullet);
self.shootTimer = self.shootDelay;
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
LK.getSound('enemyHit').play();
self.destroy();
enemiesKilled++;
LK.setScore(LK.getScore() + 100);
scoreText.setText('Score: ' + LK.getScore());
if (Math.random() < 0.15) {
spawnPowerUp(self.x, self.y);
}
}
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -10;
self.damage = 20;
self.update = function () {
self.y += self.speed;
};
return self;
});
var PlayerJet = Container.expand(function () {
var self = Container.call(this);
var jetGraphics = self.attachAsset('playerJet', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.damage = 20;
self.speed = 8;
self.shootTimer = 0;
self.shootDelay = 50;
self.shieldActive = false;
self.shieldTimer = 0;
self.damageBoostActive = false;
self.damageBoostTimer = 0;
self.specialWeaponActive = false;
self.specialWeaponTimer = 0;
self.update = function () {
if (self.shootTimer > 0) self.shootTimer--;
if (self.shieldActive) {
self.shieldTimer--;
if (self.shieldTimer <= 0) {
self.shieldActive = false;
jetGraphics.tint = 0xFFFFFF;
}
}
if (self.damageBoostActive) {
self.damageBoostTimer--;
if (self.damageBoostTimer <= 0) {
self.damageBoostActive = false;
jetGraphics.tint = self.shieldActive ? 0x3498DB : 0xFFFFFF;
}
}
if (self.specialWeaponActive) {
self.specialWeaponTimer--;
if (self.specialWeaponTimer <= 0) {
self.specialWeaponActive = false;
}
}
};
self.shoot = function () {
if (self.shootTimer > 0) return;
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - 50;
bullet.damage = self.damageBoostActive ? self.damage * 2 : self.damage;
playerBullets.push(bullet);
game.addChild(bullet);
if (self.specialWeaponActive) {
var leftBullet = new PlayerBullet();
leftBullet.x = self.x - 30;
leftBullet.y = self.y - 40;
leftBullet.damage = bullet.damage;
playerBullets.push(leftBullet);
game.addChild(leftBullet);
var rightBullet = new PlayerBullet();
rightBullet.x = self.x + 30;
rightBullet.y = self.y - 40;
rightBullet.damage = bullet.damage;
playerBullets.push(rightBullet);
game.addChild(rightBullet);
}
if (self.specialWeaponActive) {
self.shootTimer = Math.ceil(self.shootDelay * 2);
} else {
self.shootTimer = self.shootDelay;
}
LK.getSound('shoot').play();
};
self.takeDamage = function (damage) {
if (self.shieldActive) return;
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 300);
LK.getSound('playerHit').play();
if (self.health <= 0) {
LK.showGameOver();
}
};
self.activateShield = function () {
self.shieldActive = true;
self.shieldTimer = 300;
jetGraphics.tint = 0x3498DB;
};
self.activateDamageBoost = function () {
self.damageBoostActive = true;
self.damageBoostTimer = 300;
jetGraphics.tint = self.shieldActive ? 0x9B59B6 : 0x27AE60;
};
self.activateSpecialWeapon = function () {
self.specialWeaponActive = true;
self.specialWeaponTimer = 300;
};
self.upgrade = function () {
self.maxHealth += 20;
self.health = self.maxHealth;
self.damage += 5;
self.speed += 0.5;
if (self.shootDelay > 5) self.shootDelay -= 1;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
self.type = 'damage';
self.speed = 2;
self.bobTimer = 0;
self.setType = function (type) {
self.type = type;
var assetId = 'powerUpDamage';
if (type === 'shield') assetId = 'powerUpShield';else if (type === 'special') assetId = 'powerUpSpecial';
var graphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.update = function () {
self.y += self.speed;
self.bobTimer++;
self.scaleX = 1 + Math.sin(self.bobTimer * 0.2) * 0.1;
self.scaleY = 1 + Math.sin(self.bobTimer * 0.2) * 0.1;
};
return self;
});
var PowerUpBoss = Container.expand(function () {
var self = Container.call(this);
self.type = 'boss';
self.speed = 2;
self.bobTimer = 0;
var graphics = self.attachAsset('powerUpSpecial', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.y += self.speed;
self.bobTimer++;
self.scaleX = 1 + Math.sin(self.bobTimer * 0.15) * 0.15;
self.scaleY = 1 + Math.sin(self.bobTimer * 0.15) * 0.15;
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1 + Math.random() * 2;
self.twinkleTimer = Math.random() * 120;
self.update = function () {
self.y += self.speed;
self.twinkleTimer++;
// Twinkling effect
starGraphics.alpha = 0.3 + Math.sin(self.twinkleTimer * 0.05) * 0.3;
// Reset position when off screen
if (self.y > 2800) {
self.y = -20;
self.x = Math.random() * 2048;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000511
});
/****
* Game Code
****/
var player = game.addChild(new PlayerJet());
player.x = 1024;
player.y = 2400;
var enemies = [];
var playerBullets = [];
var enemyBullets = [];
var bossMissiles = [];
var bossLasers = [];
var powerUps = [];
var stars = [];
var starSpawnTimer = 0;
var currentWave = 1;
var maxWaves = 20;
var waveInProgress = false;
var enemiesInWave = 0;
var enemiesKilled = 0;
var enemiesOffScreen = 0;
var bossWave = false;
var bossDefeated = false;
var waveStartTimer = 0;
var gameWon = false;
var dragActive = false;
var scoreText = new Text2('Score: 0', {
size: 80,
fill: '#ffffff'
});
scoreText.anchor.set(0, 0);
scoreText.x = 120;
scoreText.y = 50;
LK.gui.topLeft.addChild(scoreText);
var waveText = new Text2('Wave 1', {
size: 100,
fill: '#FFD700'
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
var healthText = new Text2('Health: 100', {
size: 80,
fill: '#E74C3C'
});
healthText.anchor.set(1, 0);
healthText.x = -50;
healthText.y = 50;
LK.gui.topRight.addChild(healthText);
function spawnWave() {
if (currentWave > maxWaves) {
if (!gameWon) {
gameWon = true;
LK.showYouWin();
}
return;
}
waveInProgress = true;
bossWave = currentWave % 2 === 0;
enemiesKilled = 0;
bossDefeated = false;
waveText.setText('Wave ' + currentWave);
if (bossWave) {
enemiesInWave = 1;
var boss = new BossJet();
boss.x = 300 + Math.random() * 1448; // Random X position within safe bounds
boss.y = -100;
boss.health = 700 + (currentWave - 2) * 200;
boss.maxHealth = boss.health;
enemies.push(boss);
game.addChild(boss);
} else {
enemiesInWave = Math.min(3 + currentWave, 8);
for (var i = 0; i < enemiesInWave; i++) {
LK.setTimeout(function () {
var enemy = new EnemyJet();
enemy.x = 300 + Math.random() * 1448;
enemy.y = -100 - Math.random() * 300;
enemy.health = 40 + currentWave * 20;
enemy.speed += currentWave * 0.3;
enemy.shootDelay = Math.max(80, 140 - currentWave * 3);
if (currentWave >= 3 && Math.random() < 0.4) {
enemy.movePattern = 'zigzag';
}
enemies.push(enemy);
game.addChild(enemy);
}, i * 800);
}
}
}
function spawnPowerUp(x, y) {
var powerUp = new PowerUp();
var types = ['damage', 'shield', 'special'];
var randomType = types[Math.floor(Math.random() * types.length)];
powerUp.setType(randomType);
powerUp.x = x;
powerUp.y = y;
powerUps.push(powerUp);
game.addChild(powerUp);
}
function checkWaveComplete() {
if (!waveInProgress) return;
var allEnemiesDefeated = false;
if (bossWave) {
allEnemiesDefeated = bossDefeated;
} else {
allEnemiesDefeated = enemiesKilled + enemiesOffScreen >= enemiesInWave;
}
if (allEnemiesDefeated) {
waveInProgress = false;
currentWave++;
enemiesOffScreen = 0; // Reset off-screen counter
if (currentWave <= maxWaves) {
player.upgrade();
LK.getSound('waveComplete').play();
LK.effects.flashScreen(0x27AE60, 1000);
waveStartTimer = 180;
}
}
}
game.down = function (x, y, obj) {
dragActive = true;
player.x = x;
player.y = y;
};
game.move = function (x, y, obj) {
if (dragActive) {
player.x = Math.max(60, Math.min(1988, x));
player.y = Math.max(200, Math.min(2600, y));
}
};
game.up = function (x, y, obj) {
dragActive = false;
};
game.update = function () {
if (waveStartTimer > 0) {
waveStartTimer--;
if (waveStartTimer === 0) {
spawnWave();
}
} else if (!waveInProgress && currentWave <= maxWaves) {
spawnWave();
}
player.shoot();
healthText.setText('Health: ' + Math.max(0, player.health));
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.y < -50) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
if (i < 0 || i >= playerBullets.length) continue;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
enemy.takeDamage(bullet.damage);
bullet.destroy();
playerBullets.splice(i, 1);
if (enemy.health <= 0) {
enemies.splice(j, 1);
}
break;
}
}
}
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.y > 2800) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
if (bullet.intersects(player)) {
player.takeDamage(bullet.damage);
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
for (var i = bossMissiles.length - 1; i >= 0; i--) {
var missile = bossMissiles[i];
if (missile.y > 2800 || missile.x < -100 || missile.x > 2148) {
missile.destroy();
bossMissiles.splice(i, 1);
continue;
}
if (missile.intersects(player)) {
player.takeDamage(missile.damage);
missile.destroy();
bossMissiles.splice(i, 1);
}
}
for (var i = bossLasers.length - 1; i >= 0; i--) {
var laser = bossLasers[i];
if (laser.timer >= laser.duration) {
bossLasers.splice(i, 1);
continue;
}
if (laser.active && laser.intersects(player)) {
player.takeDamage(laser.damage);
laser.destroy();
bossLasers.splice(i, 1);
}
}
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (powerUp.y > 2800) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
if (powerUp.intersects(player)) {
LK.getSound('powerUp').play();
if (powerUp.type === 'damage') {
player.activateDamageBoost();
} else if (powerUp.type === 'shield') {
player.activateShield();
} else if (powerUp.type === 'special') {
player.activateSpecialWeapon();
} else if (powerUp.type === 'boss') {
player.activateSpecialWeapon();
}
powerUp.destroy();
powerUps.splice(i, 1);
}
}
// Check for enemies that went off screen
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.y > 2800 || enemy.y < -200 || enemy.x < -200 || enemy.x > 2248) {
if (!bossWave) {
// Don't count boss as off-screen
enemiesOffScreen++;
}
enemy.destroy();
enemies.splice(i, 1);
}
}
// Spawn stars for background
starSpawnTimer++;
if (starSpawnTimer > 20) {
starSpawnTimer = 0;
if (stars.length < 50) {
var star = new Star();
star.x = Math.random() * 2048;
star.y = -20;
stars.push(star);
game.addChild(star);
}
}
// Update and cleanup stars
for (var i = stars.length - 1; i >= 0; i--) {
var star = stars[i];
if (star.y > 2800) {
star.destroy();
stars.splice(i, 1);
}
}
checkWaveComplete();
};
LK.playMusic('combat'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BossJet = Container.expand(function () {
var self = Container.call(this);
var jetGraphics = self.attachAsset('bossJet', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 500;
self.maxHealth = 500;
self.damage = 25;
self.speed = 2;
self.shootTimer = 0;
self.shootDelay = 180;
self.moveTimer = 0;
self.phase = 1;
self.missileTimer = 0;
self.missileDelay = 200;
self.laserTimer = 0;
self.laserDelay = 280;
self.update = function () {
self.moveTimer++;
if (self.y < 300) {
self.y += self.speed;
} else {
// Enhanced movement pattern with more variation
var movementIntensity = 3 + (self.phase - 1) * 2;
var movementSpeed = 0.05 + (self.phase - 1) * 0.02;
self.x += Math.sin(self.moveTimer * movementSpeed) * movementIntensity;
// Add occasional position changes for more unpredictable movement
if (self.moveTimer % 180 === 0) {
var targetX = 400 + Math.random() * 1248;
var deltaX = targetX - self.x;
self.x += deltaX * 0.1;
}
if (self.x < 200) self.x = 200;
if (self.x > 1848) self.x = 1848;
}
if (self.shootTimer > 0) {
self.shootTimer--;
} else {
self.shoot();
}
if (self.missileTimer > 0) {
self.missileTimer--;
} else if (self.phase >= 1) {
self.shootMissile();
}
if (self.laserTimer > 0) {
self.laserTimer--;
} else if (self.phase >= 2) {
self.shootLaser();
}
if (self.health < self.maxHealth * 0.5 && self.phase === 1) {
self.phase = 2;
self.shootDelay = 85;
self.missileDelay = 100;
jetGraphics.tint = 0xFF6B6B;
}
};
self.shoot = function () {
for (var i = -1; i <= 1; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x + i * 40;
bullet.y = self.y + 60;
bullet.damage = self.damage;
enemyBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('shoot').play();
self.shootTimer = self.shootDelay;
};
self.shootMissile = function () {
var missile = new BossMissile();
missile.x = self.x;
missile.y = self.y + 60;
missile.targetPlayer = player;
missile.damage = 30;
bossMissiles.push(missile);
game.addChild(missile);
self.missileTimer = self.missileDelay;
};
self.shootLaser = function () {
var laser = new BossLaser();
laser.x = player.x;
laser.y = -200;
laser.moveDown = true;
bossLasers.push(laser);
game.addChild(laser);
self.laserTimer = self.laserDelay;
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
LK.getSound('enemyHit').play();
var bossDropPowerUp = new PowerUpBoss();
bossDropPowerUp.x = self.x;
bossDropPowerUp.y = self.y;
powerUps.push(bossDropPowerUp);
game.addChild(bossDropPowerUp);
self.destroy();
bossDefeated = true;
LK.setScore(LK.getScore() + 1000);
scoreText.setText('Score: ' + LK.getScore());
}
};
return self;
});
var BossLaser = Container.expand(function () {
var self = Container.call(this);
var laserGraphics = self.attachAsset('bossLaser', {
anchorX: 0.5,
anchorY: 0
});
self.damage = 50;
self.duration = 120;
self.timer = 0;
self.warningTimer = 60;
self.active = false;
self.moveDown = false;
laserGraphics.alpha = 0;
self.update = function () {
self.timer++;
if (self.moveDown) {
self.y += 5;
}
if (self.timer < self.warningTimer) {
// Warning phase - red tint and flashing
laserGraphics.alpha = 0.3 + Math.sin(self.timer * 0.3) * 0.2;
laserGraphics.tint = 0xff0000;
} else if (self.timer < self.duration) {
// Active laser phase
if (!self.active) {
self.active = true;
laserGraphics.tint = 0x00ff00;
laserGraphics.alpha = 0.8;
}
} else {
self.destroy();
}
};
return self;
});
var BossMissile = Container.expand(function () {
var self = Container.call(this);
var missileGraphics = self.attachAsset('bossMissile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6.5;
self.damage = 30;
self.turnSpeed = 0.05;
self.targetPlayer = null;
self.update = function () {
if (self.targetPlayer) {
var dx = self.targetPlayer.x - self.x;
var dy = self.targetPlayer.y - self.y;
var targetAngle = Math.atan2(dy, dx);
var currentAngle = self.rotation;
var angleDiff = targetAngle - currentAngle;
while (angleDiff > Math.PI) angleDiff -= Math.PI * 2;
while (angleDiff < -Math.PI) angleDiff += Math.PI * 2;
self.rotation += angleDiff * self.turnSpeed;
self.x += Math.cos(self.rotation) * self.speed;
self.y += Math.sin(self.rotation) * self.speed;
} else {
self.y += self.speed;
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 7;
self.damage = 15;
self.update = function () {
self.y += self.speed;
};
return self;
});
var EnemyJet = Container.expand(function () {
var self = Container.call(this);
var jetGraphics = self.attachAsset('enemyJet', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 40;
self.damage = 15;
self.speed = 1.2;
self.shootTimer = 0;
self.shootDelay = 85;
self.movePattern = 'straight';
self.moveTimer = 0;
self.update = function () {
self.moveTimer++;
if (self.movePattern === 'straight') {
self.y += self.speed;
// Keep enemy within screen bounds
if (self.y > 2600) {
self.y = 2600;
self.speed = -Math.abs(self.speed); // Reverse direction
} else if (self.y < 100) {
self.y = 100;
self.speed = Math.abs(self.speed); // Move down again
}
} else if (self.movePattern === 'zigzag') {
self.y += self.speed;
self.x += Math.sin(self.moveTimer * 0.1) * 2;
// Keep enemy within screen bounds
if (self.y > 2600) {
self.y = 2600;
self.speed = -Math.abs(self.speed); // Reverse direction
} else if (self.y < 100) {
self.y = 100;
self.speed = Math.abs(self.speed); // Move down again
}
// Keep X position within bounds for zigzag pattern
if (self.x < 100) self.x = 100;
if (self.x > 1948) self.x = 1948;
}
if (self.shootTimer > 0) {
self.shootTimer--;
} else if (self.y > 200 && self.y < 2000) {
self.shoot();
}
};
self.shoot = function () {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 40;
bullet.damage = self.damage;
enemyBullets.push(bullet);
game.addChild(bullet);
self.shootTimer = self.shootDelay;
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.health <= 0) {
LK.getSound('enemyHit').play();
self.destroy();
enemiesKilled++;
LK.setScore(LK.getScore() + 100);
scoreText.setText('Score: ' + LK.getScore());
if (Math.random() < 0.15) {
spawnPowerUp(self.x, self.y);
}
}
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -10;
self.damage = 20;
self.update = function () {
self.y += self.speed;
};
return self;
});
var PlayerJet = Container.expand(function () {
var self = Container.call(this);
var jetGraphics = self.attachAsset('playerJet', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.maxHealth = 100;
self.damage = 20;
self.speed = 8;
self.shootTimer = 0;
self.shootDelay = 50;
self.shieldActive = false;
self.shieldTimer = 0;
self.damageBoostActive = false;
self.damageBoostTimer = 0;
self.specialWeaponActive = false;
self.specialWeaponTimer = 0;
self.update = function () {
if (self.shootTimer > 0) self.shootTimer--;
if (self.shieldActive) {
self.shieldTimer--;
if (self.shieldTimer <= 0) {
self.shieldActive = false;
jetGraphics.tint = 0xFFFFFF;
}
}
if (self.damageBoostActive) {
self.damageBoostTimer--;
if (self.damageBoostTimer <= 0) {
self.damageBoostActive = false;
jetGraphics.tint = self.shieldActive ? 0x3498DB : 0xFFFFFF;
}
}
if (self.specialWeaponActive) {
self.specialWeaponTimer--;
if (self.specialWeaponTimer <= 0) {
self.specialWeaponActive = false;
}
}
};
self.shoot = function () {
if (self.shootTimer > 0) return;
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - 50;
bullet.damage = self.damageBoostActive ? self.damage * 2 : self.damage;
playerBullets.push(bullet);
game.addChild(bullet);
if (self.specialWeaponActive) {
var leftBullet = new PlayerBullet();
leftBullet.x = self.x - 30;
leftBullet.y = self.y - 40;
leftBullet.damage = bullet.damage;
playerBullets.push(leftBullet);
game.addChild(leftBullet);
var rightBullet = new PlayerBullet();
rightBullet.x = self.x + 30;
rightBullet.y = self.y - 40;
rightBullet.damage = bullet.damage;
playerBullets.push(rightBullet);
game.addChild(rightBullet);
}
if (self.specialWeaponActive) {
self.shootTimer = Math.ceil(self.shootDelay * 2);
} else {
self.shootTimer = self.shootDelay;
}
LK.getSound('shoot').play();
};
self.takeDamage = function (damage) {
if (self.shieldActive) return;
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 300);
LK.getSound('playerHit').play();
if (self.health <= 0) {
LK.showGameOver();
}
};
self.activateShield = function () {
self.shieldActive = true;
self.shieldTimer = 300;
jetGraphics.tint = 0x3498DB;
};
self.activateDamageBoost = function () {
self.damageBoostActive = true;
self.damageBoostTimer = 300;
jetGraphics.tint = self.shieldActive ? 0x9B59B6 : 0x27AE60;
};
self.activateSpecialWeapon = function () {
self.specialWeaponActive = true;
self.specialWeaponTimer = 300;
};
self.upgrade = function () {
self.maxHealth += 20;
self.health = self.maxHealth;
self.damage += 5;
self.speed += 0.5;
if (self.shootDelay > 5) self.shootDelay -= 1;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
self.type = 'damage';
self.speed = 2;
self.bobTimer = 0;
self.setType = function (type) {
self.type = type;
var assetId = 'powerUpDamage';
if (type === 'shield') assetId = 'powerUpShield';else if (type === 'special') assetId = 'powerUpSpecial';
var graphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.update = function () {
self.y += self.speed;
self.bobTimer++;
self.scaleX = 1 + Math.sin(self.bobTimer * 0.2) * 0.1;
self.scaleY = 1 + Math.sin(self.bobTimer * 0.2) * 0.1;
};
return self;
});
var PowerUpBoss = Container.expand(function () {
var self = Container.call(this);
self.type = 'boss';
self.speed = 2;
self.bobTimer = 0;
var graphics = self.attachAsset('powerUpSpecial', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.y += self.speed;
self.bobTimer++;
self.scaleX = 1 + Math.sin(self.bobTimer * 0.15) * 0.15;
self.scaleY = 1 + Math.sin(self.bobTimer * 0.15) * 0.15;
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1 + Math.random() * 2;
self.twinkleTimer = Math.random() * 120;
self.update = function () {
self.y += self.speed;
self.twinkleTimer++;
// Twinkling effect
starGraphics.alpha = 0.3 + Math.sin(self.twinkleTimer * 0.05) * 0.3;
// Reset position when off screen
if (self.y > 2800) {
self.y = -20;
self.x = Math.random() * 2048;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000511
});
/****
* Game Code
****/
var player = game.addChild(new PlayerJet());
player.x = 1024;
player.y = 2400;
var enemies = [];
var playerBullets = [];
var enemyBullets = [];
var bossMissiles = [];
var bossLasers = [];
var powerUps = [];
var stars = [];
var starSpawnTimer = 0;
var currentWave = 1;
var maxWaves = 20;
var waveInProgress = false;
var enemiesInWave = 0;
var enemiesKilled = 0;
var enemiesOffScreen = 0;
var bossWave = false;
var bossDefeated = false;
var waveStartTimer = 0;
var gameWon = false;
var dragActive = false;
var scoreText = new Text2('Score: 0', {
size: 80,
fill: '#ffffff'
});
scoreText.anchor.set(0, 0);
scoreText.x = 120;
scoreText.y = 50;
LK.gui.topLeft.addChild(scoreText);
var waveText = new Text2('Wave 1', {
size: 100,
fill: '#FFD700'
});
waveText.anchor.set(0.5, 0);
LK.gui.top.addChild(waveText);
var healthText = new Text2('Health: 100', {
size: 80,
fill: '#E74C3C'
});
healthText.anchor.set(1, 0);
healthText.x = -50;
healthText.y = 50;
LK.gui.topRight.addChild(healthText);
function spawnWave() {
if (currentWave > maxWaves) {
if (!gameWon) {
gameWon = true;
LK.showYouWin();
}
return;
}
waveInProgress = true;
bossWave = currentWave % 2 === 0;
enemiesKilled = 0;
bossDefeated = false;
waveText.setText('Wave ' + currentWave);
if (bossWave) {
enemiesInWave = 1;
var boss = new BossJet();
boss.x = 300 + Math.random() * 1448; // Random X position within safe bounds
boss.y = -100;
boss.health = 700 + (currentWave - 2) * 200;
boss.maxHealth = boss.health;
enemies.push(boss);
game.addChild(boss);
} else {
enemiesInWave = Math.min(3 + currentWave, 8);
for (var i = 0; i < enemiesInWave; i++) {
LK.setTimeout(function () {
var enemy = new EnemyJet();
enemy.x = 300 + Math.random() * 1448;
enemy.y = -100 - Math.random() * 300;
enemy.health = 40 + currentWave * 20;
enemy.speed += currentWave * 0.3;
enemy.shootDelay = Math.max(80, 140 - currentWave * 3);
if (currentWave >= 3 && Math.random() < 0.4) {
enemy.movePattern = 'zigzag';
}
enemies.push(enemy);
game.addChild(enemy);
}, i * 800);
}
}
}
function spawnPowerUp(x, y) {
var powerUp = new PowerUp();
var types = ['damage', 'shield', 'special'];
var randomType = types[Math.floor(Math.random() * types.length)];
powerUp.setType(randomType);
powerUp.x = x;
powerUp.y = y;
powerUps.push(powerUp);
game.addChild(powerUp);
}
function checkWaveComplete() {
if (!waveInProgress) return;
var allEnemiesDefeated = false;
if (bossWave) {
allEnemiesDefeated = bossDefeated;
} else {
allEnemiesDefeated = enemiesKilled + enemiesOffScreen >= enemiesInWave;
}
if (allEnemiesDefeated) {
waveInProgress = false;
currentWave++;
enemiesOffScreen = 0; // Reset off-screen counter
if (currentWave <= maxWaves) {
player.upgrade();
LK.getSound('waveComplete').play();
LK.effects.flashScreen(0x27AE60, 1000);
waveStartTimer = 180;
}
}
}
game.down = function (x, y, obj) {
dragActive = true;
player.x = x;
player.y = y;
};
game.move = function (x, y, obj) {
if (dragActive) {
player.x = Math.max(60, Math.min(1988, x));
player.y = Math.max(200, Math.min(2600, y));
}
};
game.up = function (x, y, obj) {
dragActive = false;
};
game.update = function () {
if (waveStartTimer > 0) {
waveStartTimer--;
if (waveStartTimer === 0) {
spawnWave();
}
} else if (!waveInProgress && currentWave <= maxWaves) {
spawnWave();
}
player.shoot();
healthText.setText('Health: ' + Math.max(0, player.health));
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.y < -50) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
if (i < 0 || i >= playerBullets.length) continue;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
enemy.takeDamage(bullet.damage);
bullet.destroy();
playerBullets.splice(i, 1);
if (enemy.health <= 0) {
enemies.splice(j, 1);
}
break;
}
}
}
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.y > 2800) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
if (bullet.intersects(player)) {
player.takeDamage(bullet.damage);
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
for (var i = bossMissiles.length - 1; i >= 0; i--) {
var missile = bossMissiles[i];
if (missile.y > 2800 || missile.x < -100 || missile.x > 2148) {
missile.destroy();
bossMissiles.splice(i, 1);
continue;
}
if (missile.intersects(player)) {
player.takeDamage(missile.damage);
missile.destroy();
bossMissiles.splice(i, 1);
}
}
for (var i = bossLasers.length - 1; i >= 0; i--) {
var laser = bossLasers[i];
if (laser.timer >= laser.duration) {
bossLasers.splice(i, 1);
continue;
}
if (laser.active && laser.intersects(player)) {
player.takeDamage(laser.damage);
laser.destroy();
bossLasers.splice(i, 1);
}
}
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (powerUp.y > 2800) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
if (powerUp.intersects(player)) {
LK.getSound('powerUp').play();
if (powerUp.type === 'damage') {
player.activateDamageBoost();
} else if (powerUp.type === 'shield') {
player.activateShield();
} else if (powerUp.type === 'special') {
player.activateSpecialWeapon();
} else if (powerUp.type === 'boss') {
player.activateSpecialWeapon();
}
powerUp.destroy();
powerUps.splice(i, 1);
}
}
// Check for enemies that went off screen
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.y > 2800 || enemy.y < -200 || enemy.x < -200 || enemy.x > 2248) {
if (!bossWave) {
// Don't count boss as off-screen
enemiesOffScreen++;
}
enemy.destroy();
enemies.splice(i, 1);
}
}
// Spawn stars for background
starSpawnTimer++;
if (starSpawnTimer > 20) {
starSpawnTimer = 0;
if (stars.length < 50) {
var star = new Star();
star.x = Math.random() * 2048;
star.y = -20;
stars.push(star);
game.addChild(star);
}
}
// Update and cleanup stars
for (var i = stars.length - 1; i >= 0; i--) {
var star = stars[i];
if (star.y > 2800) {
star.destroy();
stars.splice(i, 1);
}
}
checkWaveComplete();
};
LK.playMusic('combat');