/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Asteroid = Container.expand(function () { var self = Container.call(this); var asteroid = self.attachAsset('asteroid', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -5; self.rotationSpeed = (Math.random() - 0.5) * 0.05; self.size = 'medium'; self.health = 2; self.setSize = function (size) { self.size = size; switch (size) { case 'small': asteroid.scaleX = 0.7; asteroid.scaleY = 0.7; self.health = 1; self.speed = -6; break; case 'medium': // Default size break; case 'large': asteroid.scaleX = 1.5; asteroid.scaleY = 1.5; self.health = 3; self.speed = -3; break; } }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0x555555, 200); return self.health <= 0; }; self.update = function () { self.x += self.speed; self.rotation += self.rotationSpeed; // Remove if out of bounds if (self.x < -100) { self.shouldRemove = true; } }; return self; }); var Boss = Container.expand(function () { var self = Container.call(this); var bossGraphic = self.attachAsset('boss', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -1; self.health = 50; self.maxHealth = 50; self.phase = 1; self.attackTimer = 0; self.attackCooldown = 60; self.movePattern = 'entrance'; self.targetY = 0; self.points = 2000; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xff0000, 100); // Change phase at 50% health if (self.health <= self.maxHealth / 2 && self.phase === 1) { self.phase = 2; self.attackCooldown = 40; bossGraphic.tint = 0xe74c3c; // Red tint for phase 2 } return self.health <= 0; }; self.update = function () { if (self.movePattern === 'entrance') { self.x += self.speed; if (self.x <= 1700) { self.movePattern = 'vertical'; self.targetY = Math.random() * 1500 + 500; } } else if (self.movePattern === 'vertical') { // Move toward target Y position if (Math.abs(self.y - self.targetY) > 5) { self.y += self.targetY > self.y ? 4 : -4; } else { // Pick a new target self.targetY = Math.random() * 1500 + 500; } } // Boss attack timer self.attackTimer++; if (self.attackTimer >= self.attackCooldown) { self.attackTimer = 0; self.readyToAttack = true; // Automatic attack if player exists if (player && !self.shouldRemove) { // Get current player position for more accurate targeting var targetX = player.x; var targetY = player.y; // Calculate predicted player position based on current movement (better targeting) var angleToPlayer = Math.atan2(targetY - self.y, targetX - self.x); // Phase 1: Spread shot in multiple directions if (self.phase === 1) { // Create a circular pattern of bullets var bulletCount = 8; for (var i = 0; i < bulletCount; i++) { var bullet = new EnemyBullet(); bullet.x = self.x - 50; bullet.y = self.y; var angle = i / bulletCount * Math.PI * 2; bullet.setAngle(angle); enemyBullets.push(bullet); game.addChild(bullet); } // Also fire a cluster toward player for (var i = -1; i <= 1; i++) { var bulletPlayer = new EnemyBullet(); bulletPlayer.x = self.x - 50; bulletPlayer.y = self.y; bulletPlayer.setAngle(angleToPlayer + i * 0.15); enemyBullets.push(bulletPlayer); game.addChild(bulletPlayer); } } else { // Phase 2: Multi-directional attack with homing bullets // Create X pattern var directions = [angleToPlayer, angleToPlayer + Math.PI / 4, angleToPlayer + Math.PI / 2, angleToPlayer + Math.PI * 3 / 4, angleToPlayer + Math.PI, angleToPlayer - Math.PI / 4, angleToPlayer - Math.PI / 2, angleToPlayer - Math.PI * 3 / 4]; for (var i = 0; i < directions.length; i++) { var bullet = new EnemyBullet(); bullet.x = self.x - 50; bullet.y = self.y; bullet.setAngle(directions[i]); // Make every third bullet homing if (i % 3 === 0) { bullet.homing = true; } enemyBullets.push(bullet); game.addChild(bullet); } // Schedule more precise shots with updated targeting LK.setTimeout(function () { if (!self.shouldRemove && self.health > 0 && player) { // Fire 3 homing bullets directly at player for better accuracy for (var i = -1; i <= 1; i++) { var bullet = new EnemyBullet(); bullet.x = self.x - 50; bullet.y = self.y; // Get fresh angle for better accuracy in delayed shots var newAngle = Math.atan2(player.y - self.y, player.x - self.x); bullet.setAngle(newAngle + i * 0.1); bullet.homing = true; enemyBullets.push(bullet); game.addChild(bullet); } } }, 200); } LK.getSound('enemyShoot').play(); self.readyToAttack = false; } } }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphic = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -3; self.health = 2; self.type = 'normal'; self.fireRate = 120; self.lastShot = Math.floor(Math.random() * 60); self.points = 100; self.movePattern = 'straight'; self.amplitude = 0; self.frequency = 0; self.initialY = 0; self.angle = 0; self.setType = function (type) { self.type = type; switch (type) { case 'fast': self.speed = -5; self.health = 1; enemyGraphic.tint = 0x2ecc71; // Green self.points = 150; self.fireRate = 0; // Doesn't shoot break; case 'tank': self.speed = -2; self.health = 4; enemyGraphic.tint = 0xe74c3c; // Red enemyGraphic.scaleX = 1.3; enemyGraphic.scaleY = 1.3; self.points = 200; self.fireRate = 100; break; case 'zigzag': self.movePattern = 'zigzag'; self.amplitude = 100; self.frequency = 0.02; enemyGraphic.tint = 0xf1c40f; // Yellow self.points = 150; break; } }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xff0000, 200); return self.health <= 0; }; self.update = function () { // Store last position before moving if (self.lastX === undefined) { self.lastX = self.x; } // Determine if enemy should move to the left side var moveToLeftSide = self.x > 300 && Math.random() < 0.01; if (moveToLeftSide) { // Move toward left side self.x = Math.max(300, self.x + self.speed * 2); } else if (self.movePattern === 'straight') { self.x += self.speed; } else if (self.movePattern === 'zigzag') { self.x += self.speed; self.y = self.initialY + Math.sin(self.angle) * self.amplitude; self.angle += self.frequency; } // Attack player if in range and fireRate > 0 if (player && self.fireRate > 0 && self.x < 1500) { // Calculate angle to player for better targeting var targetAngle = 0; if (player) { var dx = player.x - self.x; var dy = player.y - self.y; targetAngle = Math.atan2(dy, dx); } if (LK.ticks - self.lastShot >= self.fireRate) { // Different firing patterns based on enemy type if (self.type === 'tank') { // Tank fires a 5-way spread for (var i = -2; i <= 2; i++) { var bullet = new EnemyBullet(); bullet.x = self.x - 20; bullet.y = self.y; var dx = player.x - self.x; var dy = player.y - self.y; var baseAngle = Math.atan2(dy, dx); bullet.setAngle(baseAngle + i * 0.25); enemyBullets.push(bullet); game.addChild(bullet); } } else if (self.type === 'zigzag') { // Zigzag fires in multiple directions including player targeting var directions = [-Math.PI / 2, -Math.PI / 4, 0, Math.PI / 4, Math.PI / 2]; for (var i = 0; i < directions.length; i++) { var bullet = new EnemyBullet(); bullet.x = self.x - 20; bullet.y = self.y; // Add target angle to create more varied patterns bullet.setAngle(targetAngle + directions[i]); enemyBullets.push(bullet); game.addChild(bullet); } } else { // Enhanced normal enemy attack - fires in 360 degrees with one aimed shot var bulletCount = 8; // Number of bullets in circle // Fire one direct shot at player var targetBullet = new EnemyBullet(); targetBullet.x = self.x - 20; targetBullet.y = self.y; targetBullet.setAngle(targetAngle); targetBullet.homing = true; // Make the targeted shot homing enemyBullets.push(targetBullet); game.addChild(targetBullet); // Fire in a circular pattern for (var i = 0; i < bulletCount; i++) { var angle = i / bulletCount * Math.PI * 2; var bullet = new EnemyBullet(); bullet.x = self.x - 20; bullet.y = self.y; bullet.setAngle(angle); enemyBullets.push(bullet); game.addChild(bullet); } } // Play sound LK.getSound('enemyShoot').play(); self.lastShot = LK.ticks; } } // Update lastX position self.lastX = self.x; // Remove if out of bounds if (self.x < -100) { self.shouldRemove = true; } }; return self; }); var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -10; self.angle = 0; self.setAngle = function (angle) { self.angle = angle; bullet.rotation = angle + Math.PI / 2; // Rotate bullet sprite to match direction }; self.update = function () { // Store last position for tracking if (self.lastX === undefined) { self.lastX = self.x; self.lastY = self.y; } // Update position based on angle and speed self.x += Math.cos(self.angle) * self.speed; self.y += Math.sin(self.angle) * self.speed; // Add slight homing capability for some bullets (10% chance at creation if not explicitly set) if (self.homing === undefined) { self.homing = Math.random() < 0.1; } // If this is a homing bullet and player exists, adjust trajectory more aggressively if (self.homing && player && LK.ticks % 10 === 0) { // More frequent updates for smoother tracking var targetAngle = Math.atan2(player.y - self.y, player.x - self.x); // Gradually adjust angle towards player (improved turning capability) var angleDiff = targetAngle - self.angle; // Normalize angle difference to -PI to PI if (angleDiff > Math.PI) { angleDiff -= Math.PI * 2; } if (angleDiff < -Math.PI) { angleDiff += Math.PI * 2; } // Apply a larger adjustment toward player for more effective homing self.angle += angleDiff * 0.15; // Update bullet rotation to match direction bullet.rotation = self.angle + Math.PI / 2; } // Remove if out of bounds if (self.x < -50 || self.x > 2048 + 50 || self.y < -50 || self.y > 2732 + 50) { self.shouldRemove = true; } // Update last position self.lastX = self.x; self.lastY = self.y; }; return self; }); var Explosion = Container.expand(function () { var self = Container.call(this); var explosion = self.attachAsset('explosion', { anchorX: 0.5, anchorY: 0.5 }); self.lifetime = 20; self.update = function () { self.lifetime--; // Scale up and fade out explosion.scaleX += 0.1; explosion.scaleY += 0.1; explosion.alpha = self.lifetime / 20; if (self.lifetime <= 0) { self.shouldRemove = true; } }; return self; }); var PlayerBullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 20; self.damage = 1; self.powered = false; self.setPowered = function () { self.powered = true; self.damage = 2; bullet.scaleX = 1.5; bullet.scaleY = 1.5; bullet.tint = 0xff9500; }; self.update = function () { self.x += self.speed; // Remove if out of bounds if (self.x > 2048 + 50) { self.shouldRemove = true; } }; return self; }); var PlayerShip = Container.expand(function () { var self = Container.call(this); var ship = self.attachAsset('playerShip', { anchorX: 0.5, anchorY: 0.5 }); ship.tint = 0xffffff; // Reset ship to default color self.speed = 10; self.health = 3; self.maxHealth = 3; self.fireRate = 15; self.lastShot = 0; self.invulnerable = false; self.powerUpActive = false; self.powerUpType = null; self.powerUpTimer = 0; self.takeDamage = function () { if (self.invulnerable) { return; } self.health -= 1; LK.getSound('damage').play(); // Flash red when damaged LK.effects.flashObject(self, 0xff0000, 500); // Make player invulnerable for a short period self.invulnerable = true; self.alpha = 0.5; LK.setTimeout(function () { self.invulnerable = false; self.alpha = 1; }, 2000); }; self.activatePowerUp = function (type) { self.powerUpActive = true; self.powerUpType = type; self.powerUpTimer = 300; // 5 seconds at 60fps LK.getSound('powerUp').play(); // Apply power-up effect switch (type) { case 'weapon': ship.tint = 0xf1c40f; // Yellow break; case 'shield': ship.tint = 0x2ecc71; // Green self.invulnerable = true; break; case 'speed': ship.tint = 0x3498db; // Blue self.speed = 15; break; } }; self.update = function () { // Handle power-up timer if (self.powerUpActive) { self.powerUpTimer--; if (self.powerUpTimer <= 0) { // Reset power-up effects self.powerUpActive = false; ship.tint = 0xffffff; self.speed = 10; if (self.powerUpType === 'shield') { self.invulnerable = false; } } } // Store last position to calculate movement direction if (self.lastX === undefined) { self.lastX = self.x; self.lastY = self.y; } // Add subtle ship tilt based on movement direction if (Math.abs(self.x - self.lastX) > 1) { // Calculate tilt based on horizontal movement speed var targetRotation = (self.x - self.lastX) * 0.01; // Limit rotation to small values targetRotation = Math.max(-0.2, Math.min(0.2, targetRotation)); // Smooth rotation transition tween(ship, { rotation: targetRotation }, { duration: 100, easing: tween.easeOutQuad }); } else { // Return to neutral position when not moving horizontally tween(ship, { rotation: 0 }, { duration: 300, easing: tween.easeOutQuad }); } // Update last position self.lastX = self.x; self.lastY = self.y; }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerUp = self.attachAsset('powerUp', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -3; self.type = 'weapon'; self.blinkTimer = 0; self.setType = function (type) { self.type = type; switch (type) { case 'weapon': powerUp.tint = 0xf1c40f; // Yellow break; case 'shield': powerUp.tint = 0x2ecc71; // Green break; case 'speed': powerUp.tint = 0x3498db; // Blue break; } }; self.update = function () { self.x += self.speed; // Make power-up blink self.blinkTimer++; if (self.blinkTimer % 20 === 0) { powerUp.alpha = powerUp.alpha === 1 ? 0.5 : 1; } // Remove if out of bounds if (self.x < -100) { self.shouldRemove = true; } }; return self; }); var Star = Container.expand(function () { var self = Container.call(this); var star = self.attachAsset('starBackground', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -1; self.setSpeed = function (speed) { self.speed = speed; // Adjust star size based on speed (parallax effect) var scale = Math.max(0.5, Math.min(2, Math.abs(speed) / 2)); star.scaleX = scale; star.scaleY = scale; // Adjust brightness based on speed var brightness = Math.max(0.3, Math.min(1, Math.abs(speed) / 5)); star.alpha = brightness; }; self.update = function () { self.x += self.speed; // Wrap around when off-screen if (self.x < -50) { self.x = 2048 + 50; self.y = Math.random() * 2732; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000022 }); /**** * Game Code ****/ // Game state variables var player; var playerBullets = []; var enemies = []; var bosses = []; var enemyBullets = []; var asteroids = []; var powerUps = []; var explosions = []; var stars = []; // Game settings var level = 1; var score = 0; var enemySpawnRate = 240; // Increased from 120 to 240 (fewer enemies) var asteroidSpawnRate = 180; var bossSpawned = false; var gameActive = true; var levelCompleted = false; var spawnBossAt = 10; // Spawn boss after this many enemies killed var enemiesKilled = 0; var maxEnemiesOnScreen = 5; // Maximum number of enemies allowed on screen // UI elements var scoreTxt; var healthTxt; var levelTxt; // Initialize game function initGame() { // Create player player = new PlayerShip(); player.x = 200; player.y = 2732 / 2; game.addChild(player); // Create stars for background for (var i = 0; i < 100; i++) { var star = new Star(); star.x = Math.random() * 2048; star.y = Math.random() * 2732; star.setSpeed(-(Math.random() * 4 + 1)); stars.push(star); game.addChild(star); } // Setup UI setupUI(); // Play background music LK.playMusic('gameMusic'); } function setupUI() { // Score text scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(scoreTxt); // Health text healthTxt = new Text2('Health: 3', { size: 60, fill: 0xFFFFFF }); healthTxt.anchor.set(0, 0); LK.gui.top.addChild(healthTxt); // Level text levelTxt = new Text2('Level: 1', { size: 60, fill: 0xFFFFFF }); levelTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(levelTxt); // Position adjustments to avoid overlapping with menu icon levelTxt.x = 120; // Move away from the top-left corner } // Update UI elements function updateUI() { scoreTxt.setText('Score: ' + score); healthTxt.setText('Health: ' + player.health); levelTxt.setText('Level: ' + level); // Set score in LK system for leaderboards LK.setScore(score); } // Player shooting function playerShoot() { if (LK.ticks - player.lastShot >= player.fireRate) { var bullet = new PlayerBullet(); bullet.x = player.x + 50; bullet.y = player.y; // Apply power-up effect if active if (player.powerUpActive && player.powerUpType === 'weapon') { bullet.setPowered(); } playerBullets.push(bullet); game.addChild(bullet); // Play sound LK.getSound('playerShoot').play(); player.lastShot = LK.ticks; } } // Enemy and boss attack functionality has been moved into their respective classes // Spawn enemies function spawnEnemy() { if (!gameActive || levelCompleted || bossSpawned) { return; } // Only spawn if we haven't reached the maximum number of enemies if (LK.ticks % enemySpawnRate === 0 && enemies.length < maxEnemiesOnScreen) { var enemy = new Enemy(); enemy.x = 2048 + 100; enemy.y = Math.random() * (2732 - 300) + 150; enemy.initialY = enemy.y; // Different enemy types based on random chance and level var typeRoll = Math.random(); if (level >= 3 && typeRoll < 0.2) { enemy.setType('tank'); } else if (level >= 2 && typeRoll < 0.4) { enemy.setType('zigzag'); } else if (typeRoll < 0.6) { enemy.setType('fast'); } enemies.push(enemy); game.addChild(enemy); } } // Spawn asteroids function spawnAsteroid() { if (!gameActive || levelCompleted) { return; } if (LK.ticks % asteroidSpawnRate === 0) { var asteroid = new Asteroid(); asteroid.x = 2048 + 100; asteroid.y = Math.random() * (2732 - 200) + 100; // Random asteroid size var sizeRoll = Math.random(); if (sizeRoll < 0.3) { asteroid.setSize('small'); } else if (sizeRoll < 0.8) { asteroid.setSize('medium'); } else { asteroid.setSize('large'); } asteroids.push(asteroid); game.addChild(asteroid); } } // Spawn boss function spawnBoss() { if (bossSpawned || !gameActive || levelCompleted) { return; } if (enemiesKilled >= spawnBossAt) { var boss = new Boss(); boss.x = 2048 + 200; boss.y = 2732 / 2; // Adjust boss health based on level boss.health = 50 + (level - 1) * 25; boss.maxHealth = boss.health; bosses.push(boss); game.addChild(boss); bossSpawned = true; } } // Spawn power-up function spawnPowerUp() { if (!gameActive || levelCompleted) { return; } // Random chance to spawn power-up (1% chance each tick) if (Math.random() < 0.01) { var powerUp = new PowerUp(); powerUp.x = 2048 + 100; powerUp.y = Math.random() * (2732 - 200) + 100; // Random power-up type var typeRoll = Math.random(); if (typeRoll < 0.33) { powerUp.setType('weapon'); } else if (typeRoll < 0.66) { powerUp.setType('shield'); } else { powerUp.setType('speed'); } powerUps.push(powerUp); game.addChild(powerUp); } } // Create explosion function createExplosion(x, y, scale) { var explosion = new Explosion(); explosion.x = x; explosion.y = y; if (scale) { explosion.scaleX = scale; explosion.scaleY = scale; } explosions.push(explosion); game.addChild(explosion); LK.getSound('explosion').play(); } // Check collisions function checkCollisions() { // Player bullets vs enemies for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; // Check against enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { if (enemy.takeDamage(bullet.damage)) { // Enemy destroyed createExplosion(enemy.x, enemy.y); // Add score score += enemy.points; enemiesKilled++; // Remove enemy enemy.destroy(); enemies.splice(j, 1); } // Remove bullet bullet.destroy(); playerBullets.splice(i, 1); break; } } // Check against bosses if bullet still exists if (playerBullets[i]) { for (var j = bosses.length - 1; j >= 0; j--) { var boss = bosses[j]; if (bullet.intersects(boss)) { if (boss.takeDamage(bullet.damage)) { // Boss destroyed createExplosion(boss.x, boss.y, 2); // Add score score += boss.points; // Level completed levelCompleted = true; // Remove boss boss.destroy(); bosses.splice(j, 1); // Advance to next level after delay LK.setTimeout(function () { levelUp(); }, 3000); } // Remove bullet bullet.destroy(); playerBullets.splice(i, 1); break; } } } // Check against asteroids if bullet still exists if (playerBullets[i]) { for (var j = asteroids.length - 1; j >= 0; j--) { var asteroid = asteroids[j]; if (bullet.intersects(asteroid)) { if (asteroid.takeDamage(bullet.damage)) { // Asteroid destroyed createExplosion(asteroid.x, asteroid.y); // Add score score += 50; // Remove asteroid asteroid.destroy(); asteroids.splice(j, 1); } // Remove bullet bullet.destroy(); playerBullets.splice(i, 1); break; } } } } // Enemy bullets vs player for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; if (bullet.intersects(player)) { // Player hit player.takeDamage(); // Remove bullet bullet.destroy(); enemyBullets.splice(i, 1); // Check player health if (player.health <= 0) { gameOver(); } } } // Enemies vs player for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.intersects(player)) { // Player collided with enemy player.takeDamage(); // Destroy enemy createExplosion(enemy.x, enemy.y); enemy.destroy(); enemies.splice(i, 1); // Check player health if (player.health <= 0) { gameOver(); } } } // Asteroids vs player for (var i = asteroids.length - 1; i >= 0; i--) { var asteroid = asteroids[i]; if (asteroid.intersects(player)) { // Player collided with asteroid player.takeDamage(); // Destroy asteroid createExplosion(asteroid.x, asteroid.y); asteroid.destroy(); asteroids.splice(i, 1); // Check player health if (player.health <= 0) { gameOver(); } } } // PowerUps vs player for (var i = powerUps.length - 1; i >= 0; i--) { var powerUp = powerUps[i]; if (powerUp.intersects(player)) { // Player collected power-up player.activatePowerUp(powerUp.type); // Remove power-up powerUp.destroy(); powerUps.splice(i, 1); } } } // Level up function function levelUp() { level++; enemiesKilled = 0; bossSpawned = false; levelCompleted = false; // Increase difficulty but keep enemySpawnRate higher to maintain reduced enemy count enemySpawnRate = Math.max(180, enemySpawnRate - 10); // Higher minimum to ensure fewer enemies asteroidSpawnRate = Math.max(90, asteroidSpawnRate - 15); spawnBossAt += 5; // Increase max enemies slightly with levels but cap it maxEnemiesOnScreen = Math.min(8, 5 + Math.floor(level / 2)); // Update UI updateUI(); // Fully heal player for next level player.health = player.maxHealth; // Clear all entities except player and stars clearEntities(); } // Clear all entities except player and stars function clearEntities() { // Clear enemies for (var i = 0; i < enemies.length; i++) { enemies[i].destroy(); } enemies = []; // Clear bosses for (var i = 0; i < bosses.length; i++) { bosses[i].destroy(); } bosses = []; // Clear enemy bullets for (var i = 0; i < enemyBullets.length; i++) { enemyBullets[i].destroy(); } enemyBullets = []; // Clear player bullets for (var i = 0; i < playerBullets.length; i++) { playerBullets[i].destroy(); } playerBullets = []; // Clear asteroids for (var i = 0; i < asteroids.length; i++) { asteroids[i].destroy(); } asteroids = []; // Clear power-ups for (var i = 0; i < powerUps.length; i++) { powerUps[i].destroy(); } powerUps = []; // Clear explosions for (var i = 0; i < explosions.length; i++) { explosions[i].destroy(); } explosions = []; } // Game over function gameOver() { gameActive = false; // Create explosion at player position createExplosion(player.x, player.y, 1.5); // Hide player player.visible = false; // Show game over screen LK.showGameOver(); } // Handle player movement function handleMove(x, y) { if (!gameActive) { return; } // Move player based on touch position if (x < 300) { x = 300; } // Keep player from going too far left if (x > 2048 - 100) { x = 2048 - 100; } // Keep player from going too far right // Stop any existing movement tweens tween.stop(player, { x: true, y: true }); // Create new tween with smooth easing tween(player, { x: x, y: y }, { duration: 200, easing: tween.easeOutQuad }); } // Touch/mouse controls game.down = function (x, y) { if (!gameActive) { return; } handleMove(x, y); }; // Add lastMoveTime to throttle move events var lastMoveTime = 0; game.move = function (x, y) { if (!gameActive) { return; } // Throttle move events to prevent excessive tweening var currentTime = Date.now(); if (currentTime - lastMoveTime > 50) { // Limit to 20 updates per second handleMove(x, y); lastMoveTime = currentTime; } }; // Main game loop game.update = function () { if (!gameActive && !levelCompleted) { return; } // Spawn game entities spawnEnemy(); spawnAsteroid(); spawnPowerUp(); spawnBoss(); // Auto-shoot if (gameActive) { playerShoot(); } // Update all game entities // Update player bullets for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; // Check if bullet should be removed if (bullet.shouldRemove) { bullet.destroy(); playerBullets.splice(i, 1); } } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; // Check if enemy should be removed if (enemy.shouldRemove) { enemy.destroy(); enemies.splice(i, 1); } } // Update bosses for (var i = bosses.length - 1; i >= 0; i--) { var boss = bosses[i]; // Check if boss should be removed if (boss.shouldRemove) { boss.destroy(); bosses.splice(i, 1); } } // Update enemy bullets for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; // Check if bullet should be removed if (bullet.shouldRemove) { bullet.destroy(); enemyBullets.splice(i, 1); } } // Update asteroids for (var i = asteroids.length - 1; i >= 0; i--) { var asteroid = asteroids[i]; // Check if asteroid should be removed if (asteroid.shouldRemove) { asteroid.destroy(); asteroids.splice(i, 1); } } // Update power-ups for (var i = powerUps.length - 1; i >= 0; i--) { var powerUp = powerUps[i]; // Check if power-up should be removed if (powerUp.shouldRemove) { powerUp.destroy(); powerUps.splice(i, 1); } } // Update explosions for (var i = explosions.length - 1; i >= 0; i--) { var explosion = explosions[i]; // Check if explosion should be removed if (explosion.shouldRemove) { explosion.destroy(); explosions.splice(i, 1); } } // Check for collisions checkCollisions(); // Update UI updateUI(); }; // Initialize the game initGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Asteroid = Container.expand(function () {
var self = Container.call(this);
var asteroid = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -5;
self.rotationSpeed = (Math.random() - 0.5) * 0.05;
self.size = 'medium';
self.health = 2;
self.setSize = function (size) {
self.size = size;
switch (size) {
case 'small':
asteroid.scaleX = 0.7;
asteroid.scaleY = 0.7;
self.health = 1;
self.speed = -6;
break;
case 'medium':
// Default size
break;
case 'large':
asteroid.scaleX = 1.5;
asteroid.scaleY = 1.5;
self.health = 3;
self.speed = -3;
break;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0x555555, 200);
return self.health <= 0;
};
self.update = function () {
self.x += self.speed;
self.rotation += self.rotationSpeed;
// Remove if out of bounds
if (self.x < -100) {
self.shouldRemove = true;
}
};
return self;
});
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphic = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -1;
self.health = 50;
self.maxHealth = 50;
self.phase = 1;
self.attackTimer = 0;
self.attackCooldown = 60;
self.movePattern = 'entrance';
self.targetY = 0;
self.points = 2000;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 100);
// Change phase at 50% health
if (self.health <= self.maxHealth / 2 && self.phase === 1) {
self.phase = 2;
self.attackCooldown = 40;
bossGraphic.tint = 0xe74c3c; // Red tint for phase 2
}
return self.health <= 0;
};
self.update = function () {
if (self.movePattern === 'entrance') {
self.x += self.speed;
if (self.x <= 1700) {
self.movePattern = 'vertical';
self.targetY = Math.random() * 1500 + 500;
}
} else if (self.movePattern === 'vertical') {
// Move toward target Y position
if (Math.abs(self.y - self.targetY) > 5) {
self.y += self.targetY > self.y ? 4 : -4;
} else {
// Pick a new target
self.targetY = Math.random() * 1500 + 500;
}
}
// Boss attack timer
self.attackTimer++;
if (self.attackTimer >= self.attackCooldown) {
self.attackTimer = 0;
self.readyToAttack = true;
// Automatic attack if player exists
if (player && !self.shouldRemove) {
// Get current player position for more accurate targeting
var targetX = player.x;
var targetY = player.y;
// Calculate predicted player position based on current movement (better targeting)
var angleToPlayer = Math.atan2(targetY - self.y, targetX - self.x);
// Phase 1: Spread shot in multiple directions
if (self.phase === 1) {
// Create a circular pattern of bullets
var bulletCount = 8;
for (var i = 0; i < bulletCount; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x - 50;
bullet.y = self.y;
var angle = i / bulletCount * Math.PI * 2;
bullet.setAngle(angle);
enemyBullets.push(bullet);
game.addChild(bullet);
}
// Also fire a cluster toward player
for (var i = -1; i <= 1; i++) {
var bulletPlayer = new EnemyBullet();
bulletPlayer.x = self.x - 50;
bulletPlayer.y = self.y;
bulletPlayer.setAngle(angleToPlayer + i * 0.15);
enemyBullets.push(bulletPlayer);
game.addChild(bulletPlayer);
}
} else {
// Phase 2: Multi-directional attack with homing bullets
// Create X pattern
var directions = [angleToPlayer, angleToPlayer + Math.PI / 4, angleToPlayer + Math.PI / 2, angleToPlayer + Math.PI * 3 / 4, angleToPlayer + Math.PI, angleToPlayer - Math.PI / 4, angleToPlayer - Math.PI / 2, angleToPlayer - Math.PI * 3 / 4];
for (var i = 0; i < directions.length; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x - 50;
bullet.y = self.y;
bullet.setAngle(directions[i]);
// Make every third bullet homing
if (i % 3 === 0) {
bullet.homing = true;
}
enemyBullets.push(bullet);
game.addChild(bullet);
}
// Schedule more precise shots with updated targeting
LK.setTimeout(function () {
if (!self.shouldRemove && self.health > 0 && player) {
// Fire 3 homing bullets directly at player for better accuracy
for (var i = -1; i <= 1; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x - 50;
bullet.y = self.y;
// Get fresh angle for better accuracy in delayed shots
var newAngle = Math.atan2(player.y - self.y, player.x - self.x);
bullet.setAngle(newAngle + i * 0.1);
bullet.homing = true;
enemyBullets.push(bullet);
game.addChild(bullet);
}
}
}, 200);
}
LK.getSound('enemyShoot').play();
self.readyToAttack = false;
}
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphic = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -3;
self.health = 2;
self.type = 'normal';
self.fireRate = 120;
self.lastShot = Math.floor(Math.random() * 60);
self.points = 100;
self.movePattern = 'straight';
self.amplitude = 0;
self.frequency = 0;
self.initialY = 0;
self.angle = 0;
self.setType = function (type) {
self.type = type;
switch (type) {
case 'fast':
self.speed = -5;
self.health = 1;
enemyGraphic.tint = 0x2ecc71; // Green
self.points = 150;
self.fireRate = 0; // Doesn't shoot
break;
case 'tank':
self.speed = -2;
self.health = 4;
enemyGraphic.tint = 0xe74c3c; // Red
enemyGraphic.scaleX = 1.3;
enemyGraphic.scaleY = 1.3;
self.points = 200;
self.fireRate = 100;
break;
case 'zigzag':
self.movePattern = 'zigzag';
self.amplitude = 100;
self.frequency = 0.02;
enemyGraphic.tint = 0xf1c40f; // Yellow
self.points = 150;
break;
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 200);
return self.health <= 0;
};
self.update = function () {
// Store last position before moving
if (self.lastX === undefined) {
self.lastX = self.x;
}
// Determine if enemy should move to the left side
var moveToLeftSide = self.x > 300 && Math.random() < 0.01;
if (moveToLeftSide) {
// Move toward left side
self.x = Math.max(300, self.x + self.speed * 2);
} else if (self.movePattern === 'straight') {
self.x += self.speed;
} else if (self.movePattern === 'zigzag') {
self.x += self.speed;
self.y = self.initialY + Math.sin(self.angle) * self.amplitude;
self.angle += self.frequency;
}
// Attack player if in range and fireRate > 0
if (player && self.fireRate > 0 && self.x < 1500) {
// Calculate angle to player for better targeting
var targetAngle = 0;
if (player) {
var dx = player.x - self.x;
var dy = player.y - self.y;
targetAngle = Math.atan2(dy, dx);
}
if (LK.ticks - self.lastShot >= self.fireRate) {
// Different firing patterns based on enemy type
if (self.type === 'tank') {
// Tank fires a 5-way spread
for (var i = -2; i <= 2; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x - 20;
bullet.y = self.y;
var dx = player.x - self.x;
var dy = player.y - self.y;
var baseAngle = Math.atan2(dy, dx);
bullet.setAngle(baseAngle + i * 0.25);
enemyBullets.push(bullet);
game.addChild(bullet);
}
} else if (self.type === 'zigzag') {
// Zigzag fires in multiple directions including player targeting
var directions = [-Math.PI / 2, -Math.PI / 4, 0, Math.PI / 4, Math.PI / 2];
for (var i = 0; i < directions.length; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x - 20;
bullet.y = self.y;
// Add target angle to create more varied patterns
bullet.setAngle(targetAngle + directions[i]);
enemyBullets.push(bullet);
game.addChild(bullet);
}
} else {
// Enhanced normal enemy attack - fires in 360 degrees with one aimed shot
var bulletCount = 8; // Number of bullets in circle
// Fire one direct shot at player
var targetBullet = new EnemyBullet();
targetBullet.x = self.x - 20;
targetBullet.y = self.y;
targetBullet.setAngle(targetAngle);
targetBullet.homing = true; // Make the targeted shot homing
enemyBullets.push(targetBullet);
game.addChild(targetBullet);
// Fire in a circular pattern
for (var i = 0; i < bulletCount; i++) {
var angle = i / bulletCount * Math.PI * 2;
var bullet = new EnemyBullet();
bullet.x = self.x - 20;
bullet.y = self.y;
bullet.setAngle(angle);
enemyBullets.push(bullet);
game.addChild(bullet);
}
}
// Play sound
LK.getSound('enemyShoot').play();
self.lastShot = LK.ticks;
}
}
// Update lastX position
self.lastX = self.x;
// Remove if out of bounds
if (self.x < -100) {
self.shouldRemove = true;
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -10;
self.angle = 0;
self.setAngle = function (angle) {
self.angle = angle;
bullet.rotation = angle + Math.PI / 2; // Rotate bullet sprite to match direction
};
self.update = function () {
// Store last position for tracking
if (self.lastX === undefined) {
self.lastX = self.x;
self.lastY = self.y;
}
// Update position based on angle and speed
self.x += Math.cos(self.angle) * self.speed;
self.y += Math.sin(self.angle) * self.speed;
// Add slight homing capability for some bullets (10% chance at creation if not explicitly set)
if (self.homing === undefined) {
self.homing = Math.random() < 0.1;
}
// If this is a homing bullet and player exists, adjust trajectory more aggressively
if (self.homing && player && LK.ticks % 10 === 0) {
// More frequent updates for smoother tracking
var targetAngle = Math.atan2(player.y - self.y, player.x - self.x);
// Gradually adjust angle towards player (improved turning capability)
var angleDiff = targetAngle - self.angle;
// Normalize angle difference to -PI to PI
if (angleDiff > Math.PI) {
angleDiff -= Math.PI * 2;
}
if (angleDiff < -Math.PI) {
angleDiff += Math.PI * 2;
}
// Apply a larger adjustment toward player for more effective homing
self.angle += angleDiff * 0.15;
// Update bullet rotation to match direction
bullet.rotation = self.angle + Math.PI / 2;
}
// Remove if out of bounds
if (self.x < -50 || self.x > 2048 + 50 || self.y < -50 || self.y > 2732 + 50) {
self.shouldRemove = true;
}
// Update last position
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosion = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifetime = 20;
self.update = function () {
self.lifetime--;
// Scale up and fade out
explosion.scaleX += 0.1;
explosion.scaleY += 0.1;
explosion.alpha = self.lifetime / 20;
if (self.lifetime <= 0) {
self.shouldRemove = true;
}
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 20;
self.damage = 1;
self.powered = false;
self.setPowered = function () {
self.powered = true;
self.damage = 2;
bullet.scaleX = 1.5;
bullet.scaleY = 1.5;
bullet.tint = 0xff9500;
};
self.update = function () {
self.x += self.speed;
// Remove if out of bounds
if (self.x > 2048 + 50) {
self.shouldRemove = true;
}
};
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
var ship = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5
});
ship.tint = 0xffffff; // Reset ship to default color
self.speed = 10;
self.health = 3;
self.maxHealth = 3;
self.fireRate = 15;
self.lastShot = 0;
self.invulnerable = false;
self.powerUpActive = false;
self.powerUpType = null;
self.powerUpTimer = 0;
self.takeDamage = function () {
if (self.invulnerable) {
return;
}
self.health -= 1;
LK.getSound('damage').play();
// Flash red when damaged
LK.effects.flashObject(self, 0xff0000, 500);
// Make player invulnerable for a short period
self.invulnerable = true;
self.alpha = 0.5;
LK.setTimeout(function () {
self.invulnerable = false;
self.alpha = 1;
}, 2000);
};
self.activatePowerUp = function (type) {
self.powerUpActive = true;
self.powerUpType = type;
self.powerUpTimer = 300; // 5 seconds at 60fps
LK.getSound('powerUp').play();
// Apply power-up effect
switch (type) {
case 'weapon':
ship.tint = 0xf1c40f; // Yellow
break;
case 'shield':
ship.tint = 0x2ecc71; // Green
self.invulnerable = true;
break;
case 'speed':
ship.tint = 0x3498db; // Blue
self.speed = 15;
break;
}
};
self.update = function () {
// Handle power-up timer
if (self.powerUpActive) {
self.powerUpTimer--;
if (self.powerUpTimer <= 0) {
// Reset power-up effects
self.powerUpActive = false;
ship.tint = 0xffffff;
self.speed = 10;
if (self.powerUpType === 'shield') {
self.invulnerable = false;
}
}
}
// Store last position to calculate movement direction
if (self.lastX === undefined) {
self.lastX = self.x;
self.lastY = self.y;
}
// Add subtle ship tilt based on movement direction
if (Math.abs(self.x - self.lastX) > 1) {
// Calculate tilt based on horizontal movement speed
var targetRotation = (self.x - self.lastX) * 0.01;
// Limit rotation to small values
targetRotation = Math.max(-0.2, Math.min(0.2, targetRotation));
// Smooth rotation transition
tween(ship, {
rotation: targetRotation
}, {
duration: 100,
easing: tween.easeOutQuad
});
} else {
// Return to neutral position when not moving horizontally
tween(ship, {
rotation: 0
}, {
duration: 300,
easing: tween.easeOutQuad
});
}
// Update last position
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUp = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -3;
self.type = 'weapon';
self.blinkTimer = 0;
self.setType = function (type) {
self.type = type;
switch (type) {
case 'weapon':
powerUp.tint = 0xf1c40f; // Yellow
break;
case 'shield':
powerUp.tint = 0x2ecc71; // Green
break;
case 'speed':
powerUp.tint = 0x3498db; // Blue
break;
}
};
self.update = function () {
self.x += self.speed;
// Make power-up blink
self.blinkTimer++;
if (self.blinkTimer % 20 === 0) {
powerUp.alpha = powerUp.alpha === 1 ? 0.5 : 1;
}
// Remove if out of bounds
if (self.x < -100) {
self.shouldRemove = true;
}
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var star = self.attachAsset('starBackground', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -1;
self.setSpeed = function (speed) {
self.speed = speed;
// Adjust star size based on speed (parallax effect)
var scale = Math.max(0.5, Math.min(2, Math.abs(speed) / 2));
star.scaleX = scale;
star.scaleY = scale;
// Adjust brightness based on speed
var brightness = Math.max(0.3, Math.min(1, Math.abs(speed) / 5));
star.alpha = brightness;
};
self.update = function () {
self.x += self.speed;
// Wrap around when off-screen
if (self.x < -50) {
self.x = 2048 + 50;
self.y = Math.random() * 2732;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000022
});
/****
* Game Code
****/
// Game state variables
var player;
var playerBullets = [];
var enemies = [];
var bosses = [];
var enemyBullets = [];
var asteroids = [];
var powerUps = [];
var explosions = [];
var stars = [];
// Game settings
var level = 1;
var score = 0;
var enemySpawnRate = 240; // Increased from 120 to 240 (fewer enemies)
var asteroidSpawnRate = 180;
var bossSpawned = false;
var gameActive = true;
var levelCompleted = false;
var spawnBossAt = 10; // Spawn boss after this many enemies killed
var enemiesKilled = 0;
var maxEnemiesOnScreen = 5; // Maximum number of enemies allowed on screen
// UI elements
var scoreTxt;
var healthTxt;
var levelTxt;
// Initialize game
function initGame() {
// Create player
player = new PlayerShip();
player.x = 200;
player.y = 2732 / 2;
game.addChild(player);
// Create stars for background
for (var i = 0; i < 100; i++) {
var star = new Star();
star.x = Math.random() * 2048;
star.y = Math.random() * 2732;
star.setSpeed(-(Math.random() * 4 + 1));
stars.push(star);
game.addChild(star);
}
// Setup UI
setupUI();
// Play background music
LK.playMusic('gameMusic');
}
function setupUI() {
// Score text
scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
// Health text
healthTxt = new Text2('Health: 3', {
size: 60,
fill: 0xFFFFFF
});
healthTxt.anchor.set(0, 0);
LK.gui.top.addChild(healthTxt);
// Level text
levelTxt = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(levelTxt);
// Position adjustments to avoid overlapping with menu icon
levelTxt.x = 120; // Move away from the top-left corner
}
// Update UI elements
function updateUI() {
scoreTxt.setText('Score: ' + score);
healthTxt.setText('Health: ' + player.health);
levelTxt.setText('Level: ' + level);
// Set score in LK system for leaderboards
LK.setScore(score);
}
// Player shooting
function playerShoot() {
if (LK.ticks - player.lastShot >= player.fireRate) {
var bullet = new PlayerBullet();
bullet.x = player.x + 50;
bullet.y = player.y;
// Apply power-up effect if active
if (player.powerUpActive && player.powerUpType === 'weapon') {
bullet.setPowered();
}
playerBullets.push(bullet);
game.addChild(bullet);
// Play sound
LK.getSound('playerShoot').play();
player.lastShot = LK.ticks;
}
}
// Enemy and boss attack functionality has been moved into their respective classes
// Spawn enemies
function spawnEnemy() {
if (!gameActive || levelCompleted || bossSpawned) {
return;
}
// Only spawn if we haven't reached the maximum number of enemies
if (LK.ticks % enemySpawnRate === 0 && enemies.length < maxEnemiesOnScreen) {
var enemy = new Enemy();
enemy.x = 2048 + 100;
enemy.y = Math.random() * (2732 - 300) + 150;
enemy.initialY = enemy.y;
// Different enemy types based on random chance and level
var typeRoll = Math.random();
if (level >= 3 && typeRoll < 0.2) {
enemy.setType('tank');
} else if (level >= 2 && typeRoll < 0.4) {
enemy.setType('zigzag');
} else if (typeRoll < 0.6) {
enemy.setType('fast');
}
enemies.push(enemy);
game.addChild(enemy);
}
}
// Spawn asteroids
function spawnAsteroid() {
if (!gameActive || levelCompleted) {
return;
}
if (LK.ticks % asteroidSpawnRate === 0) {
var asteroid = new Asteroid();
asteroid.x = 2048 + 100;
asteroid.y = Math.random() * (2732 - 200) + 100;
// Random asteroid size
var sizeRoll = Math.random();
if (sizeRoll < 0.3) {
asteroid.setSize('small');
} else if (sizeRoll < 0.8) {
asteroid.setSize('medium');
} else {
asteroid.setSize('large');
}
asteroids.push(asteroid);
game.addChild(asteroid);
}
}
// Spawn boss
function spawnBoss() {
if (bossSpawned || !gameActive || levelCompleted) {
return;
}
if (enemiesKilled >= spawnBossAt) {
var boss = new Boss();
boss.x = 2048 + 200;
boss.y = 2732 / 2;
// Adjust boss health based on level
boss.health = 50 + (level - 1) * 25;
boss.maxHealth = boss.health;
bosses.push(boss);
game.addChild(boss);
bossSpawned = true;
}
}
// Spawn power-up
function spawnPowerUp() {
if (!gameActive || levelCompleted) {
return;
}
// Random chance to spawn power-up (1% chance each tick)
if (Math.random() < 0.01) {
var powerUp = new PowerUp();
powerUp.x = 2048 + 100;
powerUp.y = Math.random() * (2732 - 200) + 100;
// Random power-up type
var typeRoll = Math.random();
if (typeRoll < 0.33) {
powerUp.setType('weapon');
} else if (typeRoll < 0.66) {
powerUp.setType('shield');
} else {
powerUp.setType('speed');
}
powerUps.push(powerUp);
game.addChild(powerUp);
}
}
// Create explosion
function createExplosion(x, y, scale) {
var explosion = new Explosion();
explosion.x = x;
explosion.y = y;
if (scale) {
explosion.scaleX = scale;
explosion.scaleY = scale;
}
explosions.push(explosion);
game.addChild(explosion);
LK.getSound('explosion').play();
}
// Check collisions
function checkCollisions() {
// Player bullets vs enemies
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
// Check against enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
if (enemy.takeDamage(bullet.damage)) {
// Enemy destroyed
createExplosion(enemy.x, enemy.y);
// Add score
score += enemy.points;
enemiesKilled++;
// Remove enemy
enemy.destroy();
enemies.splice(j, 1);
}
// Remove bullet
bullet.destroy();
playerBullets.splice(i, 1);
break;
}
}
// Check against bosses if bullet still exists
if (playerBullets[i]) {
for (var j = bosses.length - 1; j >= 0; j--) {
var boss = bosses[j];
if (bullet.intersects(boss)) {
if (boss.takeDamage(bullet.damage)) {
// Boss destroyed
createExplosion(boss.x, boss.y, 2);
// Add score
score += boss.points;
// Level completed
levelCompleted = true;
// Remove boss
boss.destroy();
bosses.splice(j, 1);
// Advance to next level after delay
LK.setTimeout(function () {
levelUp();
}, 3000);
}
// Remove bullet
bullet.destroy();
playerBullets.splice(i, 1);
break;
}
}
}
// Check against asteroids if bullet still exists
if (playerBullets[i]) {
for (var j = asteroids.length - 1; j >= 0; j--) {
var asteroid = asteroids[j];
if (bullet.intersects(asteroid)) {
if (asteroid.takeDamage(bullet.damage)) {
// Asteroid destroyed
createExplosion(asteroid.x, asteroid.y);
// Add score
score += 50;
// Remove asteroid
asteroid.destroy();
asteroids.splice(j, 1);
}
// Remove bullet
bullet.destroy();
playerBullets.splice(i, 1);
break;
}
}
}
}
// Enemy bullets vs player
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.intersects(player)) {
// Player hit
player.takeDamage();
// Remove bullet
bullet.destroy();
enemyBullets.splice(i, 1);
// Check player health
if (player.health <= 0) {
gameOver();
}
}
}
// Enemies vs player
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.intersects(player)) {
// Player collided with enemy
player.takeDamage();
// Destroy enemy
createExplosion(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(i, 1);
// Check player health
if (player.health <= 0) {
gameOver();
}
}
}
// Asteroids vs player
for (var i = asteroids.length - 1; i >= 0; i--) {
var asteroid = asteroids[i];
if (asteroid.intersects(player)) {
// Player collided with asteroid
player.takeDamage();
// Destroy asteroid
createExplosion(asteroid.x, asteroid.y);
asteroid.destroy();
asteroids.splice(i, 1);
// Check player health
if (player.health <= 0) {
gameOver();
}
}
}
// PowerUps vs player
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (powerUp.intersects(player)) {
// Player collected power-up
player.activatePowerUp(powerUp.type);
// Remove power-up
powerUp.destroy();
powerUps.splice(i, 1);
}
}
}
// Level up function
function levelUp() {
level++;
enemiesKilled = 0;
bossSpawned = false;
levelCompleted = false;
// Increase difficulty but keep enemySpawnRate higher to maintain reduced enemy count
enemySpawnRate = Math.max(180, enemySpawnRate - 10); // Higher minimum to ensure fewer enemies
asteroidSpawnRate = Math.max(90, asteroidSpawnRate - 15);
spawnBossAt += 5;
// Increase max enemies slightly with levels but cap it
maxEnemiesOnScreen = Math.min(8, 5 + Math.floor(level / 2));
// Update UI
updateUI();
// Fully heal player for next level
player.health = player.maxHealth;
// Clear all entities except player and stars
clearEntities();
}
// Clear all entities except player and stars
function clearEntities() {
// Clear enemies
for (var i = 0; i < enemies.length; i++) {
enemies[i].destroy();
}
enemies = [];
// Clear bosses
for (var i = 0; i < bosses.length; i++) {
bosses[i].destroy();
}
bosses = [];
// Clear enemy bullets
for (var i = 0; i < enemyBullets.length; i++) {
enemyBullets[i].destroy();
}
enemyBullets = [];
// Clear player bullets
for (var i = 0; i < playerBullets.length; i++) {
playerBullets[i].destroy();
}
playerBullets = [];
// Clear asteroids
for (var i = 0; i < asteroids.length; i++) {
asteroids[i].destroy();
}
asteroids = [];
// Clear power-ups
for (var i = 0; i < powerUps.length; i++) {
powerUps[i].destroy();
}
powerUps = [];
// Clear explosions
for (var i = 0; i < explosions.length; i++) {
explosions[i].destroy();
}
explosions = [];
}
// Game over
function gameOver() {
gameActive = false;
// Create explosion at player position
createExplosion(player.x, player.y, 1.5);
// Hide player
player.visible = false;
// Show game over screen
LK.showGameOver();
}
// Handle player movement
function handleMove(x, y) {
if (!gameActive) {
return;
}
// Move player based on touch position
if (x < 300) {
x = 300;
} // Keep player from going too far left
if (x > 2048 - 100) {
x = 2048 - 100;
} // Keep player from going too far right
// Stop any existing movement tweens
tween.stop(player, {
x: true,
y: true
});
// Create new tween with smooth easing
tween(player, {
x: x,
y: y
}, {
duration: 200,
easing: tween.easeOutQuad
});
}
// Touch/mouse controls
game.down = function (x, y) {
if (!gameActive) {
return;
}
handleMove(x, y);
};
// Add lastMoveTime to throttle move events
var lastMoveTime = 0;
game.move = function (x, y) {
if (!gameActive) {
return;
}
// Throttle move events to prevent excessive tweening
var currentTime = Date.now();
if (currentTime - lastMoveTime > 50) {
// Limit to 20 updates per second
handleMove(x, y);
lastMoveTime = currentTime;
}
};
// Main game loop
game.update = function () {
if (!gameActive && !levelCompleted) {
return;
}
// Spawn game entities
spawnEnemy();
spawnAsteroid();
spawnPowerUp();
spawnBoss();
// Auto-shoot
if (gameActive) {
playerShoot();
}
// Update all game entities
// Update player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
// Check if bullet should be removed
if (bullet.shouldRemove) {
bullet.destroy();
playerBullets.splice(i, 1);
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
// Check if enemy should be removed
if (enemy.shouldRemove) {
enemy.destroy();
enemies.splice(i, 1);
}
}
// Update bosses
for (var i = bosses.length - 1; i >= 0; i--) {
var boss = bosses[i];
// Check if boss should be removed
if (boss.shouldRemove) {
boss.destroy();
bosses.splice(i, 1);
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
// Check if bullet should be removed
if (bullet.shouldRemove) {
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
// Update asteroids
for (var i = asteroids.length - 1; i >= 0; i--) {
var asteroid = asteroids[i];
// Check if asteroid should be removed
if (asteroid.shouldRemove) {
asteroid.destroy();
asteroids.splice(i, 1);
}
}
// Update power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
// Check if power-up should be removed
if (powerUp.shouldRemove) {
powerUp.destroy();
powerUps.splice(i, 1);
}
}
// Update explosions
for (var i = explosions.length - 1; i >= 0; i--) {
var explosion = explosions[i];
// Check if explosion should be removed
if (explosion.shouldRemove) {
explosion.destroy();
explosions.splice(i, 1);
}
}
// Check for collisions
checkCollisions();
// Update UI
updateUI();
};
// Initialize the game
initGame();
unreal engine image side right body view angle space battle ship thunder style. In-Game asset. 2d. High contrast. No shadows
unreal engine image side right body view angle space battle ship samurai vibe In-Game asset. 2d. High contrast. No shadows
unreal engine image side right body view angle space bright black asteroid In-Game asset. 2d. High contrast. No shadows
3d unreal engine image space bright red explosion In-Game asset. 2d. High contrast. No shadows
unreal engine image side right body view angle space battle ship evil samurai vibe In-Game asset. 2d. High contrast. No shadows
space pearl. In-Game asset. 2d. High contrast. No shadows