/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { volume: 1 }); /**** * Classes ****/ var Alien = Container.expand(function (size) { var self = Container.call(this); self.size = size || 1; self.health = size; self.maxHealth = size; var assetName = 'alien' + size; var alienGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); self.speed = Math.random() * 3 + 2; self.lastShot = 0; self.shootDelay = 60 + Math.random() * 120; // AI behavior properties self.aiType = Math.floor(Math.random() * 4); // 0: aggressive, 1: evasive, 2: patrol, 3: formation self.baseX = self.x; self.patrolDirection = Math.random() < 0.5 ? -1 : 1; self.evasionTimer = 0; self.formationOffset = Math.random() * Math.PI * 2; self.aggressionLevel = Math.random() * 0.5 + 0.5; // 0.5 to 1.0 self.update = function () { self.y += self.speed; // AI Movement Behaviors if (self.aiType === 0) { // Aggressive: Move directly toward player with increasing speed var playerDistance = player.x - self.x; var horizontalSpeed = Math.min(Math.abs(playerDistance) * 0.02 * self.aggressionLevel, 2.5); if (playerDistance > 0) { self.x += horizontalSpeed; } else if (playerDistance < 0) { self.x -= horizontalSpeed; } // Increase speed when close to player if (Math.abs(playerDistance) < 200) { self.speed += 0.1; } } else if (self.aiType === 1) { // Evasive: Move away from player bullets and use unpredictable movement self.evasionTimer++; var nearbyBullet = false; for (var b = 0; b < playerBullets.length; b++) { var bullet = playerBullets[b]; var bulletDistance = Math.sqrt(Math.pow(bullet.x - self.x, 2) + Math.pow(bullet.y - self.y, 2)); if (bulletDistance < 150) { nearbyBullet = true; // Evade away from bullet if (bullet.x < self.x) { self.x += 3; } else { self.x -= 3; } break; } } // Random evasive movement when no immediate threat if (!nearbyBullet && self.evasionTimer % 60 === 0) { self.x += (Math.random() - 0.5) * 100; } } else if (self.aiType === 2) { // Patrol: Move in horizontal patterns while slowly tracking player var patrolSpeed = 1.5; self.x += self.patrolDirection * patrolSpeed; if (self.x < 200 || self.x > 1848) { self.patrolDirection *= -1; } // Slight player tracking var playerDistance = player.x - self.x; var trackingSpeed = Math.min(Math.abs(playerDistance) * 0.005, 0.5); if (playerDistance > 0) { self.x += trackingSpeed; } else if (playerDistance < 0) { self.x -= trackingSpeed; } } else if (self.aiType === 3) { // Formation: Move in coordinated patterns with other aliens var formationSpeed = Math.sin((LK.ticks + self.formationOffset) * 0.05) * 2; self.x += formationSpeed; // Maintain formation spacing for (var a = 0; a < aliens.length; a++) { var otherAlien = aliens[a]; if (otherAlien !== self && otherAlien.aiType === 3) { var distance = Math.abs(otherAlien.x - self.x); if (distance < 120 && distance > 0) { if (otherAlien.x > self.x) { self.x -= 1; } else { self.x += 1; } } } } } // Keep aliens within screen bounds self.x = Math.max(50, Math.min(1998, self.x)); // AI Shooting Behavior self.lastShot++; var shootChance = 1.0; var playerDistance = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2)); // Adjust shooting based on AI type and player proximity if (self.aiType === 0) { // Aggressive aliens shoot more frequently when close to player if (playerDistance < 300) { shootChance = 1.5; self.shootDelay = 40 + Math.random() * 60; } } else if (self.aiType === 1) { // Evasive aliens shoot less frequently but more accurately shootChance = 0.7; self.shootDelay = 80 + Math.random() * 100; } else if (self.aiType === 2) { // Patrol aliens have steady firing rate shootChance = 0.9; } else if (self.aiType === 3) { // Formation aliens coordinate volleys if (LK.ticks % 120 < 20) { shootChance = 2.0; // Synchronized bursts } else { shootChance = 0.3; } } if (self.lastShot >= self.shootDelay * (1 / shootChance) && self.y > 100 && self.y < 2000) { self.lastShot = 0; self.shootDelay = 60 + Math.random() * 120; // Smart targeting for larger aliens if (self.size >= 3) { // Predictive shooting - aim where player will be var bulletSpeed = 20; var timeToReach = Math.abs(self.y - player.y) / bulletSpeed; var predictedPlayerX = player.x; if (dragNode) { // If player is moving, predict movement var playerVelocity = player.x - (player.lastX || player.x) || 0; predictedPlayerX = player.x + playerVelocity * timeToReach; } var bullet = new AlienBullet(); bullet.x = self.x; bullet.y = self.y + 30; // Add slight targeting adjustment var targetOffset = (predictedPlayerX - self.x) * 0.1; bullet.targetOffsetX = Math.max(-2, Math.min(2, targetOffset)); alienBullets.push(bullet); game.addChild(bullet); } else { // Regular shooting for smaller aliens var bullet = new AlienBullet(); bullet.x = self.x; bullet.y = self.y + 30; alienBullets.push(bullet); game.addChild(bullet); } } // Store last position for movement prediction self.lastX = self.x; }; self.takeDamage = function () { self.health--; if (self.health <= 0) { return true; // Destroyed } return false; }; return self; }); var AlienBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('alienBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 20; self.targetOffsetX = 0; // For smart targeting self.homingStrength = 0; // For advanced bullets self.update = function () { self.y += self.speed; // Apply horizontal targeting offset for smart bullets if (self.targetOffsetX !== 0) { self.x += self.targetOffsetX; self.targetOffsetX *= 0.95; // Gradually reduce offset } // Light homing behavior for bullets from larger aliens if (self.homingStrength > 0) { var playerDistance = player.x - self.x; var homingForce = Math.sign(playerDistance) * Math.min(Math.abs(playerDistance) * 0.01, 1) * self.homingStrength; self.x += homingForce; self.homingStrength *= 0.98; // Gradually reduce homing } }; return self; }); var Bomb = Container.expand(function () { var self = Container.call(this); var bombGraphics = self.attachAsset('bomb', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.explosionRadius = 250; // 0.5cm area converted to pixels self.fuseTime = 180; // 3 seconds at 60fps self.currentFuse = 0; self.hasExploded = false; self.update = function () { self.y += self.speed; self.currentFuse++; // Pulsing animation as fuse burns down var pulseScale = 1 + Math.sin(self.currentFuse * 0.3) * 0.2; bombGraphics.scaleX = pulseScale; bombGraphics.scaleY = pulseScale; // Explode after fuse time if (self.currentFuse >= self.fuseTime && !self.hasExploded) { self.explode(); } }; self.explode = function () { self.hasExploded = true; // Flash explosion effect LK.effects.flashScreen(0xffa500, 300); // Destroy all aliens within explosion radius for (var i = aliens.length - 1; i >= 0; i--) { var alien = aliens[i]; var distance = Math.sqrt(Math.pow(alien.x - self.x, 2) + Math.pow(alien.y - self.y, 2)); if (distance <= self.explosionRadius) { LK.setScore(LK.getScore() + alien.size * 5); alien.destroy(); aliens.splice(i, 1); } } // Create explosion visual effect using tween tween(bombGraphics, { scaleX: 5, scaleY: 5, alpha: 0 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { // Remove bomb after explosion animation for (var i = bombs.length - 1; i >= 0; i--) { if (bombs[i] === self) { self.destroy(); bombs.splice(i, 1); break; } } } }); }; return self; }); var MenuButton = Container.expand(function (text, width, height) { var self = Container.call(this); // Create button background self.background = LK.getAsset('button', { width: width || 400, height: height || 100, color: 0x4444ff, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); self.addChild(self.background); // Create button text self.buttonText = new Text2(text || 'Button', { size: 50, fill: 0xffffff }); self.buttonText.anchor.set(0.5, 0.5); self.addChild(self.buttonText); // Button states self.isPressed = false; self.down = function (x, y, obj) { self.isPressed = true; self.background.tint = 0x6666ff; self.scaleX = 0.95; self.scaleY = 0.95; }; self.up = function (x, y, obj) { if (self.isPressed) { self.isPressed = false; self.background.tint = 0xffffff; self.scaleX = 1.0; self.scaleY = 1.0; if (self.onClick) { self.onClick(); } } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.fireRate = 15; self.weaponLevel = 1; self.lastShot = 0; 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 = -18; self.update = function () { self.y += self.speed; }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3; self.bobOffset = Math.random() * Math.PI * 2; self.update = function () { self.y += self.speed; self.x += Math.sin((LK.ticks + self.bobOffset) * 0.1) * 2; powerupGraphics.rotation += 0.05; }; return self; }); var VolumeSlider = Container.expand(function () { var self = Container.call(this); // Slider track self.track = LK.getAsset('sliderTrack', { width: 300, height: 20, color: 0x333333, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); self.addChild(self.track); // Slider handle self.handle = LK.getAsset('sliderHandle', { width: 40, height: 40, color: 0x4444ff, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); self.addChild(self.handle); // Initialize handle position based on stored volume self.value = storage.volume || 1.0; self.handle.x = (self.value - 0.5) * 260; // Map 0-1 to -130 to 130 self.isDragging = false; self.down = function (x, y, obj) { self.isDragging = true; self.updateSlider(x); }; self.move = function (x, y, obj) { if (self.isDragging) { self.updateSlider(x); } }; self.up = function (x, y, obj) { self.isDragging = false; }; self.updateSlider = function (x) { // Convert global x to local slider position var localX = x - self.x; localX = Math.max(-130, Math.min(130, localX)); self.handle.x = localX; self.value = (localX + 130) / 260; // Map -130 to 130 back to 0-1 // Save to storage storage.volume = self.value; // Update actual game volume if applicable if (self.onVolumeChange) { self.onVolumeChange(self.value); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000033 }); /**** * Game Code ****/ // Game state management var gameState = 'menu'; // 'menu', 'playing', 'settings' var mainMenu; var settingsMenu; var gameVolume = storage.volume || 1.0; var player = game.addChild(new Player()); player.x = 2048 / 2; player.y = 2400; player.lastX = player.x; var playerBullets = []; var aliens = []; var alienBullets = []; var powerups = []; var bombs = []; var waveTimer = 0; var difficultyLevel = 1; var alienSpawnRate = 180; var bombTimer = 0; var bombSpawnRate = 600; // 10 seconds at 60fps // Create Main Menu function createMainMenu() { mainMenu = new Container(); // Title var titleText = new Text2('ALIEN FIGHTER', { size: 120, fill: 0xffffff }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 600; mainMenu.addChild(titleText); // Start Game Button var startButton = new MenuButton('START GAME', 400, 100); startButton.x = 2048 / 2; startButton.y = 1200; startButton.onClick = function () { startGame(); }; mainMenu.addChild(startButton); // Settings Button var settingsButton = new MenuButton('SETTINGS', 400, 100); settingsButton.x = 2048 / 2; settingsButton.y = 1400; settingsButton.onClick = function () { showSettings(); }; mainMenu.addChild(settingsButton); game.addChild(mainMenu); } // Create Settings Menu function createSettingsMenu() { settingsMenu = new Container(); settingsMenu.visible = false; // Settings Title var settingsTitle = new Text2('SETTINGS', { size: 100, fill: 0xffffff }); settingsTitle.anchor.set(0.5, 0.5); settingsTitle.x = 2048 / 2; settingsTitle.y = 600; settingsMenu.addChild(settingsTitle); // Volume Label var volumeLabel = new Text2('VOLUME', { size: 60, fill: 0xffffff }); volumeLabel.anchor.set(0.5, 0.5); volumeLabel.x = 2048 / 2; volumeLabel.y = 1000; settingsMenu.addChild(volumeLabel); // Volume Slider var volumeSlider = new VolumeSlider(); volumeSlider.x = 2048 / 2; volumeSlider.y = 1150; volumeSlider.onVolumeChange = function (volume) { gameVolume = volume; // Update volume display volumeValueText.setText(Math.round(volume * 100) + '%'); }; settingsMenu.addChild(volumeSlider); // Volume Value Display var volumeValueText = new Text2(Math.round(gameVolume * 100) + '%', { size: 50, fill: 0x00ff00 }); volumeValueText.anchor.set(0.5, 0.5); volumeValueText.x = 2048 / 2; volumeValueText.y = 1300; settingsMenu.addChild(volumeValueText); // Back Button var backButton = new MenuButton('BACK', 300, 80); backButton.x = 2048 / 2; backButton.y = 1600; backButton.onClick = function () { showMainMenu(); }; settingsMenu.addChild(backButton); game.addChild(settingsMenu); } function startGame() { gameState = 'playing'; mainMenu.visible = false; settingsMenu.visible = false; // Reset game state resetGameState(); } function showSettings() { gameState = 'settings'; mainMenu.visible = false; settingsMenu.visible = true; } function showMainMenu() { gameState = 'menu'; mainMenu.visible = true; settingsMenu.visible = false; } function resetGameState() { // Clear all game objects for (var i = playerBullets.length - 1; i >= 0; i--) { playerBullets[i].destroy(); } playerBullets = []; for (var i = aliens.length - 1; i >= 0; i--) { aliens[i].destroy(); } aliens = []; for (var i = alienBullets.length - 1; i >= 0; i--) { alienBullets[i].destroy(); } alienBullets = []; for (var i = powerups.length - 1; i >= 0; i--) { powerups[i].destroy(); } powerups = []; for (var i = bombs.length - 1; i >= 0; i--) { bombs[i].destroy(); } bombs = []; // Reset player player.x = 2048 / 2; player.y = 2400; player.weaponLevel = 1; player.fireRate = 15; player.lastShot = 0; // Reset game variables playerHealth = 3; // Reset health hearts display for (var h = 0; h < healthHearts.length; h++) { healthHearts[h].visible = h < playerHealth; } waveTimer = 0; difficultyLevel = 1; alienSpawnRate = 180; bombTimer = 0; invulnerabilityTime = 0; LK.setScore(0); } // Initialize menus createMainMenu(); createSettingsMenu(); // Health system var playerHealth = 3; var maxHealth = 3; var invulnerabilityTime = 0; var invulnerabilityDuration = 120; // 2 seconds at 60fps // UI Elements var scoreTxt = new Text2('0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.y = 100; var weaponTxt = new Text2('Weapon Level: 1', { size: 50, fill: 0x00FF00 }); weaponTxt.anchor.set(0, 0); LK.gui.topRight.addChild(weaponTxt); weaponTxt.x = -350; weaponTxt.y = 50; // Health hearts display var healthHearts = []; for (var h = 0; h < maxHealth; h++) { var heart = LK.getAsset('heart', { anchorX: 0.5, anchorY: 0.5 }); heart.x = 150 + h * 60; heart.y = 80; healthHearts.push(heart); LK.gui.topLeft.addChild(heart); } // Player controls var playerControls = { moveLeft: false, moveRight: false, moveUp: false, moveDown: false, speed: 8 }; var controlZones = { left: { x: 0, y: 0, width: 512, height: 2732 }, right: { x: 1536, y: 0, width: 512, height: 2732 }, up: { x: 512, y: 0, width: 1024, height: 1366 }, down: { x: 512, y: 1366, width: 1024, height: 1366 } }; function isInZone(x, y, zone) { return x >= zone.x && x <= zone.x + zone.width && y >= zone.y && y <= zone.y + zone.height; } function handleMove(x, y, obj) { // Reset all controls playerControls.moveLeft = false; playerControls.moveRight = false; playerControls.moveUp = false; playerControls.moveDown = false; // Check which control zone is being touched if (isInZone(x, y, controlZones.left)) { playerControls.moveLeft = true; } if (isInZone(x, y, controlZones.right)) { playerControls.moveRight = true; } if (isInZone(x, y, controlZones.up)) { playerControls.moveUp = true; } if (isInZone(x, y, controlZones.down)) { playerControls.moveDown = true; } } game.move = handleMove; game.down = function (x, y, obj) { handleMove(x, y, obj); }; game.up = function (x, y, obj) { // Reset all controls when touch is released playerControls.moveLeft = false; playerControls.moveRight = false; playerControls.moveUp = false; playerControls.moveDown = false; }; // Spawn alien function function spawnAlien() { var size = 1; var rand = Math.random(); if (difficultyLevel >= 3 && rand < 0.1) size = 5;else if (difficultyLevel >= 2 && rand < 0.2) size = 4;else if (difficultyLevel >= 2 && rand < 0.35) size = 3;else if (rand < 0.5) size = 2; var alien = new Alien(size); alien.x = Math.random() * 1800 + 124; alien.y = -100; alien.baseX = alien.x; // Set initial base position for AI // Set AI type based on difficulty and alien size if (difficultyLevel >= 4) { // Higher difficulty: more aggressive and formation AI if (size >= 4) { alien.aiType = Math.random() < 0.4 ? 0 : 3; // Aggressive or Formation } else { alien.aiType = Math.floor(Math.random() * 4); // All types available } } else if (difficultyLevel >= 2) { // Medium difficulty: introduce evasive and patrol alien.aiType = Math.floor(Math.random() * 3); // No formation yet } else { // Low difficulty: mostly aggressive and patrol alien.aiType = Math.random() < 0.7 ? 0 : 2; // Aggressive or Patrol } // Larger aliens get enhanced capabilities if (size >= 3) { alien.aggressionLevel = Math.min(1.0, alien.aggressionLevel + 0.3); } aliens.push(alien); game.addChild(alien); } // Player shooting function playerShoot() { if (LK.ticks - player.lastShot >= player.fireRate) { player.lastShot = LK.ticks; // Gun positions on left and right sides of fighter plane var leftGunX = player.x - 80; var rightGunX = player.x + 80; var gunY = player.y - 60; if (player.weaponLevel === 1) { // Basic dual gun setup - left and right guns fire simultaneously var bullet1 = new PlayerBullet(); bullet1.x = leftGunX; bullet1.y = gunY; playerBullets.push(bullet1); game.addChild(bullet1); var bullet2 = new PlayerBullet(); bullet2.x = rightGunX; bullet2.y = gunY; playerBullets.push(bullet2); game.addChild(bullet2); } else if (player.weaponLevel === 2) { // Enhanced dual shot - two bullets from each gun var bullet1 = new PlayerBullet(); bullet1.x = leftGunX - 10; bullet1.y = gunY; playerBullets.push(bullet1); game.addChild(bullet1); var bullet2 = new PlayerBullet(); bullet2.x = leftGunX + 10; bullet2.y = gunY; playerBullets.push(bullet2); game.addChild(bullet2); var bullet3 = new PlayerBullet(); bullet3.x = rightGunX - 10; bullet3.y = gunY; playerBullets.push(bullet3); game.addChild(bullet3); var bullet4 = new PlayerBullet(); bullet4.x = rightGunX + 10; bullet4.y = gunY; playerBullets.push(bullet4); game.addChild(bullet4); } else if (player.weaponLevel >= 3) { // Triple shot from each gun plus center var bullet1 = new PlayerBullet(); bullet1.x = leftGunX - 15; bullet1.y = gunY; playerBullets.push(bullet1); game.addChild(bullet1); var bullet2 = new PlayerBullet(); bullet2.x = leftGunX; bullet2.y = gunY; playerBullets.push(bullet2); game.addChild(bullet2); var bullet3 = new PlayerBullet(); bullet3.x = leftGunX + 15; bullet3.y = gunY; playerBullets.push(bullet3); game.addChild(bullet3); var bullet4 = new PlayerBullet(); bullet4.x = rightGunX - 15; bullet4.y = gunY; playerBullets.push(bullet4); game.addChild(bullet4); var bullet5 = new PlayerBullet(); bullet5.x = rightGunX; bullet5.y = gunY; playerBullets.push(bullet5); game.addChild(bullet5); var bullet6 = new PlayerBullet(); bullet6.x = rightGunX + 15; bullet6.y = gunY; playerBullets.push(bullet6); game.addChild(bullet6); } var shootSound = LK.getSound('shoot'); shootSound.volume = gameVolume; shootSound.play(); } } game.update = function () { // Only update game logic when playing if (gameState !== 'playing') { return; } scoreTxt.setText(LK.getScore()); weaponTxt.setText('Weapon Level: ' + player.weaponLevel); // Update heart visibility based on current health for (var h = 0; h < healthHearts.length; h++) { healthHearts[h].visible = h < playerHealth; } // Handle invulnerability timer if (invulnerabilityTime > 0) { invulnerabilityTime--; // Make player flash during invulnerability if (Math.floor(invulnerabilityTime / 10) % 2 === 0) { player.alpha = 0.5; } else { player.alpha = 1.0; } } else { player.alpha = 1.0; } // Handle player movement based on controls player.lastX = player.x; if (playerControls.moveLeft) { player.x -= playerControls.speed; } if (playerControls.moveRight) { player.x += playerControls.speed; } if (playerControls.moveUp) { player.y -= playerControls.speed; } if (playerControls.moveDown) { player.y += playerControls.speed; } // Keep player within bounds player.x = Math.max(50, Math.min(1998, player.x)); player.y = Math.max(100, Math.min(2600, player.y)); // Player auto-shooting playerShoot(); // Wave management waveTimer++; if (waveTimer >= alienSpawnRate) { waveTimer = 0; spawnAlien(); // Increase difficulty over time if (LK.getScore() > difficultyLevel * 100) { difficultyLevel++; alienSpawnRate = Math.max(60, alienSpawnRate - 10); } } // Bomb spawning every 10 seconds bombTimer++; if (bombTimer >= bombSpawnRate) { bombTimer = 0; var bomb = new Bomb(); bomb.x = Math.random() * 1800 + 124; bomb.y = -100; bombs.push(bomb); game.addChild(bomb); } // Update and cleanup bombs for (var i = bombs.length - 1; i >= 0; i--) { var bomb = bombs[i]; if (bomb.y > 2800 && !bomb.hasExploded) { bomb.destroy(); bombs.splice(i, 1); continue; } } // Update and cleanup player bullets for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; if (bullet.y < -50) { bullet.destroy(); playerBullets.splice(i, 1); continue; } // Check collision with aliens for (var j = aliens.length - 1; j >= 0; j--) { var alien = aliens[j]; if (bullet.intersects(alien)) { if (alien.takeDamage()) { // Alien destroyed LK.setScore(LK.getScore() + alien.size * 5); // Drop powerup from size 5 aliens if (alien.size === 5 && Math.random() < 0.7) { var powerup = new PowerUp(); powerup.x = alien.x; powerup.y = alien.y; powerups.push(powerup); game.addChild(powerup); } var enemyHitSound = LK.getSound('enemyHit'); enemyHitSound.volume = gameVolume; enemyHitSound.play(); alien.destroy(); aliens.splice(j, 1); } bullet.destroy(); playerBullets.splice(i, 1); break; } } } // Update and cleanup aliens for (var i = aliens.length - 1; i >= 0; i--) { var alien = aliens[i]; if (alien.y > 2800) { alien.destroy(); aliens.splice(i, 1); continue; } // Check collision with player if (alien.intersects(player) && invulnerabilityTime <= 0) { playerHealth--; invulnerabilityTime = invulnerabilityDuration; LK.effects.flashScreen(0xff0000, 500); LK.effects.flashObject(player, 0xff0000, 500); if (playerHealth <= 0) { LK.showGameOver(); // Return to main menu after game over LK.setTimeout(function () { showMainMenu(); }, 3000); return; } } } // Update and cleanup alien bullets for (var i = alienBullets.length - 1; i >= 0; i--) { var bullet = alienBullets[i]; if (bullet.y > 2800) { bullet.destroy(); alienBullets.splice(i, 1); continue; } // Check collision with player if (bullet.intersects(player) && invulnerabilityTime <= 0) { playerHealth--; invulnerabilityTime = invulnerabilityDuration; LK.effects.flashScreen(0xff0000, 500); LK.effects.flashObject(player, 0xff0000, 500); bullet.destroy(); alienBullets.splice(i, 1); if (playerHealth <= 0) { LK.showGameOver(); // Return to main menu after game over LK.setTimeout(function () { showMainMenu(); }, 3000); return; } } } // Update and cleanup powerups for (var i = powerups.length - 1; i >= 0; i--) { var powerup = powerups[i]; if (powerup.y > 2800) { powerup.destroy(); powerups.splice(i, 1); continue; } // Check collision with player if (powerup.intersects(player)) { player.weaponLevel = Math.min(3, player.weaponLevel + 1); player.fireRate = Math.max(8, player.fireRate - 3); var powerupSound = LK.getSound('powerupCollect'); powerupSound.volume = gameVolume; powerupSound.play(); LK.effects.flashObject(player, 0x00ffff, 500); powerup.destroy(); powerups.splice(i, 1); } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
volume: 1
});
/****
* Classes
****/
var Alien = Container.expand(function (size) {
var self = Container.call(this);
self.size = size || 1;
self.health = size;
self.maxHealth = size;
var assetName = 'alien' + size;
var alienGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = Math.random() * 3 + 2;
self.lastShot = 0;
self.shootDelay = 60 + Math.random() * 120;
// AI behavior properties
self.aiType = Math.floor(Math.random() * 4); // 0: aggressive, 1: evasive, 2: patrol, 3: formation
self.baseX = self.x;
self.patrolDirection = Math.random() < 0.5 ? -1 : 1;
self.evasionTimer = 0;
self.formationOffset = Math.random() * Math.PI * 2;
self.aggressionLevel = Math.random() * 0.5 + 0.5; // 0.5 to 1.0
self.update = function () {
self.y += self.speed;
// AI Movement Behaviors
if (self.aiType === 0) {
// Aggressive: Move directly toward player with increasing speed
var playerDistance = player.x - self.x;
var horizontalSpeed = Math.min(Math.abs(playerDistance) * 0.02 * self.aggressionLevel, 2.5);
if (playerDistance > 0) {
self.x += horizontalSpeed;
} else if (playerDistance < 0) {
self.x -= horizontalSpeed;
}
// Increase speed when close to player
if (Math.abs(playerDistance) < 200) {
self.speed += 0.1;
}
} else if (self.aiType === 1) {
// Evasive: Move away from player bullets and use unpredictable movement
self.evasionTimer++;
var nearbyBullet = false;
for (var b = 0; b < playerBullets.length; b++) {
var bullet = playerBullets[b];
var bulletDistance = Math.sqrt(Math.pow(bullet.x - self.x, 2) + Math.pow(bullet.y - self.y, 2));
if (bulletDistance < 150) {
nearbyBullet = true;
// Evade away from bullet
if (bullet.x < self.x) {
self.x += 3;
} else {
self.x -= 3;
}
break;
}
}
// Random evasive movement when no immediate threat
if (!nearbyBullet && self.evasionTimer % 60 === 0) {
self.x += (Math.random() - 0.5) * 100;
}
} else if (self.aiType === 2) {
// Patrol: Move in horizontal patterns while slowly tracking player
var patrolSpeed = 1.5;
self.x += self.patrolDirection * patrolSpeed;
if (self.x < 200 || self.x > 1848) {
self.patrolDirection *= -1;
}
// Slight player tracking
var playerDistance = player.x - self.x;
var trackingSpeed = Math.min(Math.abs(playerDistance) * 0.005, 0.5);
if (playerDistance > 0) {
self.x += trackingSpeed;
} else if (playerDistance < 0) {
self.x -= trackingSpeed;
}
} else if (self.aiType === 3) {
// Formation: Move in coordinated patterns with other aliens
var formationSpeed = Math.sin((LK.ticks + self.formationOffset) * 0.05) * 2;
self.x += formationSpeed;
// Maintain formation spacing
for (var a = 0; a < aliens.length; a++) {
var otherAlien = aliens[a];
if (otherAlien !== self && otherAlien.aiType === 3) {
var distance = Math.abs(otherAlien.x - self.x);
if (distance < 120 && distance > 0) {
if (otherAlien.x > self.x) {
self.x -= 1;
} else {
self.x += 1;
}
}
}
}
}
// Keep aliens within screen bounds
self.x = Math.max(50, Math.min(1998, self.x));
// AI Shooting Behavior
self.lastShot++;
var shootChance = 1.0;
var playerDistance = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
// Adjust shooting based on AI type and player proximity
if (self.aiType === 0) {
// Aggressive aliens shoot more frequently when close to player
if (playerDistance < 300) {
shootChance = 1.5;
self.shootDelay = 40 + Math.random() * 60;
}
} else if (self.aiType === 1) {
// Evasive aliens shoot less frequently but more accurately
shootChance = 0.7;
self.shootDelay = 80 + Math.random() * 100;
} else if (self.aiType === 2) {
// Patrol aliens have steady firing rate
shootChance = 0.9;
} else if (self.aiType === 3) {
// Formation aliens coordinate volleys
if (LK.ticks % 120 < 20) {
shootChance = 2.0; // Synchronized bursts
} else {
shootChance = 0.3;
}
}
if (self.lastShot >= self.shootDelay * (1 / shootChance) && self.y > 100 && self.y < 2000) {
self.lastShot = 0;
self.shootDelay = 60 + Math.random() * 120;
// Smart targeting for larger aliens
if (self.size >= 3) {
// Predictive shooting - aim where player will be
var bulletSpeed = 20;
var timeToReach = Math.abs(self.y - player.y) / bulletSpeed;
var predictedPlayerX = player.x;
if (dragNode) {
// If player is moving, predict movement
var playerVelocity = player.x - (player.lastX || player.x) || 0;
predictedPlayerX = player.x + playerVelocity * timeToReach;
}
var bullet = new AlienBullet();
bullet.x = self.x;
bullet.y = self.y + 30;
// Add slight targeting adjustment
var targetOffset = (predictedPlayerX - self.x) * 0.1;
bullet.targetOffsetX = Math.max(-2, Math.min(2, targetOffset));
alienBullets.push(bullet);
game.addChild(bullet);
} else {
// Regular shooting for smaller aliens
var bullet = new AlienBullet();
bullet.x = self.x;
bullet.y = self.y + 30;
alienBullets.push(bullet);
game.addChild(bullet);
}
}
// Store last position for movement prediction
self.lastX = self.x;
};
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
return true; // Destroyed
}
return false;
};
return self;
});
var AlienBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('alienBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 20;
self.targetOffsetX = 0; // For smart targeting
self.homingStrength = 0; // For advanced bullets
self.update = function () {
self.y += self.speed;
// Apply horizontal targeting offset for smart bullets
if (self.targetOffsetX !== 0) {
self.x += self.targetOffsetX;
self.targetOffsetX *= 0.95; // Gradually reduce offset
}
// Light homing behavior for bullets from larger aliens
if (self.homingStrength > 0) {
var playerDistance = player.x - self.x;
var homingForce = Math.sign(playerDistance) * Math.min(Math.abs(playerDistance) * 0.01, 1) * self.homingStrength;
self.x += homingForce;
self.homingStrength *= 0.98; // Gradually reduce homing
}
};
return self;
});
var Bomb = Container.expand(function () {
var self = Container.call(this);
var bombGraphics = self.attachAsset('bomb', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.explosionRadius = 250; // 0.5cm area converted to pixels
self.fuseTime = 180; // 3 seconds at 60fps
self.currentFuse = 0;
self.hasExploded = false;
self.update = function () {
self.y += self.speed;
self.currentFuse++;
// Pulsing animation as fuse burns down
var pulseScale = 1 + Math.sin(self.currentFuse * 0.3) * 0.2;
bombGraphics.scaleX = pulseScale;
bombGraphics.scaleY = pulseScale;
// Explode after fuse time
if (self.currentFuse >= self.fuseTime && !self.hasExploded) {
self.explode();
}
};
self.explode = function () {
self.hasExploded = true;
// Flash explosion effect
LK.effects.flashScreen(0xffa500, 300);
// Destroy all aliens within explosion radius
for (var i = aliens.length - 1; i >= 0; i--) {
var alien = aliens[i];
var distance = Math.sqrt(Math.pow(alien.x - self.x, 2) + Math.pow(alien.y - self.y, 2));
if (distance <= self.explosionRadius) {
LK.setScore(LK.getScore() + alien.size * 5);
alien.destroy();
aliens.splice(i, 1);
}
}
// Create explosion visual effect using tween
tween(bombGraphics, {
scaleX: 5,
scaleY: 5,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Remove bomb after explosion animation
for (var i = bombs.length - 1; i >= 0; i--) {
if (bombs[i] === self) {
self.destroy();
bombs.splice(i, 1);
break;
}
}
}
});
};
return self;
});
var MenuButton = Container.expand(function (text, width, height) {
var self = Container.call(this);
// Create button background
self.background = LK.getAsset('button', {
width: width || 400,
height: height || 100,
color: 0x4444ff,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
self.addChild(self.background);
// Create button text
self.buttonText = new Text2(text || 'Button', {
size: 50,
fill: 0xffffff
});
self.buttonText.anchor.set(0.5, 0.5);
self.addChild(self.buttonText);
// Button states
self.isPressed = false;
self.down = function (x, y, obj) {
self.isPressed = true;
self.background.tint = 0x6666ff;
self.scaleX = 0.95;
self.scaleY = 0.95;
};
self.up = function (x, y, obj) {
if (self.isPressed) {
self.isPressed = false;
self.background.tint = 0xffffff;
self.scaleX = 1.0;
self.scaleY = 1.0;
if (self.onClick) {
self.onClick();
}
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.fireRate = 15;
self.weaponLevel = 1;
self.lastShot = 0;
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 = -18;
self.update = function () {
self.y += self.speed;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.bobOffset = Math.random() * Math.PI * 2;
self.update = function () {
self.y += self.speed;
self.x += Math.sin((LK.ticks + self.bobOffset) * 0.1) * 2;
powerupGraphics.rotation += 0.05;
};
return self;
});
var VolumeSlider = Container.expand(function () {
var self = Container.call(this);
// Slider track
self.track = LK.getAsset('sliderTrack', {
width: 300,
height: 20,
color: 0x333333,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
self.addChild(self.track);
// Slider handle
self.handle = LK.getAsset('sliderHandle', {
width: 40,
height: 40,
color: 0x4444ff,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
self.addChild(self.handle);
// Initialize handle position based on stored volume
self.value = storage.volume || 1.0;
self.handle.x = (self.value - 0.5) * 260; // Map 0-1 to -130 to 130
self.isDragging = false;
self.down = function (x, y, obj) {
self.isDragging = true;
self.updateSlider(x);
};
self.move = function (x, y, obj) {
if (self.isDragging) {
self.updateSlider(x);
}
};
self.up = function (x, y, obj) {
self.isDragging = false;
};
self.updateSlider = function (x) {
// Convert global x to local slider position
var localX = x - self.x;
localX = Math.max(-130, Math.min(130, localX));
self.handle.x = localX;
self.value = (localX + 130) / 260; // Map -130 to 130 back to 0-1
// Save to storage
storage.volume = self.value;
// Update actual game volume if applicable
if (self.onVolumeChange) {
self.onVolumeChange(self.value);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000033
});
/****
* Game Code
****/
// Game state management
var gameState = 'menu'; // 'menu', 'playing', 'settings'
var mainMenu;
var settingsMenu;
var gameVolume = storage.volume || 1.0;
var player = game.addChild(new Player());
player.x = 2048 / 2;
player.y = 2400;
player.lastX = player.x;
var playerBullets = [];
var aliens = [];
var alienBullets = [];
var powerups = [];
var bombs = [];
var waveTimer = 0;
var difficultyLevel = 1;
var alienSpawnRate = 180;
var bombTimer = 0;
var bombSpawnRate = 600; // 10 seconds at 60fps
// Create Main Menu
function createMainMenu() {
mainMenu = new Container();
// Title
var titleText = new Text2('ALIEN FIGHTER', {
size: 120,
fill: 0xffffff
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 600;
mainMenu.addChild(titleText);
// Start Game Button
var startButton = new MenuButton('START GAME', 400, 100);
startButton.x = 2048 / 2;
startButton.y = 1200;
startButton.onClick = function () {
startGame();
};
mainMenu.addChild(startButton);
// Settings Button
var settingsButton = new MenuButton('SETTINGS', 400, 100);
settingsButton.x = 2048 / 2;
settingsButton.y = 1400;
settingsButton.onClick = function () {
showSettings();
};
mainMenu.addChild(settingsButton);
game.addChild(mainMenu);
}
// Create Settings Menu
function createSettingsMenu() {
settingsMenu = new Container();
settingsMenu.visible = false;
// Settings Title
var settingsTitle = new Text2('SETTINGS', {
size: 100,
fill: 0xffffff
});
settingsTitle.anchor.set(0.5, 0.5);
settingsTitle.x = 2048 / 2;
settingsTitle.y = 600;
settingsMenu.addChild(settingsTitle);
// Volume Label
var volumeLabel = new Text2('VOLUME', {
size: 60,
fill: 0xffffff
});
volumeLabel.anchor.set(0.5, 0.5);
volumeLabel.x = 2048 / 2;
volumeLabel.y = 1000;
settingsMenu.addChild(volumeLabel);
// Volume Slider
var volumeSlider = new VolumeSlider();
volumeSlider.x = 2048 / 2;
volumeSlider.y = 1150;
volumeSlider.onVolumeChange = function (volume) {
gameVolume = volume;
// Update volume display
volumeValueText.setText(Math.round(volume * 100) + '%');
};
settingsMenu.addChild(volumeSlider);
// Volume Value Display
var volumeValueText = new Text2(Math.round(gameVolume * 100) + '%', {
size: 50,
fill: 0x00ff00
});
volumeValueText.anchor.set(0.5, 0.5);
volumeValueText.x = 2048 / 2;
volumeValueText.y = 1300;
settingsMenu.addChild(volumeValueText);
// Back Button
var backButton = new MenuButton('BACK', 300, 80);
backButton.x = 2048 / 2;
backButton.y = 1600;
backButton.onClick = function () {
showMainMenu();
};
settingsMenu.addChild(backButton);
game.addChild(settingsMenu);
}
function startGame() {
gameState = 'playing';
mainMenu.visible = false;
settingsMenu.visible = false;
// Reset game state
resetGameState();
}
function showSettings() {
gameState = 'settings';
mainMenu.visible = false;
settingsMenu.visible = true;
}
function showMainMenu() {
gameState = 'menu';
mainMenu.visible = true;
settingsMenu.visible = false;
}
function resetGameState() {
// Clear all game objects
for (var i = playerBullets.length - 1; i >= 0; i--) {
playerBullets[i].destroy();
}
playerBullets = [];
for (var i = aliens.length - 1; i >= 0; i--) {
aliens[i].destroy();
}
aliens = [];
for (var i = alienBullets.length - 1; i >= 0; i--) {
alienBullets[i].destroy();
}
alienBullets = [];
for (var i = powerups.length - 1; i >= 0; i--) {
powerups[i].destroy();
}
powerups = [];
for (var i = bombs.length - 1; i >= 0; i--) {
bombs[i].destroy();
}
bombs = [];
// Reset player
player.x = 2048 / 2;
player.y = 2400;
player.weaponLevel = 1;
player.fireRate = 15;
player.lastShot = 0;
// Reset game variables
playerHealth = 3;
// Reset health hearts display
for (var h = 0; h < healthHearts.length; h++) {
healthHearts[h].visible = h < playerHealth;
}
waveTimer = 0;
difficultyLevel = 1;
alienSpawnRate = 180;
bombTimer = 0;
invulnerabilityTime = 0;
LK.setScore(0);
}
// Initialize menus
createMainMenu();
createSettingsMenu();
// Health system
var playerHealth = 3;
var maxHealth = 3;
var invulnerabilityTime = 0;
var invulnerabilityDuration = 120; // 2 seconds at 60fps
// UI Elements
var scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 100;
var weaponTxt = new Text2('Weapon Level: 1', {
size: 50,
fill: 0x00FF00
});
weaponTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(weaponTxt);
weaponTxt.x = -350;
weaponTxt.y = 50;
// Health hearts display
var healthHearts = [];
for (var h = 0; h < maxHealth; h++) {
var heart = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
heart.x = 150 + h * 60;
heart.y = 80;
healthHearts.push(heart);
LK.gui.topLeft.addChild(heart);
}
// Player controls
var playerControls = {
moveLeft: false,
moveRight: false,
moveUp: false,
moveDown: false,
speed: 8
};
var controlZones = {
left: {
x: 0,
y: 0,
width: 512,
height: 2732
},
right: {
x: 1536,
y: 0,
width: 512,
height: 2732
},
up: {
x: 512,
y: 0,
width: 1024,
height: 1366
},
down: {
x: 512,
y: 1366,
width: 1024,
height: 1366
}
};
function isInZone(x, y, zone) {
return x >= zone.x && x <= zone.x + zone.width && y >= zone.y && y <= zone.y + zone.height;
}
function handleMove(x, y, obj) {
// Reset all controls
playerControls.moveLeft = false;
playerControls.moveRight = false;
playerControls.moveUp = false;
playerControls.moveDown = false;
// Check which control zone is being touched
if (isInZone(x, y, controlZones.left)) {
playerControls.moveLeft = true;
}
if (isInZone(x, y, controlZones.right)) {
playerControls.moveRight = true;
}
if (isInZone(x, y, controlZones.up)) {
playerControls.moveUp = true;
}
if (isInZone(x, y, controlZones.down)) {
playerControls.moveDown = true;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
// Reset all controls when touch is released
playerControls.moveLeft = false;
playerControls.moveRight = false;
playerControls.moveUp = false;
playerControls.moveDown = false;
};
// Spawn alien function
function spawnAlien() {
var size = 1;
var rand = Math.random();
if (difficultyLevel >= 3 && rand < 0.1) size = 5;else if (difficultyLevel >= 2 && rand < 0.2) size = 4;else if (difficultyLevel >= 2 && rand < 0.35) size = 3;else if (rand < 0.5) size = 2;
var alien = new Alien(size);
alien.x = Math.random() * 1800 + 124;
alien.y = -100;
alien.baseX = alien.x; // Set initial base position for AI
// Set AI type based on difficulty and alien size
if (difficultyLevel >= 4) {
// Higher difficulty: more aggressive and formation AI
if (size >= 4) {
alien.aiType = Math.random() < 0.4 ? 0 : 3; // Aggressive or Formation
} else {
alien.aiType = Math.floor(Math.random() * 4); // All types available
}
} else if (difficultyLevel >= 2) {
// Medium difficulty: introduce evasive and patrol
alien.aiType = Math.floor(Math.random() * 3); // No formation yet
} else {
// Low difficulty: mostly aggressive and patrol
alien.aiType = Math.random() < 0.7 ? 0 : 2; // Aggressive or Patrol
}
// Larger aliens get enhanced capabilities
if (size >= 3) {
alien.aggressionLevel = Math.min(1.0, alien.aggressionLevel + 0.3);
}
aliens.push(alien);
game.addChild(alien);
}
// Player shooting
function playerShoot() {
if (LK.ticks - player.lastShot >= player.fireRate) {
player.lastShot = LK.ticks;
// Gun positions on left and right sides of fighter plane
var leftGunX = player.x - 80;
var rightGunX = player.x + 80;
var gunY = player.y - 60;
if (player.weaponLevel === 1) {
// Basic dual gun setup - left and right guns fire simultaneously
var bullet1 = new PlayerBullet();
bullet1.x = leftGunX;
bullet1.y = gunY;
playerBullets.push(bullet1);
game.addChild(bullet1);
var bullet2 = new PlayerBullet();
bullet2.x = rightGunX;
bullet2.y = gunY;
playerBullets.push(bullet2);
game.addChild(bullet2);
} else if (player.weaponLevel === 2) {
// Enhanced dual shot - two bullets from each gun
var bullet1 = new PlayerBullet();
bullet1.x = leftGunX - 10;
bullet1.y = gunY;
playerBullets.push(bullet1);
game.addChild(bullet1);
var bullet2 = new PlayerBullet();
bullet2.x = leftGunX + 10;
bullet2.y = gunY;
playerBullets.push(bullet2);
game.addChild(bullet2);
var bullet3 = new PlayerBullet();
bullet3.x = rightGunX - 10;
bullet3.y = gunY;
playerBullets.push(bullet3);
game.addChild(bullet3);
var bullet4 = new PlayerBullet();
bullet4.x = rightGunX + 10;
bullet4.y = gunY;
playerBullets.push(bullet4);
game.addChild(bullet4);
} else if (player.weaponLevel >= 3) {
// Triple shot from each gun plus center
var bullet1 = new PlayerBullet();
bullet1.x = leftGunX - 15;
bullet1.y = gunY;
playerBullets.push(bullet1);
game.addChild(bullet1);
var bullet2 = new PlayerBullet();
bullet2.x = leftGunX;
bullet2.y = gunY;
playerBullets.push(bullet2);
game.addChild(bullet2);
var bullet3 = new PlayerBullet();
bullet3.x = leftGunX + 15;
bullet3.y = gunY;
playerBullets.push(bullet3);
game.addChild(bullet3);
var bullet4 = new PlayerBullet();
bullet4.x = rightGunX - 15;
bullet4.y = gunY;
playerBullets.push(bullet4);
game.addChild(bullet4);
var bullet5 = new PlayerBullet();
bullet5.x = rightGunX;
bullet5.y = gunY;
playerBullets.push(bullet5);
game.addChild(bullet5);
var bullet6 = new PlayerBullet();
bullet6.x = rightGunX + 15;
bullet6.y = gunY;
playerBullets.push(bullet6);
game.addChild(bullet6);
}
var shootSound = LK.getSound('shoot');
shootSound.volume = gameVolume;
shootSound.play();
}
}
game.update = function () {
// Only update game logic when playing
if (gameState !== 'playing') {
return;
}
scoreTxt.setText(LK.getScore());
weaponTxt.setText('Weapon Level: ' + player.weaponLevel);
// Update heart visibility based on current health
for (var h = 0; h < healthHearts.length; h++) {
healthHearts[h].visible = h < playerHealth;
}
// Handle invulnerability timer
if (invulnerabilityTime > 0) {
invulnerabilityTime--;
// Make player flash during invulnerability
if (Math.floor(invulnerabilityTime / 10) % 2 === 0) {
player.alpha = 0.5;
} else {
player.alpha = 1.0;
}
} else {
player.alpha = 1.0;
}
// Handle player movement based on controls
player.lastX = player.x;
if (playerControls.moveLeft) {
player.x -= playerControls.speed;
}
if (playerControls.moveRight) {
player.x += playerControls.speed;
}
if (playerControls.moveUp) {
player.y -= playerControls.speed;
}
if (playerControls.moveDown) {
player.y += playerControls.speed;
}
// Keep player within bounds
player.x = Math.max(50, Math.min(1998, player.x));
player.y = Math.max(100, Math.min(2600, player.y));
// Player auto-shooting
playerShoot();
// Wave management
waveTimer++;
if (waveTimer >= alienSpawnRate) {
waveTimer = 0;
spawnAlien();
// Increase difficulty over time
if (LK.getScore() > difficultyLevel * 100) {
difficultyLevel++;
alienSpawnRate = Math.max(60, alienSpawnRate - 10);
}
}
// Bomb spawning every 10 seconds
bombTimer++;
if (bombTimer >= bombSpawnRate) {
bombTimer = 0;
var bomb = new Bomb();
bomb.x = Math.random() * 1800 + 124;
bomb.y = -100;
bombs.push(bomb);
game.addChild(bomb);
}
// Update and cleanup bombs
for (var i = bombs.length - 1; i >= 0; i--) {
var bomb = bombs[i];
if (bomb.y > 2800 && !bomb.hasExploded) {
bomb.destroy();
bombs.splice(i, 1);
continue;
}
}
// Update and cleanup player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.y < -50) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check collision with aliens
for (var j = aliens.length - 1; j >= 0; j--) {
var alien = aliens[j];
if (bullet.intersects(alien)) {
if (alien.takeDamage()) {
// Alien destroyed
LK.setScore(LK.getScore() + alien.size * 5);
// Drop powerup from size 5 aliens
if (alien.size === 5 && Math.random() < 0.7) {
var powerup = new PowerUp();
powerup.x = alien.x;
powerup.y = alien.y;
powerups.push(powerup);
game.addChild(powerup);
}
var enemyHitSound = LK.getSound('enemyHit');
enemyHitSound.volume = gameVolume;
enemyHitSound.play();
alien.destroy();
aliens.splice(j, 1);
}
bullet.destroy();
playerBullets.splice(i, 1);
break;
}
}
}
// Update and cleanup aliens
for (var i = aliens.length - 1; i >= 0; i--) {
var alien = aliens[i];
if (alien.y > 2800) {
alien.destroy();
aliens.splice(i, 1);
continue;
}
// Check collision with player
if (alien.intersects(player) && invulnerabilityTime <= 0) {
playerHealth--;
invulnerabilityTime = invulnerabilityDuration;
LK.effects.flashScreen(0xff0000, 500);
LK.effects.flashObject(player, 0xff0000, 500);
if (playerHealth <= 0) {
LK.showGameOver();
// Return to main menu after game over
LK.setTimeout(function () {
showMainMenu();
}, 3000);
return;
}
}
}
// Update and cleanup alien bullets
for (var i = alienBullets.length - 1; i >= 0; i--) {
var bullet = alienBullets[i];
if (bullet.y > 2800) {
bullet.destroy();
alienBullets.splice(i, 1);
continue;
}
// Check collision with player
if (bullet.intersects(player) && invulnerabilityTime <= 0) {
playerHealth--;
invulnerabilityTime = invulnerabilityDuration;
LK.effects.flashScreen(0xff0000, 500);
LK.effects.flashObject(player, 0xff0000, 500);
bullet.destroy();
alienBullets.splice(i, 1);
if (playerHealth <= 0) {
LK.showGameOver();
// Return to main menu after game over
LK.setTimeout(function () {
showMainMenu();
}, 3000);
return;
}
}
}
// Update and cleanup powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
if (powerup.y > 2800) {
powerup.destroy();
powerups.splice(i, 1);
continue;
}
// Check collision with player
if (powerup.intersects(player)) {
player.weaponLevel = Math.min(3, player.weaponLevel + 1);
player.fireRate = Math.max(8, player.fireRate - 3);
var powerupSound = LK.getSound('powerupCollect');
powerupSound.volume = gameVolume;
powerupSound.play();
LK.effects.flashObject(player, 0x00ffff, 500);
powerup.destroy();
powerups.splice(i, 1);
}
}
};