/**** * 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();
}
};