User prompt
Use POWERUP as powerup drops
User prompt
Make a go back to level 1 button under settings
User prompt
Too big asset... i said not too big
User prompt
Make player bullet asset a lot bigger but not too big and make minibosses easier
User prompt
Make controls default to left
User prompt
Remove skip tutorial and play tutorial no matter what
User prompt
Put settings in top right and just do tutorial without skip stuff
User prompt
I meant the skip tutorial button not settings put it back and move skip tutorial button (also it skipped tutorial and I didn't even press it)
User prompt
Put it in top left for that button
User prompt
Instead of skip tutorial in settings what about a button for it during tutorial
User prompt
Make a left hand or right hand selector in a settings tab that pauses game for left or right hand placing for move buttons and other settings. âȘđĄ Consider importing and using the following plugins: @upit/storage.v1
User prompt
Make up/down/left/right buttons bigger
User prompt
Make arrow buttons to move instead of dragging
Code edit (1 edits merged)
Please save this source code
User prompt
Boss Blitz: Escalating Challenge
User prompt
Make bosses after 2 mini-bosses for first 2 levels and then the other ones are bosses. Make bosses and mini-bosswes get harder every time
Initial prompt
Space shooter game
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { currentLevel: 1, maxLevelReached: 1, playerPowerups: {} }); /**** * Classes ****/ var Boss = Container.expand(function (type, level) { var self = Container.call(this); self.type = type || 'miniBoss1'; self.level = level || 1; var bossGraphics = self.attachAsset(self.type, { anchorX: 0.5, anchorY: 0.5 }); // Boss stats scale with level self.health = 100 * self.level; self.maxHealth = self.health; self.speed = 3 + self.level * 0.5; self.shootCooldown = 0; self.shootDelay = Math.max(30 - self.level * 5, 10); // Faster shooting at higher levels self.attackPattern = 0; self.phaseCounter = 0; self.phases = ['entry', 'attack1', 'movement', 'attack2', 'rage']; self.currentPhase = 'entry'; self.phaseTimer = 180; // 3 seconds per phase self.moveDirection = 1; self.targetX = 2048 / 2; self.targetY = 300; // Define movement patterns based on boss type self.patterns = { miniBoss1: { entry: function entry() { if (self.y < self.targetY) { self.y += self.speed; } else { self.changePhase('attack1'); } }, attack1: function attack1() { // Simple straight shots if (self.shootCooldown <= 0) { self.shootBullets(); self.shootCooldown = self.shootDelay; } // Move side to side self.x += self.speed * self.moveDirection; if (self.x > 1800 || self.x < 248) { self.moveDirection *= -1; } }, movement: function movement() { // Circle pattern self.x = self.targetX + Math.cos(self.phaseCounter / 30) * 300; self.y = self.targetY + Math.sin(self.phaseCounter / 30) * 100; }, attack2: function attack2() { // Spread shots if (self.shootCooldown <= 0) { self.shootSpread(5, 0.2); self.shootCooldown = self.shootDelay * 2; } }, rage: function rage() { // Fast movements and frequent attacks self.x += self.speed * 1.5 * self.moveDirection; if (self.x > 1800 || self.x < 248) { self.moveDirection *= -1; } if (self.shootCooldown <= 0) { self.shootSpread(3, 0.3); self.shootCooldown = self.shootDelay / 2; } } }, miniBoss2: { entry: function entry() { if (self.y < self.targetY) { self.y += self.speed; } else { self.changePhase('attack1'); } }, attack1: function attack1() { // Laser attacks if (self.shootCooldown <= 0) { self.shootLaser(); self.shootCooldown = self.shootDelay * 3; } // Slow tracking if (player && self.phaseCounter % 30 === 0) { self.targetX = player.x; } self.x += (self.targetX - self.x) * 0.02; }, movement: function movement() { // Quick dash to one side then the other if (self.phaseCounter < self.phaseTimer / 2) { self.x += self.speed * 2; } else { self.x -= self.speed * 2; } // Keep in bounds self.x = Math.max(200, Math.min(1848, self.x)); }, attack2: function attack2() { // Circular bullet pattern if (self.shootCooldown <= 0) { self.shootCircle(8); self.shootCooldown = self.shootDelay * 2; } }, rage: function rage() { // Erratic movement and mixed attacks self.x = self.targetX + Math.sin(self.phaseCounter / 10) * 300; if (self.shootCooldown <= 0) { if (self.phaseCounter % 120 < 60) { self.shootSpread(7, 0.15); } else { self.shootLaser(); } self.shootCooldown = self.shootDelay; } } }, boss1: { // More complex patterns for main bosses entry: function entry() { if (self.y < self.targetY) { self.y += self.speed; } else { self.changePhase('attack1'); } }, attack1: function attack1() { // Wave pattern with bursts of bullets self.x = self.targetX + Math.sin(self.phaseCounter / 20) * 400; if (self.shootCooldown <= 0) { if (self.phaseCounter % 60 < 30) { self.shootBullets(); } else { self.shootSpread(3, 0.2); } self.shootCooldown = self.shootDelay; } }, movement: function movement() { // Quick charge toward player if (player && self.phaseCounter % 60 === 0) { self.targetX = player.x; self.targetY = player.y - 300; } self.x += (self.targetX - self.x) * 0.05; self.y += (self.targetY - self.y) * 0.05; // Don't get too close to player self.y = Math.min(self.y, 500); }, attack2: function attack2() { // Laser attacks with bullet spray if (self.shootCooldown <= 0) { if (self.phaseCounter % 120 < 60) { self.shootLaser(); } else { self.shootCircle(12); } self.shootCooldown = self.shootDelay * 1.5; } // Slow side-to-side movement self.x += Math.sin(self.phaseCounter / 30) * 5; }, rage: function rage() { // Fast erratic movement with constant attacks self.x = self.targetX + Math.sin(self.phaseCounter / 10) * 300 + Math.cos(self.phaseCounter / 15) * 200; self.y = self.targetY + Math.sin(self.phaseCounter / 12) * 100; if (self.shootCooldown <= 0) { // Alternate between different attack patterns switch (Math.floor(self.phaseCounter / 40) % 3) { case 0: self.shootSpread(5, 0.15); break; case 1: self.shootLaser(); break; case 2: self.shootCircle(8); break; } self.shootCooldown = self.shootDelay * 0.7; } } }, boss2: { // Similar structure, different patterns entry: function entry() { if (self.y < self.targetY) { self.y += self.speed; } else { self.changePhase('attack1'); } }, attack1: function attack1() { // Spiral bullet pattern if (self.shootCooldown <= 0) { self.shootSpiral(self.phaseCounter / 10); self.shootCooldown = Math.max(5, self.shootDelay / 2); } // Slow rotation around center self.x = self.targetX + Math.cos(self.phaseCounter / 60) * 200; self.y = self.targetY + Math.sin(self.phaseCounter / 60) * 100; }, movement: function movement() { // Quick teleport movements if (self.phaseCounter % 60 === 0) { // Flash effect for teleport LK.effects.flashObject(self, 0xFFFFFF, 200); // Choose random position in top third of screen self.targetX = 300 + Math.random() * (2048 - 600); self.targetY = 150 + Math.random() * 250; } // Quick movement to target self.x += (self.targetX - self.x) * 0.1; self.y += (self.targetY - self.y) * 0.1; }, attack2: function attack2() { // Multiple lasers if (self.shootCooldown <= 0) { for (var i = 0; i < 3; i++) { var offset = (i - 1) * 200; self.shootLaser(offset); } self.shootCooldown = self.shootDelay * 2; } // Small jittery movements self.x += (Math.random() - 0.5) * 10; self.y += (Math.random() - 0.5) * 5; // Keep in bounds self.x = Math.max(200, Math.min(1848, self.x)); self.y = Math.max(100, Math.min(500, self.y)); }, rage: function rage() { // Screen-filling attacks and fast movement if (self.shootCooldown <= 0) { // Alternate between massive spreads and laser curtains if (self.phaseCounter % 180 < 90) { self.shootSpread(15, 0.1); } else { for (var i = 0; i < 5; i++) { var offset = (i - 2) * 150; self.shootLaser(offset); } } self.shootCooldown = self.shootDelay * 0.6; } // Aggressive tracking of player if (player) { self.targetX = player.x; self.x += (self.targetX - self.x) * 0.03; } // Vertical bobbing self.y = self.targetY + Math.sin(self.phaseCounter / 20) * 100; } }, boss3: { // More extreme patterns entry: function entry() { if (self.y < self.targetY) { self.y += self.speed; } else { self.changePhase('attack1'); } }, attack1: function attack1() { // 360-degree bullet hell if (self.shootCooldown <= 0) { self.shootCircle(16); self.shootCooldown = self.shootDelay; } // Slow pulsing movement self.x = self.targetX + Math.sin(self.phaseCounter / 30) * 300; self.y = self.targetY + Math.cos(self.phaseCounter / 30) * 100; }, movement: function movement() { // Aggressive dash toward player position then retreat if (self.phaseCounter % 90 < 45 && player) { // Dash toward player self.targetX = player.x; self.targetY = player.y - 150; self.x += (self.targetX - self.x) * 0.08; self.y += (self.targetY - self.y) * 0.08; } else { // Retreat to top self.targetY = 250; self.y += (self.targetY - self.y) * 0.05; } }, attack2: function attack2() { // Multiple attack types simultaneously if (self.shootCooldown <= 0) { // Lasers + bullets combo self.shootLaser(0); self.shootSpread(9, 0.15); self.shootCooldown = self.shootDelay * 1.2; } // Side-to-side sweep self.x += self.speed * 2 * self.moveDirection; if (self.x > 1800 || self.x < 248) { self.moveDirection *= -1; } }, rage: function rage() { // Total bullet hell mode if (self.shootCooldown <= 0) { // Spiral + lasers + directed shots self.shootSpiral(self.phaseCounter / 5); if (self.phaseCounter % 60 === 0) { // Multiple lasers in fan pattern for (var i = -2; i <= 2; i++) { self.shootLaser(i * 120); } } // Direct shots at player if (player && self.phaseCounter % 30 === 0) { self.shootAtPlayer(); } self.shootCooldown = Math.max(3, self.shootDelay / 3); } // Chaotic movement self.x = self.targetX + Math.sin(self.phaseCounter / 10) * 400 + Math.cos(self.phaseCounter / 7) * 200; self.y = self.targetY + Math.sin(self.phaseCounter / 8) * 150; } } }; // Shooting methods self.shootBullets = function () { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y + 50; bullet.angle = Math.PI / 2; // Straight down bullets.push(bullet); game.addChild(bullet); }; self.shootSpread = function (count, spreadAngle) { var startAngle = Math.PI / 2 - spreadAngle * (count - 1) / 2; for (var i = 0; i < count; i++) { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y + 50; bullet.angle = startAngle + spreadAngle * i; bullets.push(bullet); game.addChild(bullet); } }; self.shootCircle = function (count) { var angleStep = Math.PI * 2 / count; for (var i = 0; i < count; i++) { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.angle = angleStep * i; bullets.push(bullet); game.addChild(bullet); } }; self.shootSpiral = function (baseAngle) { var count = 8; var angleStep = Math.PI * 2 / count; for (var i = 0; i < count; i++) { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.angle = baseAngle + angleStep * i; bullets.push(bullet); game.addChild(bullet); } }; self.shootLaser = function (xOffset) { xOffset = xOffset || 0; var laser = new EnemyLaser(); laser.x = self.x + xOffset; laser.y = self.y; lasers.push(laser); game.addChild(laser); }; self.shootAtPlayer = function () { if (!player) return; var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y + 50; // Calculate angle to player var dx = player.x - self.x; var dy = player.y - self.y; bullet.angle = Math.atan2(dy, dx); bullets.push(bullet); game.addChild(bullet); }; self.changePhase = function (newPhase) { self.currentPhase = newPhase; self.phaseCounter = 0; // Adjust phase timer based on phase if (newPhase === 'rage') { self.phaseTimer = 360; // Longer rage phase } else { self.phaseTimer = 180; // Normal phases } }; self.takeDamage = function (damage) { self.health -= damage; // Flash boss when hit LK.effects.flashObject(bossGraphics, 0xFFFFFF, 200); LK.getSound('bossHit').play(); // Check for phase change based on health percentage var healthPercent = self.health / self.maxHealth; if (healthPercent <= 0.25 && self.currentPhase !== 'rage') { self.changePhase('rage'); } else if (healthPercent <= 0.5 && self.currentPhase !== 'rage' && self.currentPhase !== 'attack2') { self.changePhase('attack2'); } else if (healthPercent <= 0.75 && self.currentPhase !== 'rage' && self.currentPhase !== 'attack2' && self.currentPhase !== 'movement') { self.changePhase('movement'); } return self.health <= 0; }; self.update = function () { // Update based on current phase if (self.patterns[self.type] && self.patterns[self.type][self.currentPhase]) { self.patterns[self.type][self.currentPhase](); } // Update counters self.phaseCounter++; if (self.shootCooldown > 0) { self.shootCooldown--; } // Check for phase timeout if (self.phaseCounter >= self.phaseTimer && self.currentPhase !== 'rage' && self.health > self.maxHealth * 0.25) { // Cycle to next phase var currentPhaseIndex = self.phases.indexOf(self.currentPhase); var nextPhaseIndex = (currentPhaseIndex + 1) % (self.phases.length - 1); // Skip rage phase self.changePhase(self.phases[nextPhaseIndex]); } }; return self; }); var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.damage = 1; self.angle = 0; // Direction in radians self.update = function () { self.x += Math.cos(self.angle) * self.speed; self.y += Math.sin(self.angle) * self.speed; // Remove if off screen if (self.y > 2732 + 50 || self.y < -50 || self.x > 2048 + 50 || self.x < -50) { self.shouldRemove = true; } }; return self; }); var EnemyLaser = Container.expand(function () { var self = Container.call(this); var laserGraphics = self.attachAsset('enemyLaser', { anchorX: 0.5, anchorY: 0 }); self.damage = 2; self.duration = 120; // 2 seconds at 60fps self.counter = 0; self.warningCounter = 60; // 1 second warning // Start with low alpha for warning laserGraphics.alpha = 0.3; self.update = function () { self.counter++; if (self.counter < self.warningCounter) { // Warning phase if (self.counter % 10 < 5) { laserGraphics.alpha = 0.5; } else { laserGraphics.alpha = 0.3; } } else if (self.counter === self.warningCounter) { // Activate laser laserGraphics.alpha = 0.8; // Expand width tween(laserGraphics, { width: 80 }, { duration: 100 }); } else if (self.counter >= self.duration) { // Remove laser self.shouldRemove = true; } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; self.shootCooldown = 0; self.shootDelay = 15; // 4 shots per second self.health = 100; self.maxHealth = 100; self.invincible = false; self.invincibleTimer = 0; self.shield = null; self.powerups = {}; // Initialize shield (hidden at first) self.createShield = function () { if (self.shield) return; self.shield = self.attachAsset('playerShield', { anchorX: 0.5, anchorY: 0.5 }); self.shield.alpha = 0; }; self.activateShield = function (duration) { if (!self.shield) self.createShield(); self.shield.alpha = 0.7; self.invincible = true; // Fade out shield over duration tween(self.shield, { alpha: 0 }, { duration: duration, onFinish: function onFinish() { self.invincible = false; } }); }; self.takeDamage = function (damage) { if (self.invincible) return false; self.health -= damage; if (self.health <= 0) { self.health = 0; return true; // Player died } // Flash player and make invincible briefly LK.effects.flashObject(playerGraphics, 0xFF0000, 500); self.invincible = true; self.invincibleTimer = 60; // 1 second invincibility LK.getSound('playerHit').play(); return false; // Player alive }; self.shoot = function () { if (self.shootCooldown > 0) return null; var bullet = new PlayerBullet(); bullet.x = self.x; bullet.y = self.y - 40; // Apply powerups if (self.powerups.doubleDamage) { bullet.damage *= 2; bullet.tint = 0xFFFF00; // Yellow for double damage } // Triple shot powerup if (self.powerups.tripleShot) { // Create two additional bullets var bulletLeft = new PlayerBullet(); bulletLeft.x = self.x - 30; bulletLeft.y = self.y - 20; var bulletRight = new PlayerBullet(); bulletRight.x = self.x + 30; bulletRight.y = self.y - 20; self.shootCooldown = self.shootDelay; LK.getSound('playerShoot').play(); return [bullet, bulletLeft, bulletRight]; } self.shootCooldown = self.shootDelay; LK.getSound('playerShoot').play(); return [bullet]; }; self.update = function () { if (self.shootCooldown > 0) { self.shootCooldown--; } if (self.invincible && self.invincibleTimer > 0) { self.invincibleTimer--; if (self.invincibleTimer <= 0) { self.invincible = false; } } }; self.down = function (x, y, obj) { // This is handled in the game's touch handler }; self.up = function (x, y, obj) { // This is handled in the game's touch handler }; self.createShield(); return self; }); var PlayerBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 15; self.damage = 1; self.update = function () { self.y -= self.speed; // Remove if off screen if (self.y < -50) { self.shouldRemove = true; } }; return self; }); var PowerUp = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'shield'; var color; switch (self.type) { case 'shield': color = 0x00FFFF; break; case 'doubleDamage': color = 0xFFFF00; break; case 'tripleShot': color = 0xFF00FF; break; default: color = 0xFFFFFF; } var powerupGraphics = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2 }); // Set color based on powerup type powerupGraphics.tint = color; self.speed = 3; self.duration = type === 'shield' ? 300 : 600; // Shield lasts 5 seconds, others 10 self.update = function () { self.y += self.speed; // Remove if off screen if (self.y > 2732 + 50) { self.shouldRemove = true; } }; self.applyEffect = function (player) { LK.getSound('powerUp').play(); switch (self.type) { case 'shield': player.activateShield(5000); // 5 seconds break; case 'doubleDamage': player.powerups.doubleDamage = true; // Clear previous timeout if exists if (player.powerups.doubleDamageTimer) { LK.clearTimeout(player.powerups.doubleDamageTimer); } // Set timeout to clear powerup player.powerups.doubleDamageTimer = LK.setTimeout(function () { player.powerups.doubleDamage = false; }, 10000); // 10 seconds break; case 'tripleShot': player.powerups.tripleShot = true; // Clear previous timeout if exists if (player.powerups.tripleShotTimer) { LK.clearTimeout(player.powerups.tripleShotTimer); } // Set timeout to clear powerup player.powerups.tripleShotTimer = LK.setTimeout(function () { player.powerups.tripleShot = false; }, 10000); // 10 seconds break; } self.shouldRemove = true; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Background music // Sound effects // Health bars and UI // Boss projectiles // Main bosses // Mini bosses // Player, bosses, projectiles, UI elements, and effects // Core game variables var player; var currentBoss; var bullets = []; var lasers = []; var playerBullets = []; var powerups = []; var currentLevel = storage.currentLevel || 1; var gameState = 'tutorial'; // tutorial, playing, bossDead, gameOver var tutorialStep = 0; var lastShootTime = 0; var dragNode = null; // UI Elements var scoreText; var levelText; var playerHealthBar; var playerHealthBarBg; var bossHealthBar; var bossHealthBarBg; var tutorialText; // Initialize game function initGame() { // Background game.setBackgroundColor(0x111133); // Create player player = new Player(); player.x = 2048 / 2; player.y = 2732 - 200; game.addChild(player); // Initialize UI createUI(); // Start with tutorial if first level if (currentLevel === 1 && !storage.skipTutorial) { showTutorial(); } else { startLevel(); } // Play background music LK.playMusic('battleMusic'); } function createUI() { // Score and level display scoreText = new Text2('SCORE: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0, 0); LK.gui.top.addChild(scoreText); scoreText.x = 150; scoreText.y = 30; levelText = new Text2('LEVEL ' + currentLevel, { size: 60, fill: 0xFFFFFF }); levelText.anchor.set(1, 0); LK.gui.topRight.addChild(levelText); levelText.x = -50; levelText.y = 30; // Player health bar playerHealthBarBg = LK.getAsset('healthBarBackground', { anchorX: 0, anchorY: 0.5 }); playerHealthBar = LK.getAsset('healthBar', { anchorX: 0, anchorY: 0.5 }); playerHealthBarBg.x = 50; playerHealthBarBg.y = 100; playerHealthBar.x = 50; playerHealthBar.y = 100; game.addChild(playerHealthBarBg); game.addChild(playerHealthBar); // Boss health bar (hidden initially) bossHealthBarBg = LK.getAsset('bossHealthBarBackground', { anchorX: 0.5, anchorY: 0.5 }); bossHealthBar = LK.getAsset('bossHealthBar', { anchorX: 0, anchorY: 0.5 }); bossHealthBarBg.x = 2048 / 2; bossHealthBarBg.y = 50; bossHealthBar.x = 2048 / 2 - bossHealthBarBg.width / 2; bossHealthBar.y = 50; bossHealthBarBg.visible = false; bossHealthBar.visible = false; game.addChild(bossHealthBarBg); game.addChild(bossHealthBar); // Tutorial text (hidden initially) tutorialText = new Text2('', { size: 70, fill: 0xFFFFFF }); tutorialText.anchor.set(0.5, 0.5); tutorialText.x = 2048 / 2; tutorialText.y = 2732 / 2; tutorialText.visible = false; game.addChild(tutorialText); } function showTutorial() { gameState = 'tutorial'; tutorialText.visible = true; var tutorialMessages = ["Welcome to Boss Blitz!\n\nDrag to move your ship.", "Tap anywhere to shoot.\n\nDestroy the bosses to progress.", "Collect power-ups dropped by bosses\nto gain special abilities.", "Survive long enough to defeat\nall boss levels.", "Good luck!\n\nTap to begin..."]; tutorialText.setText(tutorialMessages[tutorialStep]); // Make tutorial text pulsate tween(tutorialText, { alpha: 0.7 }, { duration: 1000, easing: tween.sinceOut, onFinish: function onFinish() { tween(tutorialText, { alpha: 1 }, { duration: 1000, easing: tween.sinceIn }); } }); } function advanceTutorial() { tutorialStep++; if (tutorialStep >= 5) { // End tutorial tutorialText.visible = false; startLevel(); } else { showTutorial(); } } function startLevel() { gameState = 'playing'; // Reset player position player.x = 2048 / 2; player.y = 2732 - 200; // Clear any existing projectiles clearProjectiles(); // Create boss based on current level var bossType; if (currentLevel === 1) { bossType = 'miniBoss1'; } else if (currentLevel === 2) { bossType = 'miniBoss2'; } else if (currentLevel === 3) { bossType = 'boss1'; } else if (currentLevel === 4) { bossType = 'boss2'; } else { bossType = 'boss3'; } currentBoss = new Boss(bossType, currentLevel); currentBoss.x = 2048 / 2; currentBoss.y = -200; // Start above screen game.addChild(currentBoss); // Show boss health bar bossHealthBarBg.visible = true; bossHealthBar.visible = true; // Update UI updateScore(); levelText.setText('LEVEL ' + currentLevel); } function updateScore() { scoreText.setText('SCORE: ' + LK.getScore()); } function clearProjectiles() { // Remove all bullets, lasers, and powerups bullets.forEach(function (bullet) { bullet.parent.removeChild(bullet); }); bullets = []; lasers.forEach(function (laser) { laser.parent.removeChild(laser); }); lasers = []; playerBullets.forEach(function (bullet) { bullet.parent.removeChild(bullet); }); playerBullets = []; powerups.forEach(function (powerup) { powerup.parent.removeChild(powerup); }); powerups = []; } function checkCollisions() { // Player bullets hitting boss for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; if (bullet.intersects(currentBoss)) { // Boss hit var bossDead = currentBoss.takeDamage(bullet.damage); // Remove bullet bullet.parent.removeChild(bullet); playerBullets.splice(i, 1); // Update boss health bar updateBossHealthBar(); // Check if boss defeated if (bossDead) { handleBossDefeat(); } } } // Enemy bullets hitting player for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; if (bullet.intersects(player)) { // Player hit var playerDied = player.takeDamage(bullet.damage); // Remove bullet bullet.parent.removeChild(bullet); bullets.splice(i, 1); // Update health bar updatePlayerHealthBar(); // Check if player died if (playerDied) { handlePlayerDefeat(); } } } // Lasers hitting player for (var i = lasers.length - 1; i >= 0; i--) { var laser = lasers[i]; // Only check active lasers (not in warning phase) if (laser.counter >= laser.warningCounter && laser.intersects(player)) { // Player hit var playerDied = player.takeDamage(laser.damage); // Update health bar updatePlayerHealthBar(); // Check if player died if (playerDied) { handlePlayerDefeat(); } // Don't remove laser on hit, it persists } } // Power-ups being collected by player for (var i = powerups.length - 1; i >= 0; i--) { var powerup = powerups[i]; if (powerup.intersects(player)) { // Apply powerup effect powerup.applyEffect(player); // Remove powerup powerup.parent.removeChild(powerup); powerups.splice(i, 1); } } } function updatePlayerHealthBar() { // Update width of health bar based on player health percentage var healthPercent = player.health / player.maxHealth; playerHealthBar.width = playerHealthBarBg.width * healthPercent; // Change color based on health remaining if (healthPercent > 0.6) { playerHealthBar.tint = 0x34A853; // Green } else if (healthPercent > 0.3) { playerHealthBar.tint = 0xFBBC05; // Yellow } else { playerHealthBar.tint = 0xEA4335; // Red } } function updateBossHealthBar() { // Update width of health bar based on boss health percentage var healthPercent = currentBoss.health / currentBoss.maxHealth; bossHealthBar.width = bossHealthBarBg.width * healthPercent; // Change color based on health remaining if (healthPercent > 0.6) { bossHealthBar.tint = 0xEA4335; // Red } else if (healthPercent > 0.3) { bossHealthBar.tint = 0xFF5733; // Orange } else { bossHealthBar.tint = 0xC70039; // Dark red } } function handleBossDefeat() { gameState = 'bossDead'; // Play defeat sound LK.getSound('bossDefeat').play(); // Flash screen LK.effects.flashScreen(0xFFFFFF, 500); // Create explosion effect at boss position LK.effects.flashObject(currentBoss, 0xFFFFFF, 1000); LK.getSound('explosion').play(); // Remove boss LK.setTimeout(function () { game.removeChild(currentBoss); currentBoss = null; // Hide boss health bar bossHealthBarBg.visible = false; bossHealthBar.visible = false; // Spawn powerups spawnPowerups(); // Award score based on level var scoreIncrease = currentLevel * 1000; LK.setScore(LK.getScore() + scoreIncrease); updateScore(); // Show level complete message tutorialText.setText("LEVEL " + currentLevel + " COMPLETE!\n\nTap to continue..."); tutorialText.visible = true; // Make text appear with effect tutorialText.alpha = 0; tween(tutorialText, { alpha: 1 }, { duration: 500, easing: tween.easeOut }); }, 1000); } function spawnPowerups() { // Spawn 1-3 random powerups var count = Math.floor(Math.random() * 3) + 1; var types = ['shield', 'doubleDamage', 'tripleShot']; for (var i = 0; i < count; i++) { var type = types[Math.floor(Math.random() * types.length)]; var powerup = new PowerUp(type); // Position near where boss was defeated powerup.x = 2048 / 2 + (Math.random() * 400 - 200); powerup.y = 300 + (Math.random() * 200 - 100); game.addChild(powerup); powerups.push(powerup); } } function advanceToNextLevel() { currentLevel++; storage.currentLevel = currentLevel; // Update max level reached if (currentLevel > storage.maxLevelReached) { storage.maxLevelReached = currentLevel; } // Hide tutorial text tutorialText.visible = false; // Start new level startLevel(); } function handlePlayerDefeat() { gameState = 'gameOver'; // Play explosion LK.getSound('explosion').play(); // Flash screen red LK.effects.flashScreen(0xFF0000, 1000); // Show game over message LK.setTimeout(function () { LK.showGameOver(); }, 1500); } function playerShoot() { if (gameState !== 'playing') return; var bullets = player.shoot(); if (bullets) { bullets.forEach(function (bullet) { game.addChild(bullet); playerBullets.push(bullet); }); } } // Event handlers function handleDown(x, y, obj) { // Handle tutorial advancement if (gameState === 'tutorial') { advanceTutorial(); return; } // Handle level advancement after boss defeat if (gameState === 'bossDead' && tutorialText.visible) { advanceToNextLevel(); return; } // Start dragging player if (gameState === 'playing') { // Check if click is on player if (obj === player || player.intersects(obj)) { dragNode = player; } else { // Shoot when clicking elsewhere playerShoot(); } } } function handleMove(x, y, obj) { if (dragNode && gameState === 'playing') { // Move player, keeping within screen bounds dragNode.x = Math.max(50, Math.min(2048 - 50, x)); dragNode.y = Math.max(100, Math.min(2732 - 100, y)); } } function handleUp(x, y, obj) { dragNode = null; } game.down = handleDown; game.move = handleMove; game.up = handleUp; // Main game loop game.update = function () { // Skip updates for non-playing states if (gameState === 'tutorial' || gameState === 'gameOver') { return; } // Auto-shoot for player if (gameState === 'playing' && LK.ticks % 30 === 0) { playerShoot(); } // Update player player.update(); // Update boss if (currentBoss && gameState === 'playing') { currentBoss.update(); } // Update projectiles for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; bullet.update(); if (bullet.shouldRemove) { bullet.parent.removeChild(bullet); playerBullets.splice(i, 1); } } for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; bullet.update(); if (bullet.shouldRemove) { bullet.parent.removeChild(bullet); bullets.splice(i, 1); } } for (var i = lasers.length - 1; i >= 0; i--) { var laser = lasers[i]; laser.update(); if (laser.shouldRemove) { laser.parent.removeChild(laser); lasers.splice(i, 1); } } for (var i = powerups.length - 1; i >= 0; i--) { var powerup = powerups[i]; powerup.update(); if (powerup.shouldRemove) { powerup.parent.removeChild(powerup); powerups.splice(i, 1); } } // Check for collisions if (gameState === 'playing') { checkCollisions(); } // Update UI elements updatePlayerHealthBar(); if (currentBoss) { updateBossHealthBar(); } }; // Initialize game initGame();
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,1157 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1", {
+ currentLevel: 1,
+ maxLevelReached: 1,
+ playerPowerups: {}
+});
+
+/****
+* Classes
+****/
+var Boss = Container.expand(function (type, level) {
+ var self = Container.call(this);
+ self.type = type || 'miniBoss1';
+ self.level = level || 1;
+ var bossGraphics = self.attachAsset(self.type, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Boss stats scale with level
+ self.health = 100 * self.level;
+ self.maxHealth = self.health;
+ self.speed = 3 + self.level * 0.5;
+ self.shootCooldown = 0;
+ self.shootDelay = Math.max(30 - self.level * 5, 10); // Faster shooting at higher levels
+ self.attackPattern = 0;
+ self.phaseCounter = 0;
+ self.phases = ['entry', 'attack1', 'movement', 'attack2', 'rage'];
+ self.currentPhase = 'entry';
+ self.phaseTimer = 180; // 3 seconds per phase
+ self.moveDirection = 1;
+ self.targetX = 2048 / 2;
+ self.targetY = 300;
+ // Define movement patterns based on boss type
+ self.patterns = {
+ miniBoss1: {
+ entry: function entry() {
+ if (self.y < self.targetY) {
+ self.y += self.speed;
+ } else {
+ self.changePhase('attack1');
+ }
+ },
+ attack1: function attack1() {
+ // Simple straight shots
+ if (self.shootCooldown <= 0) {
+ self.shootBullets();
+ self.shootCooldown = self.shootDelay;
+ }
+ // Move side to side
+ self.x += self.speed * self.moveDirection;
+ if (self.x > 1800 || self.x < 248) {
+ self.moveDirection *= -1;
+ }
+ },
+ movement: function movement() {
+ // Circle pattern
+ self.x = self.targetX + Math.cos(self.phaseCounter / 30) * 300;
+ self.y = self.targetY + Math.sin(self.phaseCounter / 30) * 100;
+ },
+ attack2: function attack2() {
+ // Spread shots
+ if (self.shootCooldown <= 0) {
+ self.shootSpread(5, 0.2);
+ self.shootCooldown = self.shootDelay * 2;
+ }
+ },
+ rage: function rage() {
+ // Fast movements and frequent attacks
+ self.x += self.speed * 1.5 * self.moveDirection;
+ if (self.x > 1800 || self.x < 248) {
+ self.moveDirection *= -1;
+ }
+ if (self.shootCooldown <= 0) {
+ self.shootSpread(3, 0.3);
+ self.shootCooldown = self.shootDelay / 2;
+ }
+ }
+ },
+ miniBoss2: {
+ entry: function entry() {
+ if (self.y < self.targetY) {
+ self.y += self.speed;
+ } else {
+ self.changePhase('attack1');
+ }
+ },
+ attack1: function attack1() {
+ // Laser attacks
+ if (self.shootCooldown <= 0) {
+ self.shootLaser();
+ self.shootCooldown = self.shootDelay * 3;
+ }
+ // Slow tracking
+ if (player && self.phaseCounter % 30 === 0) {
+ self.targetX = player.x;
+ }
+ self.x += (self.targetX - self.x) * 0.02;
+ },
+ movement: function movement() {
+ // Quick dash to one side then the other
+ if (self.phaseCounter < self.phaseTimer / 2) {
+ self.x += self.speed * 2;
+ } else {
+ self.x -= self.speed * 2;
+ }
+ // Keep in bounds
+ self.x = Math.max(200, Math.min(1848, self.x));
+ },
+ attack2: function attack2() {
+ // Circular bullet pattern
+ if (self.shootCooldown <= 0) {
+ self.shootCircle(8);
+ self.shootCooldown = self.shootDelay * 2;
+ }
+ },
+ rage: function rage() {
+ // Erratic movement and mixed attacks
+ self.x = self.targetX + Math.sin(self.phaseCounter / 10) * 300;
+ if (self.shootCooldown <= 0) {
+ if (self.phaseCounter % 120 < 60) {
+ self.shootSpread(7, 0.15);
+ } else {
+ self.shootLaser();
+ }
+ self.shootCooldown = self.shootDelay;
+ }
+ }
+ },
+ boss1: {
+ // More complex patterns for main bosses
+ entry: function entry() {
+ if (self.y < self.targetY) {
+ self.y += self.speed;
+ } else {
+ self.changePhase('attack1');
+ }
+ },
+ attack1: function attack1() {
+ // Wave pattern with bursts of bullets
+ self.x = self.targetX + Math.sin(self.phaseCounter / 20) * 400;
+ if (self.shootCooldown <= 0) {
+ if (self.phaseCounter % 60 < 30) {
+ self.shootBullets();
+ } else {
+ self.shootSpread(3, 0.2);
+ }
+ self.shootCooldown = self.shootDelay;
+ }
+ },
+ movement: function movement() {
+ // Quick charge toward player
+ if (player && self.phaseCounter % 60 === 0) {
+ self.targetX = player.x;
+ self.targetY = player.y - 300;
+ }
+ self.x += (self.targetX - self.x) * 0.05;
+ self.y += (self.targetY - self.y) * 0.05;
+ // Don't get too close to player
+ self.y = Math.min(self.y, 500);
+ },
+ attack2: function attack2() {
+ // Laser attacks with bullet spray
+ if (self.shootCooldown <= 0) {
+ if (self.phaseCounter % 120 < 60) {
+ self.shootLaser();
+ } else {
+ self.shootCircle(12);
+ }
+ self.shootCooldown = self.shootDelay * 1.5;
+ }
+ // Slow side-to-side movement
+ self.x += Math.sin(self.phaseCounter / 30) * 5;
+ },
+ rage: function rage() {
+ // Fast erratic movement with constant attacks
+ self.x = self.targetX + Math.sin(self.phaseCounter / 10) * 300 + Math.cos(self.phaseCounter / 15) * 200;
+ self.y = self.targetY + Math.sin(self.phaseCounter / 12) * 100;
+ if (self.shootCooldown <= 0) {
+ // Alternate between different attack patterns
+ switch (Math.floor(self.phaseCounter / 40) % 3) {
+ case 0:
+ self.shootSpread(5, 0.15);
+ break;
+ case 1:
+ self.shootLaser();
+ break;
+ case 2:
+ self.shootCircle(8);
+ break;
+ }
+ self.shootCooldown = self.shootDelay * 0.7;
+ }
+ }
+ },
+ boss2: {
+ // Similar structure, different patterns
+ entry: function entry() {
+ if (self.y < self.targetY) {
+ self.y += self.speed;
+ } else {
+ self.changePhase('attack1');
+ }
+ },
+ attack1: function attack1() {
+ // Spiral bullet pattern
+ if (self.shootCooldown <= 0) {
+ self.shootSpiral(self.phaseCounter / 10);
+ self.shootCooldown = Math.max(5, self.shootDelay / 2);
+ }
+ // Slow rotation around center
+ self.x = self.targetX + Math.cos(self.phaseCounter / 60) * 200;
+ self.y = self.targetY + Math.sin(self.phaseCounter / 60) * 100;
+ },
+ movement: function movement() {
+ // Quick teleport movements
+ if (self.phaseCounter % 60 === 0) {
+ // Flash effect for teleport
+ LK.effects.flashObject(self, 0xFFFFFF, 200);
+ // Choose random position in top third of screen
+ self.targetX = 300 + Math.random() * (2048 - 600);
+ self.targetY = 150 + Math.random() * 250;
+ }
+ // Quick movement to target
+ self.x += (self.targetX - self.x) * 0.1;
+ self.y += (self.targetY - self.y) * 0.1;
+ },
+ attack2: function attack2() {
+ // Multiple lasers
+ if (self.shootCooldown <= 0) {
+ for (var i = 0; i < 3; i++) {
+ var offset = (i - 1) * 200;
+ self.shootLaser(offset);
+ }
+ self.shootCooldown = self.shootDelay * 2;
+ }
+ // Small jittery movements
+ self.x += (Math.random() - 0.5) * 10;
+ self.y += (Math.random() - 0.5) * 5;
+ // Keep in bounds
+ self.x = Math.max(200, Math.min(1848, self.x));
+ self.y = Math.max(100, Math.min(500, self.y));
+ },
+ rage: function rage() {
+ // Screen-filling attacks and fast movement
+ if (self.shootCooldown <= 0) {
+ // Alternate between massive spreads and laser curtains
+ if (self.phaseCounter % 180 < 90) {
+ self.shootSpread(15, 0.1);
+ } else {
+ for (var i = 0; i < 5; i++) {
+ var offset = (i - 2) * 150;
+ self.shootLaser(offset);
+ }
+ }
+ self.shootCooldown = self.shootDelay * 0.6;
+ }
+ // Aggressive tracking of player
+ if (player) {
+ self.targetX = player.x;
+ self.x += (self.targetX - self.x) * 0.03;
+ }
+ // Vertical bobbing
+ self.y = self.targetY + Math.sin(self.phaseCounter / 20) * 100;
+ }
+ },
+ boss3: {
+ // More extreme patterns
+ entry: function entry() {
+ if (self.y < self.targetY) {
+ self.y += self.speed;
+ } else {
+ self.changePhase('attack1');
+ }
+ },
+ attack1: function attack1() {
+ // 360-degree bullet hell
+ if (self.shootCooldown <= 0) {
+ self.shootCircle(16);
+ self.shootCooldown = self.shootDelay;
+ }
+ // Slow pulsing movement
+ self.x = self.targetX + Math.sin(self.phaseCounter / 30) * 300;
+ self.y = self.targetY + Math.cos(self.phaseCounter / 30) * 100;
+ },
+ movement: function movement() {
+ // Aggressive dash toward player position then retreat
+ if (self.phaseCounter % 90 < 45 && player) {
+ // Dash toward player
+ self.targetX = player.x;
+ self.targetY = player.y - 150;
+ self.x += (self.targetX - self.x) * 0.08;
+ self.y += (self.targetY - self.y) * 0.08;
+ } else {
+ // Retreat to top
+ self.targetY = 250;
+ self.y += (self.targetY - self.y) * 0.05;
+ }
+ },
+ attack2: function attack2() {
+ // Multiple attack types simultaneously
+ if (self.shootCooldown <= 0) {
+ // Lasers + bullets combo
+ self.shootLaser(0);
+ self.shootSpread(9, 0.15);
+ self.shootCooldown = self.shootDelay * 1.2;
+ }
+ // Side-to-side sweep
+ self.x += self.speed * 2 * self.moveDirection;
+ if (self.x > 1800 || self.x < 248) {
+ self.moveDirection *= -1;
+ }
+ },
+ rage: function rage() {
+ // Total bullet hell mode
+ if (self.shootCooldown <= 0) {
+ // Spiral + lasers + directed shots
+ self.shootSpiral(self.phaseCounter / 5);
+ if (self.phaseCounter % 60 === 0) {
+ // Multiple lasers in fan pattern
+ for (var i = -2; i <= 2; i++) {
+ self.shootLaser(i * 120);
+ }
+ }
+ // Direct shots at player
+ if (player && self.phaseCounter % 30 === 0) {
+ self.shootAtPlayer();
+ }
+ self.shootCooldown = Math.max(3, self.shootDelay / 3);
+ }
+ // Chaotic movement
+ self.x = self.targetX + Math.sin(self.phaseCounter / 10) * 400 + Math.cos(self.phaseCounter / 7) * 200;
+ self.y = self.targetY + Math.sin(self.phaseCounter / 8) * 150;
+ }
+ }
+ };
+ // Shooting methods
+ self.shootBullets = function () {
+ var bullet = new EnemyBullet();
+ bullet.x = self.x;
+ bullet.y = self.y + 50;
+ bullet.angle = Math.PI / 2; // Straight down
+ bullets.push(bullet);
+ game.addChild(bullet);
+ };
+ self.shootSpread = function (count, spreadAngle) {
+ var startAngle = Math.PI / 2 - spreadAngle * (count - 1) / 2;
+ for (var i = 0; i < count; i++) {
+ var bullet = new EnemyBullet();
+ bullet.x = self.x;
+ bullet.y = self.y + 50;
+ bullet.angle = startAngle + spreadAngle * i;
+ bullets.push(bullet);
+ game.addChild(bullet);
+ }
+ };
+ self.shootCircle = function (count) {
+ var angleStep = Math.PI * 2 / count;
+ for (var i = 0; i < count; i++) {
+ var bullet = new EnemyBullet();
+ bullet.x = self.x;
+ bullet.y = self.y;
+ bullet.angle = angleStep * i;
+ bullets.push(bullet);
+ game.addChild(bullet);
+ }
+ };
+ self.shootSpiral = function (baseAngle) {
+ var count = 8;
+ var angleStep = Math.PI * 2 / count;
+ for (var i = 0; i < count; i++) {
+ var bullet = new EnemyBullet();
+ bullet.x = self.x;
+ bullet.y = self.y;
+ bullet.angle = baseAngle + angleStep * i;
+ bullets.push(bullet);
+ game.addChild(bullet);
+ }
+ };
+ self.shootLaser = function (xOffset) {
+ xOffset = xOffset || 0;
+ var laser = new EnemyLaser();
+ laser.x = self.x + xOffset;
+ laser.y = self.y;
+ lasers.push(laser);
+ game.addChild(laser);
+ };
+ self.shootAtPlayer = function () {
+ if (!player) return;
+ var bullet = new EnemyBullet();
+ bullet.x = self.x;
+ bullet.y = self.y + 50;
+ // Calculate angle to player
+ var dx = player.x - self.x;
+ var dy = player.y - self.y;
+ bullet.angle = Math.atan2(dy, dx);
+ bullets.push(bullet);
+ game.addChild(bullet);
+ };
+ self.changePhase = function (newPhase) {
+ self.currentPhase = newPhase;
+ self.phaseCounter = 0;
+ // Adjust phase timer based on phase
+ if (newPhase === 'rage') {
+ self.phaseTimer = 360; // Longer rage phase
+ } else {
+ self.phaseTimer = 180; // Normal phases
+ }
+ };
+ self.takeDamage = function (damage) {
+ self.health -= damage;
+ // Flash boss when hit
+ LK.effects.flashObject(bossGraphics, 0xFFFFFF, 200);
+ LK.getSound('bossHit').play();
+ // Check for phase change based on health percentage
+ var healthPercent = self.health / self.maxHealth;
+ if (healthPercent <= 0.25 && self.currentPhase !== 'rage') {
+ self.changePhase('rage');
+ } else if (healthPercent <= 0.5 && self.currentPhase !== 'rage' && self.currentPhase !== 'attack2') {
+ self.changePhase('attack2');
+ } else if (healthPercent <= 0.75 && self.currentPhase !== 'rage' && self.currentPhase !== 'attack2' && self.currentPhase !== 'movement') {
+ self.changePhase('movement');
+ }
+ return self.health <= 0;
+ };
+ self.update = function () {
+ // Update based on current phase
+ if (self.patterns[self.type] && self.patterns[self.type][self.currentPhase]) {
+ self.patterns[self.type][self.currentPhase]();
+ }
+ // Update counters
+ self.phaseCounter++;
+ if (self.shootCooldown > 0) {
+ self.shootCooldown--;
+ }
+ // Check for phase timeout
+ if (self.phaseCounter >= self.phaseTimer && self.currentPhase !== 'rage' && self.health > self.maxHealth * 0.25) {
+ // Cycle to next phase
+ var currentPhaseIndex = self.phases.indexOf(self.currentPhase);
+ var nextPhaseIndex = (currentPhaseIndex + 1) % (self.phases.length - 1); // Skip rage phase
+ self.changePhase(self.phases[nextPhaseIndex]);
+ }
+ };
+ return self;
+});
+var EnemyBullet = Container.expand(function () {
+ var self = Container.call(this);
+ var bulletGraphics = self.attachAsset('enemyBullet', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 8;
+ self.damage = 1;
+ self.angle = 0; // Direction in radians
+ self.update = function () {
+ self.x += Math.cos(self.angle) * self.speed;
+ self.y += Math.sin(self.angle) * self.speed;
+ // Remove if off screen
+ if (self.y > 2732 + 50 || self.y < -50 || self.x > 2048 + 50 || self.x < -50) {
+ self.shouldRemove = true;
+ }
+ };
+ return self;
+});
+var EnemyLaser = Container.expand(function () {
+ var self = Container.call(this);
+ var laserGraphics = self.attachAsset('enemyLaser', {
+ anchorX: 0.5,
+ anchorY: 0
+ });
+ self.damage = 2;
+ self.duration = 120; // 2 seconds at 60fps
+ self.counter = 0;
+ self.warningCounter = 60; // 1 second warning
+ // Start with low alpha for warning
+ laserGraphics.alpha = 0.3;
+ self.update = function () {
+ self.counter++;
+ if (self.counter < self.warningCounter) {
+ // Warning phase
+ if (self.counter % 10 < 5) {
+ laserGraphics.alpha = 0.5;
+ } else {
+ laserGraphics.alpha = 0.3;
+ }
+ } else if (self.counter === self.warningCounter) {
+ // Activate laser
+ laserGraphics.alpha = 0.8;
+ // Expand width
+ tween(laserGraphics, {
+ width: 80
+ }, {
+ duration: 100
+ });
+ } else if (self.counter >= self.duration) {
+ // Remove laser
+ self.shouldRemove = true;
+ }
+ };
+ return self;
+});
+var Player = Container.expand(function () {
+ var self = Container.call(this);
+ var playerGraphics = self.attachAsset('player', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 10;
+ self.shootCooldown = 0;
+ self.shootDelay = 15; // 4 shots per second
+ self.health = 100;
+ self.maxHealth = 100;
+ self.invincible = false;
+ self.invincibleTimer = 0;
+ self.shield = null;
+ self.powerups = {};
+ // Initialize shield (hidden at first)
+ self.createShield = function () {
+ if (self.shield) return;
+ self.shield = self.attachAsset('playerShield', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.shield.alpha = 0;
+ };
+ self.activateShield = function (duration) {
+ if (!self.shield) self.createShield();
+ self.shield.alpha = 0.7;
+ self.invincible = true;
+ // Fade out shield over duration
+ tween(self.shield, {
+ alpha: 0
+ }, {
+ duration: duration,
+ onFinish: function onFinish() {
+ self.invincible = false;
+ }
+ });
+ };
+ self.takeDamage = function (damage) {
+ if (self.invincible) return false;
+ self.health -= damage;
+ if (self.health <= 0) {
+ self.health = 0;
+ return true; // Player died
+ }
+ // Flash player and make invincible briefly
+ LK.effects.flashObject(playerGraphics, 0xFF0000, 500);
+ self.invincible = true;
+ self.invincibleTimer = 60; // 1 second invincibility
+ LK.getSound('playerHit').play();
+ return false; // Player alive
+ };
+ self.shoot = function () {
+ if (self.shootCooldown > 0) return null;
+ var bullet = new PlayerBullet();
+ bullet.x = self.x;
+ bullet.y = self.y - 40;
+ // Apply powerups
+ if (self.powerups.doubleDamage) {
+ bullet.damage *= 2;
+ bullet.tint = 0xFFFF00; // Yellow for double damage
+ }
+ // Triple shot powerup
+ if (self.powerups.tripleShot) {
+ // Create two additional bullets
+ var bulletLeft = new PlayerBullet();
+ bulletLeft.x = self.x - 30;
+ bulletLeft.y = self.y - 20;
+ var bulletRight = new PlayerBullet();
+ bulletRight.x = self.x + 30;
+ bulletRight.y = self.y - 20;
+ self.shootCooldown = self.shootDelay;
+ LK.getSound('playerShoot').play();
+ return [bullet, bulletLeft, bulletRight];
+ }
+ self.shootCooldown = self.shootDelay;
+ LK.getSound('playerShoot').play();
+ return [bullet];
+ };
+ self.update = function () {
+ if (self.shootCooldown > 0) {
+ self.shootCooldown--;
+ }
+ if (self.invincible && self.invincibleTimer > 0) {
+ self.invincibleTimer--;
+ if (self.invincibleTimer <= 0) {
+ self.invincible = false;
+ }
+ }
+ };
+ self.down = function (x, y, obj) {
+ // This is handled in the game's touch handler
+ };
+ self.up = function (x, y, obj) {
+ // This is handled in the game's touch handler
+ };
+ self.createShield();
+ return self;
+});
+var PlayerBullet = Container.expand(function () {
+ var self = Container.call(this);
+ var bulletGraphics = self.attachAsset('playerBullet', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 15;
+ self.damage = 1;
+ self.update = function () {
+ self.y -= self.speed;
+ // Remove if off screen
+ if (self.y < -50) {
+ self.shouldRemove = true;
+ }
+ };
+ return self;
+});
+var PowerUp = Container.expand(function (type) {
+ var self = Container.call(this);
+ self.type = type || 'shield';
+ var color;
+ switch (self.type) {
+ case 'shield':
+ color = 0x00FFFF;
+ break;
+ case 'doubleDamage':
+ color = 0xFFFF00;
+ break;
+ case 'tripleShot':
+ color = 0xFF00FF;
+ break;
+ default:
+ color = 0xFFFFFF;
+ }
+ var powerupGraphics = self.attachAsset('playerBullet', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 2,
+ scaleY: 2
+ });
+ // Set color based on powerup type
+ powerupGraphics.tint = color;
+ self.speed = 3;
+ self.duration = type === 'shield' ? 300 : 600; // Shield lasts 5 seconds, others 10
+ self.update = function () {
+ self.y += self.speed;
+ // Remove if off screen
+ if (self.y > 2732 + 50) {
+ self.shouldRemove = true;
+ }
+ };
+ self.applyEffect = function (player) {
+ LK.getSound('powerUp').play();
+ switch (self.type) {
+ case 'shield':
+ player.activateShield(5000); // 5 seconds
+ break;
+ case 'doubleDamage':
+ player.powerups.doubleDamage = true;
+ // Clear previous timeout if exists
+ if (player.powerups.doubleDamageTimer) {
+ LK.clearTimeout(player.powerups.doubleDamageTimer);
+ }
+ // Set timeout to clear powerup
+ player.powerups.doubleDamageTimer = LK.setTimeout(function () {
+ player.powerups.doubleDamage = false;
+ }, 10000); // 10 seconds
+ break;
+ case 'tripleShot':
+ player.powerups.tripleShot = true;
+ // Clear previous timeout if exists
+ if (player.powerups.tripleShotTimer) {
+ LK.clearTimeout(player.powerups.tripleShotTimer);
+ }
+ // Set timeout to clear powerup
+ player.powerups.tripleShotTimer = LK.setTimeout(function () {
+ player.powerups.tripleShot = false;
+ }, 10000); // 10 seconds
+ break;
+ }
+ self.shouldRemove = true;
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
backgroundColor: 0x000000
-});
\ No newline at end of file
+});
+
+/****
+* Game Code
+****/
+// Background music
+// Sound effects
+// Health bars and UI
+// Boss projectiles
+// Main bosses
+// Mini bosses
+// Player, bosses, projectiles, UI elements, and effects
+// Core game variables
+var player;
+var currentBoss;
+var bullets = [];
+var lasers = [];
+var playerBullets = [];
+var powerups = [];
+var currentLevel = storage.currentLevel || 1;
+var gameState = 'tutorial'; // tutorial, playing, bossDead, gameOver
+var tutorialStep = 0;
+var lastShootTime = 0;
+var dragNode = null;
+// UI Elements
+var scoreText;
+var levelText;
+var playerHealthBar;
+var playerHealthBarBg;
+var bossHealthBar;
+var bossHealthBarBg;
+var tutorialText;
+// Initialize game
+function initGame() {
+ // Background
+ game.setBackgroundColor(0x111133);
+ // Create player
+ player = new Player();
+ player.x = 2048 / 2;
+ player.y = 2732 - 200;
+ game.addChild(player);
+ // Initialize UI
+ createUI();
+ // Start with tutorial if first level
+ if (currentLevel === 1 && !storage.skipTutorial) {
+ showTutorial();
+ } else {
+ startLevel();
+ }
+ // Play background music
+ LK.playMusic('battleMusic');
+}
+function createUI() {
+ // Score and level display
+ scoreText = new Text2('SCORE: 0', {
+ size: 60,
+ fill: 0xFFFFFF
+ });
+ scoreText.anchor.set(0, 0);
+ LK.gui.top.addChild(scoreText);
+ scoreText.x = 150;
+ scoreText.y = 30;
+ levelText = new Text2('LEVEL ' + currentLevel, {
+ size: 60,
+ fill: 0xFFFFFF
+ });
+ levelText.anchor.set(1, 0);
+ LK.gui.topRight.addChild(levelText);
+ levelText.x = -50;
+ levelText.y = 30;
+ // Player health bar
+ playerHealthBarBg = LK.getAsset('healthBarBackground', {
+ anchorX: 0,
+ anchorY: 0.5
+ });
+ playerHealthBar = LK.getAsset('healthBar', {
+ anchorX: 0,
+ anchorY: 0.5
+ });
+ playerHealthBarBg.x = 50;
+ playerHealthBarBg.y = 100;
+ playerHealthBar.x = 50;
+ playerHealthBar.y = 100;
+ game.addChild(playerHealthBarBg);
+ game.addChild(playerHealthBar);
+ // Boss health bar (hidden initially)
+ bossHealthBarBg = LK.getAsset('bossHealthBarBackground', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ bossHealthBar = LK.getAsset('bossHealthBar', {
+ anchorX: 0,
+ anchorY: 0.5
+ });
+ bossHealthBarBg.x = 2048 / 2;
+ bossHealthBarBg.y = 50;
+ bossHealthBar.x = 2048 / 2 - bossHealthBarBg.width / 2;
+ bossHealthBar.y = 50;
+ bossHealthBarBg.visible = false;
+ bossHealthBar.visible = false;
+ game.addChild(bossHealthBarBg);
+ game.addChild(bossHealthBar);
+ // Tutorial text (hidden initially)
+ tutorialText = new Text2('', {
+ size: 70,
+ fill: 0xFFFFFF
+ });
+ tutorialText.anchor.set(0.5, 0.5);
+ tutorialText.x = 2048 / 2;
+ tutorialText.y = 2732 / 2;
+ tutorialText.visible = false;
+ game.addChild(tutorialText);
+}
+function showTutorial() {
+ gameState = 'tutorial';
+ tutorialText.visible = true;
+ var tutorialMessages = ["Welcome to Boss Blitz!\n\nDrag to move your ship.", "Tap anywhere to shoot.\n\nDestroy the bosses to progress.", "Collect power-ups dropped by bosses\nto gain special abilities.", "Survive long enough to defeat\nall boss levels.", "Good luck!\n\nTap to begin..."];
+ tutorialText.setText(tutorialMessages[tutorialStep]);
+ // Make tutorial text pulsate
+ tween(tutorialText, {
+ alpha: 0.7
+ }, {
+ duration: 1000,
+ easing: tween.sinceOut,
+ onFinish: function onFinish() {
+ tween(tutorialText, {
+ alpha: 1
+ }, {
+ duration: 1000,
+ easing: tween.sinceIn
+ });
+ }
+ });
+}
+function advanceTutorial() {
+ tutorialStep++;
+ if (tutorialStep >= 5) {
+ // End tutorial
+ tutorialText.visible = false;
+ startLevel();
+ } else {
+ showTutorial();
+ }
+}
+function startLevel() {
+ gameState = 'playing';
+ // Reset player position
+ player.x = 2048 / 2;
+ player.y = 2732 - 200;
+ // Clear any existing projectiles
+ clearProjectiles();
+ // Create boss based on current level
+ var bossType;
+ if (currentLevel === 1) {
+ bossType = 'miniBoss1';
+ } else if (currentLevel === 2) {
+ bossType = 'miniBoss2';
+ } else if (currentLevel === 3) {
+ bossType = 'boss1';
+ } else if (currentLevel === 4) {
+ bossType = 'boss2';
+ } else {
+ bossType = 'boss3';
+ }
+ currentBoss = new Boss(bossType, currentLevel);
+ currentBoss.x = 2048 / 2;
+ currentBoss.y = -200; // Start above screen
+ game.addChild(currentBoss);
+ // Show boss health bar
+ bossHealthBarBg.visible = true;
+ bossHealthBar.visible = true;
+ // Update UI
+ updateScore();
+ levelText.setText('LEVEL ' + currentLevel);
+}
+function updateScore() {
+ scoreText.setText('SCORE: ' + LK.getScore());
+}
+function clearProjectiles() {
+ // Remove all bullets, lasers, and powerups
+ bullets.forEach(function (bullet) {
+ bullet.parent.removeChild(bullet);
+ });
+ bullets = [];
+ lasers.forEach(function (laser) {
+ laser.parent.removeChild(laser);
+ });
+ lasers = [];
+ playerBullets.forEach(function (bullet) {
+ bullet.parent.removeChild(bullet);
+ });
+ playerBullets = [];
+ powerups.forEach(function (powerup) {
+ powerup.parent.removeChild(powerup);
+ });
+ powerups = [];
+}
+function checkCollisions() {
+ // Player bullets hitting boss
+ for (var i = playerBullets.length - 1; i >= 0; i--) {
+ var bullet = playerBullets[i];
+ if (bullet.intersects(currentBoss)) {
+ // Boss hit
+ var bossDead = currentBoss.takeDamage(bullet.damage);
+ // Remove bullet
+ bullet.parent.removeChild(bullet);
+ playerBullets.splice(i, 1);
+ // Update boss health bar
+ updateBossHealthBar();
+ // Check if boss defeated
+ if (bossDead) {
+ handleBossDefeat();
+ }
+ }
+ }
+ // Enemy bullets hitting player
+ for (var i = bullets.length - 1; i >= 0; i--) {
+ var bullet = bullets[i];
+ if (bullet.intersects(player)) {
+ // Player hit
+ var playerDied = player.takeDamage(bullet.damage);
+ // Remove bullet
+ bullet.parent.removeChild(bullet);
+ bullets.splice(i, 1);
+ // Update health bar
+ updatePlayerHealthBar();
+ // Check if player died
+ if (playerDied) {
+ handlePlayerDefeat();
+ }
+ }
+ }
+ // Lasers hitting player
+ for (var i = lasers.length - 1; i >= 0; i--) {
+ var laser = lasers[i];
+ // Only check active lasers (not in warning phase)
+ if (laser.counter >= laser.warningCounter && laser.intersects(player)) {
+ // Player hit
+ var playerDied = player.takeDamage(laser.damage);
+ // Update health bar
+ updatePlayerHealthBar();
+ // Check if player died
+ if (playerDied) {
+ handlePlayerDefeat();
+ }
+ // Don't remove laser on hit, it persists
+ }
+ }
+ // Power-ups being collected by player
+ for (var i = powerups.length - 1; i >= 0; i--) {
+ var powerup = powerups[i];
+ if (powerup.intersects(player)) {
+ // Apply powerup effect
+ powerup.applyEffect(player);
+ // Remove powerup
+ powerup.parent.removeChild(powerup);
+ powerups.splice(i, 1);
+ }
+ }
+}
+function updatePlayerHealthBar() {
+ // Update width of health bar based on player health percentage
+ var healthPercent = player.health / player.maxHealth;
+ playerHealthBar.width = playerHealthBarBg.width * healthPercent;
+ // Change color based on health remaining
+ if (healthPercent > 0.6) {
+ playerHealthBar.tint = 0x34A853; // Green
+ } else if (healthPercent > 0.3) {
+ playerHealthBar.tint = 0xFBBC05; // Yellow
+ } else {
+ playerHealthBar.tint = 0xEA4335; // Red
+ }
+}
+function updateBossHealthBar() {
+ // Update width of health bar based on boss health percentage
+ var healthPercent = currentBoss.health / currentBoss.maxHealth;
+ bossHealthBar.width = bossHealthBarBg.width * healthPercent;
+ // Change color based on health remaining
+ if (healthPercent > 0.6) {
+ bossHealthBar.tint = 0xEA4335; // Red
+ } else if (healthPercent > 0.3) {
+ bossHealthBar.tint = 0xFF5733; // Orange
+ } else {
+ bossHealthBar.tint = 0xC70039; // Dark red
+ }
+}
+function handleBossDefeat() {
+ gameState = 'bossDead';
+ // Play defeat sound
+ LK.getSound('bossDefeat').play();
+ // Flash screen
+ LK.effects.flashScreen(0xFFFFFF, 500);
+ // Create explosion effect at boss position
+ LK.effects.flashObject(currentBoss, 0xFFFFFF, 1000);
+ LK.getSound('explosion').play();
+ // Remove boss
+ LK.setTimeout(function () {
+ game.removeChild(currentBoss);
+ currentBoss = null;
+ // Hide boss health bar
+ bossHealthBarBg.visible = false;
+ bossHealthBar.visible = false;
+ // Spawn powerups
+ spawnPowerups();
+ // Award score based on level
+ var scoreIncrease = currentLevel * 1000;
+ LK.setScore(LK.getScore() + scoreIncrease);
+ updateScore();
+ // Show level complete message
+ tutorialText.setText("LEVEL " + currentLevel + " COMPLETE!\n\nTap to continue...");
+ tutorialText.visible = true;
+ // Make text appear with effect
+ tutorialText.alpha = 0;
+ tween(tutorialText, {
+ alpha: 1
+ }, {
+ duration: 500,
+ easing: tween.easeOut
+ });
+ }, 1000);
+}
+function spawnPowerups() {
+ // Spawn 1-3 random powerups
+ var count = Math.floor(Math.random() * 3) + 1;
+ var types = ['shield', 'doubleDamage', 'tripleShot'];
+ for (var i = 0; i < count; i++) {
+ var type = types[Math.floor(Math.random() * types.length)];
+ var powerup = new PowerUp(type);
+ // Position near where boss was defeated
+ powerup.x = 2048 / 2 + (Math.random() * 400 - 200);
+ powerup.y = 300 + (Math.random() * 200 - 100);
+ game.addChild(powerup);
+ powerups.push(powerup);
+ }
+}
+function advanceToNextLevel() {
+ currentLevel++;
+ storage.currentLevel = currentLevel;
+ // Update max level reached
+ if (currentLevel > storage.maxLevelReached) {
+ storage.maxLevelReached = currentLevel;
+ }
+ // Hide tutorial text
+ tutorialText.visible = false;
+ // Start new level
+ startLevel();
+}
+function handlePlayerDefeat() {
+ gameState = 'gameOver';
+ // Play explosion
+ LK.getSound('explosion').play();
+ // Flash screen red
+ LK.effects.flashScreen(0xFF0000, 1000);
+ // Show game over message
+ LK.setTimeout(function () {
+ LK.showGameOver();
+ }, 1500);
+}
+function playerShoot() {
+ if (gameState !== 'playing') return;
+ var bullets = player.shoot();
+ if (bullets) {
+ bullets.forEach(function (bullet) {
+ game.addChild(bullet);
+ playerBullets.push(bullet);
+ });
+ }
+}
+// Event handlers
+function handleDown(x, y, obj) {
+ // Handle tutorial advancement
+ if (gameState === 'tutorial') {
+ advanceTutorial();
+ return;
+ }
+ // Handle level advancement after boss defeat
+ if (gameState === 'bossDead' && tutorialText.visible) {
+ advanceToNextLevel();
+ return;
+ }
+ // Start dragging player
+ if (gameState === 'playing') {
+ // Check if click is on player
+ if (obj === player || player.intersects(obj)) {
+ dragNode = player;
+ } else {
+ // Shoot when clicking elsewhere
+ playerShoot();
+ }
+ }
+}
+function handleMove(x, y, obj) {
+ if (dragNode && gameState === 'playing') {
+ // Move player, keeping within screen bounds
+ dragNode.x = Math.max(50, Math.min(2048 - 50, x));
+ dragNode.y = Math.max(100, Math.min(2732 - 100, y));
+ }
+}
+function handleUp(x, y, obj) {
+ dragNode = null;
+}
+game.down = handleDown;
+game.move = handleMove;
+game.up = handleUp;
+// Main game loop
+game.update = function () {
+ // Skip updates for non-playing states
+ if (gameState === 'tutorial' || gameState === 'gameOver') {
+ return;
+ }
+ // Auto-shoot for player
+ if (gameState === 'playing' && LK.ticks % 30 === 0) {
+ playerShoot();
+ }
+ // Update player
+ player.update();
+ // Update boss
+ if (currentBoss && gameState === 'playing') {
+ currentBoss.update();
+ }
+ // Update projectiles
+ for (var i = playerBullets.length - 1; i >= 0; i--) {
+ var bullet = playerBullets[i];
+ bullet.update();
+ if (bullet.shouldRemove) {
+ bullet.parent.removeChild(bullet);
+ playerBullets.splice(i, 1);
+ }
+ }
+ for (var i = bullets.length - 1; i >= 0; i--) {
+ var bullet = bullets[i];
+ bullet.update();
+ if (bullet.shouldRemove) {
+ bullet.parent.removeChild(bullet);
+ bullets.splice(i, 1);
+ }
+ }
+ for (var i = lasers.length - 1; i >= 0; i--) {
+ var laser = lasers[i];
+ laser.update();
+ if (laser.shouldRemove) {
+ laser.parent.removeChild(laser);
+ lasers.splice(i, 1);
+ }
+ }
+ for (var i = powerups.length - 1; i >= 0; i--) {
+ var powerup = powerups[i];
+ powerup.update();
+ if (powerup.shouldRemove) {
+ powerup.parent.removeChild(powerup);
+ powerups.splice(i, 1);
+ }
+ }
+ // Check for collisions
+ if (gameState === 'playing') {
+ checkCollisions();
+ }
+ // Update UI elements
+ updatePlayerHealthBar();
+ if (currentBoss) {
+ updateBossHealthBar();
+ }
+};
+// Initialize game
+initGame();
\ No newline at end of file