/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BossBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bossBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10; // Faster than regular enemy bullets
self.update = function () {
self.y += self.speed;
};
return self;
});
var BossShip = Container.expand(function () {
var self = Container.call(this);
// Central large cockpit
var cockpit = self.attachAsset('bossShipCockpit', {
anchorX: 0.5,
anchorY: 0.5
});
// Main body
var body = self.attachAsset('bossShip', {
anchorX: 0.5,
anchorY: 0.5
});
// Top wing
var topWing = self.attachAsset('bossShipWing', {
anchorX: 0.5,
anchorY: 0.5
});
topWing.y = -25;
// Bottom wing
var bottomWing = self.attachAsset('bossShipWing', {
anchorX: 0.5,
anchorY: 0.5
});
bottomWing.y = 25;
// Multiple engines
var leftEngine = self.attachAsset('bossShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
leftEngine.x = -40;
leftEngine.y = 0;
var rightEngine = self.attachAsset('bossShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
rightEngine.x = 40;
rightEngine.y = 0;
var centerEngine = self.attachAsset('bossShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
centerEngine.y = 30;
self.health = 5; // Takes 5 hits to destroy
self.maxHealth = 5;
self.speed = 1.5;
self.direction = 1;
self.shootTimer = Math.floor(Math.random() * 60) + 30;
self.shootDelay = 60; // Shoots more frequently than regular enemies
self.update = function () {
// Move horizontally slower but more menacingly
self.x += self.speed * self.direction;
// Bounce off edges and move down
if (self.x <= 150 || self.x >= 1898) {
self.direction *= -1;
self.y += 40;
}
// Aggressive shooting pattern
self.shootTimer--;
if (self.shootTimer <= 0 && Math.random() < 0.25) {
self.shootTimer = self.shootDelay + Math.floor(Math.random() * 30);
// Shoot multiple bullets in spread pattern
for (var i = 0; i < 3; i++) {
var bullet = new BossBullet();
bullet.x = self.x + (i - 1) * 30; // Spread bullets
bullet.y = self.y + 40;
enemyBullets.push(bullet);
game.addChild(bullet);
}
}
// Visual health indicator - tint based on health
var healthRatio = self.health / self.maxHealth;
if (healthRatio > 0.6) {
body.tint = 0x660000; // Dark red
} else if (healthRatio > 0.3) {
body.tint = 0x880000; // Medium red
} else {
body.tint = 0xaa0000; // Light red
}
};
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 = 8;
self.update = function () {
self.y += self.speed;
};
return self;
});
var EnemyShip = Container.expand(function () {
var self = Container.call(this);
// Central cockpit sphere (TIE Fighter style)
var cockpit = self.attachAsset('enemyShipCockpit', {
anchorX: 0.5,
anchorY: 0.5
});
// Left solar panel
var leftPanel = self.attachAsset('enemyShipSolarPanel', {
anchorX: 0.5,
anchorY: 0.5
});
leftPanel.x = -35;
leftPanel.y = 0;
// Right solar panel
var rightPanel = self.attachAsset('enemyShipSolarPanel', {
anchorX: 0.5,
anchorY: 0.5
});
rightPanel.x = 35;
rightPanel.y = 0;
// Center connecting bars
var leftBar = self.attachAsset('enemyShipCenterBar', {
anchorX: 0.5,
anchorY: 0.5
});
leftBar.x = -17;
leftBar.y = 0;
var rightBar = self.attachAsset('enemyShipCenterBar', {
anchorX: 0.5,
anchorY: 0.5
});
rightBar.x = 17;
rightBar.y = 0;
self.speed = 2;
self.direction = 1; // 1 for right, -1 for left
self.shootTimer = Math.floor(Math.random() * 120) + 60; // Random shoot timing
self.shootDelay = 120; // Shoot every 2 seconds on average
self.update = function () {
// Move horizontally
self.x += self.speed * self.direction;
// Bounce off edges and move down
if (self.x <= 100 || self.x >= 1948) {
self.direction *= -1;
self.y += 60;
}
// Occasional shooting
self.shootTimer--;
if (self.shootTimer <= 0 && Math.random() < 0.1) {
self.shootTimer = self.shootDelay + Math.floor(Math.random() * 60);
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 30;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
return self;
});
var FastEnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('fastEnemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 14; // Faster than regular enemy bullets
self.update = function () {
self.y += self.speed;
};
return self;
});
var FastEnemyShip = Container.expand(function () {
var self = Container.call(this);
// Central cockpit (TIE Interceptor style - smaller and more angular)
var cockpit = self.attachAsset('fastEnemyShipCockpit', {
anchorX: 0.5,
anchorY: 0.5
});
// Angled wing configuration (TIE Interceptor style)
var topWing = self.attachAsset('fastEnemyShipWing', {
anchorX: 0.5,
anchorY: 0.5
});
topWing.x = 0;
topWing.y = -15;
topWing.rotation = -0.3; // Angled upward
var bottomWing = self.attachAsset('fastEnemyShipWing', {
anchorX: 0.5,
anchorY: 0.5
});
bottomWing.x = 0;
bottomWing.y = 15;
bottomWing.rotation = 0.3; // Angled downward
// Wing tip engines
var leftEngine = self.attachAsset('fastEnemyShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
leftEngine.x = -25;
leftEngine.y = 0;
var rightEngine = self.attachAsset('fastEnemyShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
rightEngine.x = 25;
rightEngine.y = 0;
self.speed = 3; // Faster movement
self.direction = 1;
self.shootTimer = Math.floor(Math.random() * 90) + 30; // Shoots more frequently
self.shootDelay = 90;
self.update = function () {
// Move horizontally faster
self.x += self.speed * self.direction;
// Bounce off edges and move down
if (self.x <= 100 || self.x >= 1948) {
self.direction *= -1;
self.y += 60;
}
// More aggressive shooting
self.shootTimer--;
if (self.shootTimer <= 0 && Math.random() < 0.15) {
self.shootTimer = self.shootDelay + Math.floor(Math.random() * 40);
var bullet = new FastEnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 30;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
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 = -12;
self.update = function () {
self.y += self.speed;
};
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
// Main fuselage (X-Wing body)
var fuselage = self.attachAsset('playerShipFuselage', {
anchorX: 0.5,
anchorY: 0.5
});
// Cockpit
var cockpit = self.attachAsset('playerShipCockpit', {
anchorX: 0.5,
anchorY: 0.5
});
cockpit.y = -15;
// Top wing
var topWing = self.attachAsset('playerShipWing', {
anchorX: 0.5,
anchorY: 0.5
});
topWing.y = -10;
// Bottom wing
var bottomWing = self.attachAsset('playerShipWing', {
anchorX: 0.5,
anchorY: 0.5
});
bottomWing.y = 10;
// Engines (4 total for X-Wing)
var topLeftEngine = self.attachAsset('playerShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
topLeftEngine.x = -20;
topLeftEngine.y = -10;
var topRightEngine = self.attachAsset('playerShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
topRightEngine.x = 20;
topRightEngine.y = -10;
var bottomLeftEngine = self.attachAsset('playerShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
bottomLeftEngine.x = -20;
bottomLeftEngine.y = 10;
var bottomRightEngine = self.attachAsset('playerShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
bottomRightEngine.x = 20;
bottomRightEngine.y = 10;
// Laser cannons on wing tips
var topLeftLaser = self.attachAsset('playerShipLaser', {
anchorX: 0.5,
anchorY: 0.5
});
topLeftLaser.x = -25;
topLeftLaser.y = -10;
var topRightLaser = self.attachAsset('playerShipLaser', {
anchorX: 0.5,
anchorY: 0.5
});
topRightLaser.x = 25;
topRightLaser.y = -10;
var bottomLeftLaser = self.attachAsset('playerShipLaser', {
anchorX: 0.5,
anchorY: 0.5
});
bottomLeftLaser.x = -25;
bottomLeftLaser.y = 10;
var bottomRightLaser = self.attachAsset('playerShipLaser', {
anchorX: 0.5,
anchorY: 0.5
});
bottomRightLaser.x = 25;
bottomRightLaser.y = 10;
self.speed = 8;
self.shootTimer = 0;
self.shootDelay = 10; // Shoot every 10 ticks
self.shotType = 'single'; // Default shot type
self.update = function () {
// Auto-shoot
self.shootTimer++;
if (self.shootTimer >= self.shootDelay) {
self.shootTimer = 0;
// Create bullets based on shot type
if (self.shotType === 'double') {
// Create two bullets side by side
var bullet1 = new PlayerBullet();
bullet1.x = self.x - 15;
bullet1.y = self.y - 40;
playerBullets.push(bullet1);
game.addChild(bullet1);
var bullet2 = new PlayerBullet();
bullet2.x = self.x + 15;
bullet2.y = self.y - 40;
playerBullets.push(bullet2);
game.addChild(bullet2);
} else if (self.shotType === 'triple') {
// Create three bullets
var bullet1 = new PlayerBullet();
bullet1.x = self.x - 20;
bullet1.y = self.y - 40;
playerBullets.push(bullet1);
game.addChild(bullet1);
var bullet2 = new PlayerBullet();
bullet2.x = self.x;
bullet2.y = self.y - 40;
playerBullets.push(bullet2);
game.addChild(bullet2);
var bullet3 = new PlayerBullet();
bullet3.x = self.x + 20;
bullet3.y = self.y - 40;
playerBullets.push(bullet3);
game.addChild(bullet3);
} else {
// Single bullet (default)
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - 40;
playerBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('shoot').play();
}
};
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'health';
// Attach appropriate asset based on type
var assetName = 'powerUpHealth';
if (self.type === 'speed') {
assetName = 'powerUpSpeed';
} else if (self.type === 'weapon') {
assetName = 'powerUpWeapon';
} else if (self.type === 'doubleShot') {
assetName = 'powerUpDoubleShot';
} else if (self.type === 'tripleShot') {
assetName = 'powerUpTripleShot';
}
var powerUpGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Add logo symbols based on power-up type
if (self.type === 'health') {
// Cross symbol for health
var horizontalBar = self.attachAsset('powerUpHealthLogoH', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
horizontalBar.tint = 0x000000; // Black color for visibility on green background
var verticalBar = self.attachAsset('powerUpHealthLogoV', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
verticalBar.tint = 0x000000; // Black color for visibility on green background
} else if (self.type === 'speed') {
// Arrow symbol for speed
var arrow = self.attachAsset('powerUpSpeedLogo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
arrow.rotation = -Math.PI / 2; // Point upward
} else if (self.type === 'weapon') {
// Star/burst symbol for weapon power
var weaponLogo = self.attachAsset('powerUpWeaponLogo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
weaponLogo.rotation = Math.PI / 4; // Rotate 45 degrees to look like diamond
} else if (self.type === 'doubleShot') {
// Two bars for double shot
var leftBar = self.attachAsset('powerUpDoubleShotLogo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
leftBar.x = -6;
var rightBar = self.attachAsset('powerUpDoubleShotLogo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
rightBar.x = 6;
} else if (self.type === 'tripleShot') {
// Three dots for triple shot
var leftDot = self.attachAsset('powerUpTripleShotLogo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
leftDot.x = -8;
var centerDot = self.attachAsset('powerUpTripleShotLogo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
var rightDot = self.attachAsset('powerUpTripleShotLogo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
rightDot.x = 8;
}
self.speed = 4;
self.bobOffset = Math.random() * Math.PI * 2; // Random start for bobbing animation
self.bobAmount = 5;
self.update = function () {
self.y += self.speed;
// Add bobbing effect
powerUpGraphics.y = Math.sin(LK.ticks * 0.1 + self.bobOffset) * self.bobAmount;
// Slight rotation for visual appeal
powerUpGraphics.rotation += 0.05;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000022
});
/****
* Game Code
****/
// Game variables
var player;
var enemies = [];
var playerBullets = [];
var enemyBullets = [];
var powerUps = [];
var waveNumber = 1;
var enemiesPerWave = 12;
var waveSpawnTimer = 0;
var gameStarted = false;
var bossShips = [];
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var waveTxt = new Text2('Wave: 1', {
size: 50,
fill: 0xFFFF00
});
waveTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(waveTxt);
// Create player
player = game.addChild(new PlayerShip());
player.x = 1024;
player.y = 2600;
// Spawn initial wave
function spawnWave() {
// Play new wave sound (except for first wave)
if (waveNumber > 1) {
LK.getSound('newWave').play();
}
// Every 10th wave, spawn a boss instead of regular enemies
if (waveNumber % 10 === 0) {
// Boss wave - spawn 1-2 boss ships
var numBosses = Math.min(2, Math.floor(waveNumber / 10));
for (var b = 0; b < numBosses; b++) {
var boss = new BossShip();
boss.x = 500 + b * 600; // Space bosses apart
boss.y = 150;
boss.speed = 1 + waveNumber * 0.3;
bossShips.push(boss);
enemies.push(boss); // Add to enemies array for collision detection
game.addChild(boss);
}
} else {
// Regular wave
var enemiesInRow = 6;
var rows = Math.ceil(enemiesPerWave / enemiesInRow);
var startX = 300;
var startY = 200;
var spacingX = 200;
var spacingY = 100;
for (var i = 0; i < enemiesPerWave; i++) {
var row = Math.floor(i / enemiesInRow);
var col = i % enemiesInRow;
// 30% chance to spawn fast enemy ships after wave 2
var enemy;
if (waveNumber > 2 && Math.random() < 0.3) {
enemy = new FastEnemyShip();
} else {
enemy = new EnemyShip();
}
enemy.x = startX + col * spacingX;
enemy.y = startY + row * spacingY;
enemy.speed = 1 + waveNumber * 0.5; // Increase speed each wave
enemies.push(enemy);
game.addChild(enemy);
}
}
}
// Initial wave spawn
spawnWave();
// Touch controls for player movement
var isDragging = false;
game.down = function (x, y, obj) {
isDragging = true;
player.x = x;
};
game.move = function (x, y, obj) {
if (isDragging) {
player.x = Math.max(50, Math.min(1998, x)); // Keep player in bounds
}
};
game.up = function (x, y, obj) {
isDragging = false;
};
// Main game loop
game.update = function () {
// Update player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.lastY === undefined) bullet.lastY = bullet.y;
// Remove bullets that go off screen
if (bullet.lastY >= -50 && bullet.y < -50) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check collision with enemies
var hitEnemy = false;
for (var j = enemies.length - 1; j >= 0; j--) {
if (bullet.intersects(enemies[j])) {
// Check if this is a boss ship
var isBoss = false;
for (var bossIndex = 0; bossIndex < bossShips.length; bossIndex++) {
if (bossShips[bossIndex] === enemies[j]) {
isBoss = true;
// Boss takes multiple hits
enemies[j].health--;
LK.setScore(LK.getScore() + 25); // More points for hitting boss
scoreTxt.setText('Score: ' + LK.getScore());
LK.getSound('enemyHit').play();
LK.effects.flashObject(enemies[j], 0xffffff, 200);
if (enemies[j].health <= 0) {
// Boss destroyed - big score bonus and guaranteed power-up
LK.setScore(LK.getScore() + 500);
scoreTxt.setText('Score: ' + LK.getScore());
// Guaranteed rare power-up drop
var rarePowerUps = ['doubleShot', 'tripleShot'];
var randomType = rarePowerUps[Math.floor(Math.random() * rarePowerUps.length)];
var powerUp = new PowerUp(randomType);
powerUp.x = enemies[j].x;
powerUp.y = enemies[j].y;
powerUps.push(powerUp);
game.addChild(powerUp);
// Remove boss from arrays
bossShips.splice(bossIndex, 1);
enemies[j].destroy();
enemies.splice(j, 1);
}
break;
}
}
if (!isBoss) {
// Regular enemy - destroy in one hit
LK.setScore(LK.getScore() + 10);
scoreTxt.setText('Score: ' + LK.getScore());
LK.getSound('enemyHit').play();
LK.effects.flashObject(enemies[j], 0xffffff, 200);
// 20% chance to spawn a power-up when enemy is destroyed
if (Math.random() < 0.2) {
var powerUpTypes = ['health', 'speed', 'weapon'];
var randomValue = Math.random();
var randomType;
// 5% chance for rare power-ups
if (randomValue < 0.05) {
var rarePowerUps = ['doubleShot', 'tripleShot'];
randomType = rarePowerUps[Math.floor(Math.random() * rarePowerUps.length)];
} else {
randomType = powerUpTypes[Math.floor(Math.random() * powerUpTypes.length)];
}
var powerUp = new PowerUp(randomType);
powerUp.x = enemies[j].x;
powerUp.y = enemies[j].y;
powerUps.push(powerUp);
game.addChild(powerUp);
}
// Check if enemies reached player
enemies[j].destroy();
enemies.splice(j, 1);
}
// Remove bullet
bullet.destroy();
playerBullets.splice(i, 1);
hitEnemy = true;
break;
}
}
if (!hitEnemy) {
bullet.lastY = bullet.y;
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.lastY === undefined) bullet.lastY = bullet.y;
// Remove bullets that go off screen
if (bullet.lastY <= 2782 && bullet.y > 2782) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with player
if (bullet.intersects(player)) {
LK.getSound('playerHit').play();
LK.getSound('death').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
bullet.lastY = bullet.y;
}
// Check if enemies reached player
for (var i = 0; i < enemies.length; i++) {
if (enemies[i].intersects(player) || enemies[i].y > 2500) {
LK.getSound('playerHit').play();
LK.getSound('death').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Update power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (powerUp.lastY === undefined) powerUp.lastY = powerUp.y;
// Remove power-ups that go off screen
if (powerUp.lastY <= 2782 && powerUp.y > 2782) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
// Check collision with player
if (powerUp.intersects(player)) {
LK.getSound('powerUp').play();
LK.getSound('powerUpCollect').play();
LK.effects.flashObject(player, 0x00ff00, 500);
// Apply power-up effect based on type
if (powerUp.type === 'health') {
// Health power-up - add score bonus
LK.setScore(LK.getScore() + 50);
scoreTxt.setText('Score: ' + LK.getScore());
} else if (powerUp.type === 'speed') {
// Speed power-up - temporarily increase player speed
var originalSpeed = player.speed;
player.speed = originalSpeed * 1.5;
LK.setTimeout(function () {
player.speed = originalSpeed;
}, 5000); // 5 second duration
} else if (powerUp.type === 'weapon') {
// Weapon power-up - temporarily increase fire rate
var originalDelay = player.shootDelay;
player.shootDelay = Math.max(6, originalDelay / 1.5); // Less aggressive fire rate increase
LK.setTimeout(function () {
player.shootDelay = originalDelay;
}, 5000); // 5 second duration
} else if (powerUp.type === 'doubleShot') {
// Double shot power-up - temporarily enable double shot
var originalShotType = player.shotType;
player.shotType = 'double';
LK.setTimeout(function () {
player.shotType = originalShotType;
}, 8000); // 8 second duration
} else if (powerUp.type === 'tripleShot') {
// Triple shot power-up - temporarily enable triple shot
var originalShotType = player.shotType;
player.shotType = 'triple';
LK.setTimeout(function () {
player.shotType = originalShotType;
}, 10000); // 10 second duration
}
// Remove power-up
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
powerUp.lastY = powerUp.y;
}
// Check if wave is complete
if (enemies.length === 0) {
waveSpawnTimer++;
if (waveSpawnTimer > 120) {
// 2 second delay between waves
waveNumber++;
enemiesPerWave = Math.min(20, 12 + waveNumber); // Cap at 20 enemies
waveTxt.setText('Wave: ' + waveNumber);
spawnWave();
waveSpawnTimer = 0;
}
}
// Victory condition - survived 10 waves
if (waveNumber > 10 && enemies.length === 0) {
LK.showYouWin();
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BossBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bossBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10; // Faster than regular enemy bullets
self.update = function () {
self.y += self.speed;
};
return self;
});
var BossShip = Container.expand(function () {
var self = Container.call(this);
// Central large cockpit
var cockpit = self.attachAsset('bossShipCockpit', {
anchorX: 0.5,
anchorY: 0.5
});
// Main body
var body = self.attachAsset('bossShip', {
anchorX: 0.5,
anchorY: 0.5
});
// Top wing
var topWing = self.attachAsset('bossShipWing', {
anchorX: 0.5,
anchorY: 0.5
});
topWing.y = -25;
// Bottom wing
var bottomWing = self.attachAsset('bossShipWing', {
anchorX: 0.5,
anchorY: 0.5
});
bottomWing.y = 25;
// Multiple engines
var leftEngine = self.attachAsset('bossShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
leftEngine.x = -40;
leftEngine.y = 0;
var rightEngine = self.attachAsset('bossShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
rightEngine.x = 40;
rightEngine.y = 0;
var centerEngine = self.attachAsset('bossShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
centerEngine.y = 30;
self.health = 5; // Takes 5 hits to destroy
self.maxHealth = 5;
self.speed = 1.5;
self.direction = 1;
self.shootTimer = Math.floor(Math.random() * 60) + 30;
self.shootDelay = 60; // Shoots more frequently than regular enemies
self.update = function () {
// Move horizontally slower but more menacingly
self.x += self.speed * self.direction;
// Bounce off edges and move down
if (self.x <= 150 || self.x >= 1898) {
self.direction *= -1;
self.y += 40;
}
// Aggressive shooting pattern
self.shootTimer--;
if (self.shootTimer <= 0 && Math.random() < 0.25) {
self.shootTimer = self.shootDelay + Math.floor(Math.random() * 30);
// Shoot multiple bullets in spread pattern
for (var i = 0; i < 3; i++) {
var bullet = new BossBullet();
bullet.x = self.x + (i - 1) * 30; // Spread bullets
bullet.y = self.y + 40;
enemyBullets.push(bullet);
game.addChild(bullet);
}
}
// Visual health indicator - tint based on health
var healthRatio = self.health / self.maxHealth;
if (healthRatio > 0.6) {
body.tint = 0x660000; // Dark red
} else if (healthRatio > 0.3) {
body.tint = 0x880000; // Medium red
} else {
body.tint = 0xaa0000; // Light red
}
};
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 = 8;
self.update = function () {
self.y += self.speed;
};
return self;
});
var EnemyShip = Container.expand(function () {
var self = Container.call(this);
// Central cockpit sphere (TIE Fighter style)
var cockpit = self.attachAsset('enemyShipCockpit', {
anchorX: 0.5,
anchorY: 0.5
});
// Left solar panel
var leftPanel = self.attachAsset('enemyShipSolarPanel', {
anchorX: 0.5,
anchorY: 0.5
});
leftPanel.x = -35;
leftPanel.y = 0;
// Right solar panel
var rightPanel = self.attachAsset('enemyShipSolarPanel', {
anchorX: 0.5,
anchorY: 0.5
});
rightPanel.x = 35;
rightPanel.y = 0;
// Center connecting bars
var leftBar = self.attachAsset('enemyShipCenterBar', {
anchorX: 0.5,
anchorY: 0.5
});
leftBar.x = -17;
leftBar.y = 0;
var rightBar = self.attachAsset('enemyShipCenterBar', {
anchorX: 0.5,
anchorY: 0.5
});
rightBar.x = 17;
rightBar.y = 0;
self.speed = 2;
self.direction = 1; // 1 for right, -1 for left
self.shootTimer = Math.floor(Math.random() * 120) + 60; // Random shoot timing
self.shootDelay = 120; // Shoot every 2 seconds on average
self.update = function () {
// Move horizontally
self.x += self.speed * self.direction;
// Bounce off edges and move down
if (self.x <= 100 || self.x >= 1948) {
self.direction *= -1;
self.y += 60;
}
// Occasional shooting
self.shootTimer--;
if (self.shootTimer <= 0 && Math.random() < 0.1) {
self.shootTimer = self.shootDelay + Math.floor(Math.random() * 60);
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 30;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
return self;
});
var FastEnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('fastEnemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 14; // Faster than regular enemy bullets
self.update = function () {
self.y += self.speed;
};
return self;
});
var FastEnemyShip = Container.expand(function () {
var self = Container.call(this);
// Central cockpit (TIE Interceptor style - smaller and more angular)
var cockpit = self.attachAsset('fastEnemyShipCockpit', {
anchorX: 0.5,
anchorY: 0.5
});
// Angled wing configuration (TIE Interceptor style)
var topWing = self.attachAsset('fastEnemyShipWing', {
anchorX: 0.5,
anchorY: 0.5
});
topWing.x = 0;
topWing.y = -15;
topWing.rotation = -0.3; // Angled upward
var bottomWing = self.attachAsset('fastEnemyShipWing', {
anchorX: 0.5,
anchorY: 0.5
});
bottomWing.x = 0;
bottomWing.y = 15;
bottomWing.rotation = 0.3; // Angled downward
// Wing tip engines
var leftEngine = self.attachAsset('fastEnemyShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
leftEngine.x = -25;
leftEngine.y = 0;
var rightEngine = self.attachAsset('fastEnemyShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
rightEngine.x = 25;
rightEngine.y = 0;
self.speed = 3; // Faster movement
self.direction = 1;
self.shootTimer = Math.floor(Math.random() * 90) + 30; // Shoots more frequently
self.shootDelay = 90;
self.update = function () {
// Move horizontally faster
self.x += self.speed * self.direction;
// Bounce off edges and move down
if (self.x <= 100 || self.x >= 1948) {
self.direction *= -1;
self.y += 60;
}
// More aggressive shooting
self.shootTimer--;
if (self.shootTimer <= 0 && Math.random() < 0.15) {
self.shootTimer = self.shootDelay + Math.floor(Math.random() * 40);
var bullet = new FastEnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 30;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
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 = -12;
self.update = function () {
self.y += self.speed;
};
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
// Main fuselage (X-Wing body)
var fuselage = self.attachAsset('playerShipFuselage', {
anchorX: 0.5,
anchorY: 0.5
});
// Cockpit
var cockpit = self.attachAsset('playerShipCockpit', {
anchorX: 0.5,
anchorY: 0.5
});
cockpit.y = -15;
// Top wing
var topWing = self.attachAsset('playerShipWing', {
anchorX: 0.5,
anchorY: 0.5
});
topWing.y = -10;
// Bottom wing
var bottomWing = self.attachAsset('playerShipWing', {
anchorX: 0.5,
anchorY: 0.5
});
bottomWing.y = 10;
// Engines (4 total for X-Wing)
var topLeftEngine = self.attachAsset('playerShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
topLeftEngine.x = -20;
topLeftEngine.y = -10;
var topRightEngine = self.attachAsset('playerShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
topRightEngine.x = 20;
topRightEngine.y = -10;
var bottomLeftEngine = self.attachAsset('playerShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
bottomLeftEngine.x = -20;
bottomLeftEngine.y = 10;
var bottomRightEngine = self.attachAsset('playerShipEngine', {
anchorX: 0.5,
anchorY: 0.5
});
bottomRightEngine.x = 20;
bottomRightEngine.y = 10;
// Laser cannons on wing tips
var topLeftLaser = self.attachAsset('playerShipLaser', {
anchorX: 0.5,
anchorY: 0.5
});
topLeftLaser.x = -25;
topLeftLaser.y = -10;
var topRightLaser = self.attachAsset('playerShipLaser', {
anchorX: 0.5,
anchorY: 0.5
});
topRightLaser.x = 25;
topRightLaser.y = -10;
var bottomLeftLaser = self.attachAsset('playerShipLaser', {
anchorX: 0.5,
anchorY: 0.5
});
bottomLeftLaser.x = -25;
bottomLeftLaser.y = 10;
var bottomRightLaser = self.attachAsset('playerShipLaser', {
anchorX: 0.5,
anchorY: 0.5
});
bottomRightLaser.x = 25;
bottomRightLaser.y = 10;
self.speed = 8;
self.shootTimer = 0;
self.shootDelay = 10; // Shoot every 10 ticks
self.shotType = 'single'; // Default shot type
self.update = function () {
// Auto-shoot
self.shootTimer++;
if (self.shootTimer >= self.shootDelay) {
self.shootTimer = 0;
// Create bullets based on shot type
if (self.shotType === 'double') {
// Create two bullets side by side
var bullet1 = new PlayerBullet();
bullet1.x = self.x - 15;
bullet1.y = self.y - 40;
playerBullets.push(bullet1);
game.addChild(bullet1);
var bullet2 = new PlayerBullet();
bullet2.x = self.x + 15;
bullet2.y = self.y - 40;
playerBullets.push(bullet2);
game.addChild(bullet2);
} else if (self.shotType === 'triple') {
// Create three bullets
var bullet1 = new PlayerBullet();
bullet1.x = self.x - 20;
bullet1.y = self.y - 40;
playerBullets.push(bullet1);
game.addChild(bullet1);
var bullet2 = new PlayerBullet();
bullet2.x = self.x;
bullet2.y = self.y - 40;
playerBullets.push(bullet2);
game.addChild(bullet2);
var bullet3 = new PlayerBullet();
bullet3.x = self.x + 20;
bullet3.y = self.y - 40;
playerBullets.push(bullet3);
game.addChild(bullet3);
} else {
// Single bullet (default)
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - 40;
playerBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('shoot').play();
}
};
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'health';
// Attach appropriate asset based on type
var assetName = 'powerUpHealth';
if (self.type === 'speed') {
assetName = 'powerUpSpeed';
} else if (self.type === 'weapon') {
assetName = 'powerUpWeapon';
} else if (self.type === 'doubleShot') {
assetName = 'powerUpDoubleShot';
} else if (self.type === 'tripleShot') {
assetName = 'powerUpTripleShot';
}
var powerUpGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Add logo symbols based on power-up type
if (self.type === 'health') {
// Cross symbol for health
var horizontalBar = self.attachAsset('powerUpHealthLogoH', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
horizontalBar.tint = 0x000000; // Black color for visibility on green background
var verticalBar = self.attachAsset('powerUpHealthLogoV', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
verticalBar.tint = 0x000000; // Black color for visibility on green background
} else if (self.type === 'speed') {
// Arrow symbol for speed
var arrow = self.attachAsset('powerUpSpeedLogo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
arrow.rotation = -Math.PI / 2; // Point upward
} else if (self.type === 'weapon') {
// Star/burst symbol for weapon power
var weaponLogo = self.attachAsset('powerUpWeaponLogo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
weaponLogo.rotation = Math.PI / 4; // Rotate 45 degrees to look like diamond
} else if (self.type === 'doubleShot') {
// Two bars for double shot
var leftBar = self.attachAsset('powerUpDoubleShotLogo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
leftBar.x = -6;
var rightBar = self.attachAsset('powerUpDoubleShotLogo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
rightBar.x = 6;
} else if (self.type === 'tripleShot') {
// Three dots for triple shot
var leftDot = self.attachAsset('powerUpTripleShotLogo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
leftDot.x = -8;
var centerDot = self.attachAsset('powerUpTripleShotLogo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
var rightDot = self.attachAsset('powerUpTripleShotLogo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
rightDot.x = 8;
}
self.speed = 4;
self.bobOffset = Math.random() * Math.PI * 2; // Random start for bobbing animation
self.bobAmount = 5;
self.update = function () {
self.y += self.speed;
// Add bobbing effect
powerUpGraphics.y = Math.sin(LK.ticks * 0.1 + self.bobOffset) * self.bobAmount;
// Slight rotation for visual appeal
powerUpGraphics.rotation += 0.05;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000022
});
/****
* Game Code
****/
// Game variables
var player;
var enemies = [];
var playerBullets = [];
var enemyBullets = [];
var powerUps = [];
var waveNumber = 1;
var enemiesPerWave = 12;
var waveSpawnTimer = 0;
var gameStarted = false;
var bossShips = [];
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var waveTxt = new Text2('Wave: 1', {
size: 50,
fill: 0xFFFF00
});
waveTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(waveTxt);
// Create player
player = game.addChild(new PlayerShip());
player.x = 1024;
player.y = 2600;
// Spawn initial wave
function spawnWave() {
// Play new wave sound (except for first wave)
if (waveNumber > 1) {
LK.getSound('newWave').play();
}
// Every 10th wave, spawn a boss instead of regular enemies
if (waveNumber % 10 === 0) {
// Boss wave - spawn 1-2 boss ships
var numBosses = Math.min(2, Math.floor(waveNumber / 10));
for (var b = 0; b < numBosses; b++) {
var boss = new BossShip();
boss.x = 500 + b * 600; // Space bosses apart
boss.y = 150;
boss.speed = 1 + waveNumber * 0.3;
bossShips.push(boss);
enemies.push(boss); // Add to enemies array for collision detection
game.addChild(boss);
}
} else {
// Regular wave
var enemiesInRow = 6;
var rows = Math.ceil(enemiesPerWave / enemiesInRow);
var startX = 300;
var startY = 200;
var spacingX = 200;
var spacingY = 100;
for (var i = 0; i < enemiesPerWave; i++) {
var row = Math.floor(i / enemiesInRow);
var col = i % enemiesInRow;
// 30% chance to spawn fast enemy ships after wave 2
var enemy;
if (waveNumber > 2 && Math.random() < 0.3) {
enemy = new FastEnemyShip();
} else {
enemy = new EnemyShip();
}
enemy.x = startX + col * spacingX;
enemy.y = startY + row * spacingY;
enemy.speed = 1 + waveNumber * 0.5; // Increase speed each wave
enemies.push(enemy);
game.addChild(enemy);
}
}
}
// Initial wave spawn
spawnWave();
// Touch controls for player movement
var isDragging = false;
game.down = function (x, y, obj) {
isDragging = true;
player.x = x;
};
game.move = function (x, y, obj) {
if (isDragging) {
player.x = Math.max(50, Math.min(1998, x)); // Keep player in bounds
}
};
game.up = function (x, y, obj) {
isDragging = false;
};
// Main game loop
game.update = function () {
// Update player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.lastY === undefined) bullet.lastY = bullet.y;
// Remove bullets that go off screen
if (bullet.lastY >= -50 && bullet.y < -50) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check collision with enemies
var hitEnemy = false;
for (var j = enemies.length - 1; j >= 0; j--) {
if (bullet.intersects(enemies[j])) {
// Check if this is a boss ship
var isBoss = false;
for (var bossIndex = 0; bossIndex < bossShips.length; bossIndex++) {
if (bossShips[bossIndex] === enemies[j]) {
isBoss = true;
// Boss takes multiple hits
enemies[j].health--;
LK.setScore(LK.getScore() + 25); // More points for hitting boss
scoreTxt.setText('Score: ' + LK.getScore());
LK.getSound('enemyHit').play();
LK.effects.flashObject(enemies[j], 0xffffff, 200);
if (enemies[j].health <= 0) {
// Boss destroyed - big score bonus and guaranteed power-up
LK.setScore(LK.getScore() + 500);
scoreTxt.setText('Score: ' + LK.getScore());
// Guaranteed rare power-up drop
var rarePowerUps = ['doubleShot', 'tripleShot'];
var randomType = rarePowerUps[Math.floor(Math.random() * rarePowerUps.length)];
var powerUp = new PowerUp(randomType);
powerUp.x = enemies[j].x;
powerUp.y = enemies[j].y;
powerUps.push(powerUp);
game.addChild(powerUp);
// Remove boss from arrays
bossShips.splice(bossIndex, 1);
enemies[j].destroy();
enemies.splice(j, 1);
}
break;
}
}
if (!isBoss) {
// Regular enemy - destroy in one hit
LK.setScore(LK.getScore() + 10);
scoreTxt.setText('Score: ' + LK.getScore());
LK.getSound('enemyHit').play();
LK.effects.flashObject(enemies[j], 0xffffff, 200);
// 20% chance to spawn a power-up when enemy is destroyed
if (Math.random() < 0.2) {
var powerUpTypes = ['health', 'speed', 'weapon'];
var randomValue = Math.random();
var randomType;
// 5% chance for rare power-ups
if (randomValue < 0.05) {
var rarePowerUps = ['doubleShot', 'tripleShot'];
randomType = rarePowerUps[Math.floor(Math.random() * rarePowerUps.length)];
} else {
randomType = powerUpTypes[Math.floor(Math.random() * powerUpTypes.length)];
}
var powerUp = new PowerUp(randomType);
powerUp.x = enemies[j].x;
powerUp.y = enemies[j].y;
powerUps.push(powerUp);
game.addChild(powerUp);
}
// Check if enemies reached player
enemies[j].destroy();
enemies.splice(j, 1);
}
// Remove bullet
bullet.destroy();
playerBullets.splice(i, 1);
hitEnemy = true;
break;
}
}
if (!hitEnemy) {
bullet.lastY = bullet.y;
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.lastY === undefined) bullet.lastY = bullet.y;
// Remove bullets that go off screen
if (bullet.lastY <= 2782 && bullet.y > 2782) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with player
if (bullet.intersects(player)) {
LK.getSound('playerHit').play();
LK.getSound('death').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
bullet.lastY = bullet.y;
}
// Check if enemies reached player
for (var i = 0; i < enemies.length; i++) {
if (enemies[i].intersects(player) || enemies[i].y > 2500) {
LK.getSound('playerHit').play();
LK.getSound('death').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Update power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (powerUp.lastY === undefined) powerUp.lastY = powerUp.y;
// Remove power-ups that go off screen
if (powerUp.lastY <= 2782 && powerUp.y > 2782) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
// Check collision with player
if (powerUp.intersects(player)) {
LK.getSound('powerUp').play();
LK.getSound('powerUpCollect').play();
LK.effects.flashObject(player, 0x00ff00, 500);
// Apply power-up effect based on type
if (powerUp.type === 'health') {
// Health power-up - add score bonus
LK.setScore(LK.getScore() + 50);
scoreTxt.setText('Score: ' + LK.getScore());
} else if (powerUp.type === 'speed') {
// Speed power-up - temporarily increase player speed
var originalSpeed = player.speed;
player.speed = originalSpeed * 1.5;
LK.setTimeout(function () {
player.speed = originalSpeed;
}, 5000); // 5 second duration
} else if (powerUp.type === 'weapon') {
// Weapon power-up - temporarily increase fire rate
var originalDelay = player.shootDelay;
player.shootDelay = Math.max(6, originalDelay / 1.5); // Less aggressive fire rate increase
LK.setTimeout(function () {
player.shootDelay = originalDelay;
}, 5000); // 5 second duration
} else if (powerUp.type === 'doubleShot') {
// Double shot power-up - temporarily enable double shot
var originalShotType = player.shotType;
player.shotType = 'double';
LK.setTimeout(function () {
player.shotType = originalShotType;
}, 8000); // 8 second duration
} else if (powerUp.type === 'tripleShot') {
// Triple shot power-up - temporarily enable triple shot
var originalShotType = player.shotType;
player.shotType = 'triple';
LK.setTimeout(function () {
player.shotType = originalShotType;
}, 10000); // 10 second duration
}
// Remove power-up
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
powerUp.lastY = powerUp.y;
}
// Check if wave is complete
if (enemies.length === 0) {
waveSpawnTimer++;
if (waveSpawnTimer > 120) {
// 2 second delay between waves
waveNumber++;
enemiesPerWave = Math.min(20, 12 + waveNumber); // Cap at 20 enemies
waveTxt.setText('Wave: ' + waveNumber);
spawnWave();
waveSpawnTimer = 0;
}
}
// Victory condition - survived 10 waves
if (waveNumber > 10 && enemies.length === 0) {
LK.showYouWin();
}
};