User prompt
Add sound effects to each new wave, when you die, and when you get a power up
User prompt
Every 10 waves make a boss ship with better bullets and has more health then other enemies
User prompt
I can’t see the logo on the green power ups
User prompt
Make the power up logos more visible
User prompt
Make a logo on the power ups to show what the power up is
User prompt
Make rare power ups that don’t spawn as much with double and triple shot
User prompt
Make the faster firing power up not as laggy
User prompt
Make it so you can pick up the power ups and powers your character
User prompt
Make power ups flow down sometimes, after you kill an enemy
User prompt
Make some enemies have faster bullets and a different Star Wars ship
User prompt
Make the ships look like a Star Wars ship
User prompt
Make the character and enemies look like ships
Code edit (1 edits merged)
Please save this source code
User prompt
Galactic Defender
Initial prompt
A space invader game shooting at other ships
/**** * 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();
}
};