User prompt
reduce the number of enemies on screen
User prompt
player tap for shoot
User prompt
reduce enemy ship
User prompt
reduce enemy
User prompt
fix player color
User prompt
make smooth control ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
enemy move to left side move and shoot
User prompt
multiple direction shooter bullet from enemy
User prompt
enemy targeting player
User prompt
enemy shoot multi direction
User prompt
make enemy attack player
User prompt
fix enemy
User prompt
fix boss problem
Code edit (1 edits merged)
Please save this source code
User prompt
Cosmic Defender
Initial prompt
side scrolling shooter
/**** * 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