User prompt
me equivoque, quería decir que la velocidad de recarga aumente, es decir que tarde mas en disparar, de paso quiero que arregles cuando pasas el nivel y te manda al selector de mejora, el personaje sigue disparando
User prompt
bueno, ahora quiero que la velocidad de los disparos del personaje aumente, pero que la velocidad de recarga disminuya, de paso que el personaje dispare automaticamente
User prompt
ahora, con respecto a las estadisticas enemigas, quiero que el pez enemigo de nivel 1 tenga 2 de vida, y que sus disparos causen 1 de daño
User prompt
cuando ya completes un nivel y mates a todos los peces enemigos, quiero que los disparos que aun sigan en la pantalla desaparescan
User prompt
bien, quiero que para la vida, en cada nivel el personaje recupere el maximo de su salud, obviamente aumentando esta conforme elijas la mejora de salud
User prompt
cuando mates a todos los enemigos de la pantalla, que esta se pause para hacerte elegir la mejora, de paso, haz que los enemigos en lugar de simplemente avanzar, que se queden en la zona superior disparando
Code edit (1 edits merged)
Please save this source code
User prompt
Bubble Defense: Ocean Depths
Initial prompt
bien, quiero que el juego trate de un shooter de naves en vertical, en lugar de naves quiero que trate acerca de peces en el oceano, el protagonista es un pequeño pez que se defenderá disparando burbujas que hacen daño a los enemigos, habrá 10 niveles, en los cuales aparecerán cada vez mas enemigos y mas dificiles, en el decimo apareciendo el pez jefe final malvado, los peces enemigos se mantendrán arriba disparando así como el jugador, para hacerlo mas justo, al finalizar cada nivel, el jugador podrá elegir o una mejora para aumentar la salud, o una mejora para aumentar el daño de los disparos del jugador, digamos que inicias teniendo 3 de vida y 1 de daño, cuando elijes la mejora de vida obtienes +2 de vida, y cuando elijes la mejora de daño obtienes +1 de daño
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var BossBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bossBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.damage = 5; self.update = function () { self.y += self.speed; }; return self; }); var BossFish = Container.expand(function () { var self = Container.call(this); var fishGraphics = self.attachAsset('bossFish', { anchorX: 0.5, anchorY: 0.5 }); self.health = 500; self.speed = 2; self.shootCooldown = 30; self.moveDirection = 1; self.attackPattern = 0; // 0: triple shot, 1: spread shot, 2: rapid fire self.attackCooldown = 0; self.pauseCooldown = 0; self.attacksInPattern = 0; self.maxAttacksPerPattern = 5; self.update = function () { self.x += self.speed * self.moveDirection; if (self.x <= 100 || self.x >= 2048 - 100) { self.moveDirection *= -1; } // Handle pauses between attack patterns if (self.pauseCooldown > 0) { self.pauseCooldown--; return; } if (self.shootCooldown > 0) { self.shootCooldown--; } else { self.executeAttackPattern(); self.attacksInPattern++; // Check if we need to switch patterns or pause if (self.attacksInPattern >= self.maxAttacksPerPattern) { self.attacksInPattern = 0; self.attackPattern = (self.attackPattern + 1) % 3; self.pauseCooldown = 90; // 1.5 second pause between patterns } else { // Set cooldown based on attack pattern if (self.attackPattern === 2) { // Rapid fire self.shootCooldown = 10; } else { self.shootCooldown = 25; } } } }; self.executeAttackPattern = function () { if (self.attackPattern === 0) { // Pattern 1: Triple shot (original) for (var i = 0; i < 3; i++) { var bullet = new BossBullet(); bullet.x = self.x + (i - 1) * 50; bullet.y = self.y + 70; enemyBullets.push(bullet); game.addChild(bullet); } } else if (self.attackPattern === 1) { // Pattern 2: Spread shot (5 bullets in wide arc) for (var i = 0; i < 5; i++) { var bullet = new BossBullet(); bullet.x = self.x + (i - 2) * 80; bullet.y = self.y + 70; // Add slight angle variation var angle = (i - 2) * 0.2; bullet.speedX = Math.sin(angle) * 2; bullet.speedY = bullet.speed + Math.abs(Math.cos(angle)) * 2; bullet.update = function () { this.x += this.speedX || 0; this.y += this.speedY || this.speed; }; enemyBullets.push(bullet); game.addChild(bullet); } } else if (self.attackPattern === 2) { // Pattern 3: Rapid fire (single bullet aimed at player) var bullet = new BossBullet(); bullet.x = self.x; bullet.y = self.y + 70; // Aim towards player var deltaX = player.x - bullet.x; var deltaY = player.y - bullet.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance > 0) { bullet.speedX = deltaX / distance * 3; bullet.speedY = deltaY / distance * 3; bullet.update = function () { this.x += this.speedX; this.y += this.speedY; }; } enemyBullets.push(bullet); game.addChild(bullet); } }; self.shootEnemy = function () { for (var i = 0; i < 3; i++) { var bullet = new BossBullet(); bullet.x = self.x + (i - 1) * 50; bullet.y = self.y + 70; enemyBullets.push(bullet); game.addChild(bullet); } }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xffffff, 200); // Visual feedback when boss takes significant damage if (self.health <= 75 && self.health > 50) { tween(self, { tint: 0xff9999 }, { duration: 300, onFinish: function onFinish() { tween(self, { tint: 0xffffff }, { duration: 300 }); } }); } else if (self.health <= 50 && self.health > 25) { tween(self, { tint: 0xff6666 }, { duration: 300, onFinish: function onFinish() { tween(self, { tint: 0xffffff }, { duration: 300 }); } }); } else if (self.health <= 25) { tween(self, { tint: 0xff3333 }, { duration: 300, onFinish: function onFinish() { tween(self, { tint: 0xffffff }, { duration: 300 }); } }); } if (self.health <= 0) { LK.getSound('enemyHit').play(); return true; } return false; }; return self; }); var Bubble = Container.expand(function () { var self = Container.call(this); var bubbleGraphics = self.attachAsset('bubble', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -16; self.damage = 1; self.update = function () { self.y += self.speed; }; 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 = 4; self.damage = 1; self.update = function () { self.y += self.speed; }; return self; }); var EnemyBullet2 = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet2', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.damage = 2; self.update = function () { self.y += self.speed; }; return self; }); var EnemyBullet3 = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet3', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 6; self.damage = 3; self.update = function () { self.y += self.speed; }; return self; }); var EnemyBullet4 = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet4', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 7; self.damage = 4; self.update = function () { self.y += self.speed; }; return self; }); var EnemyFish = Container.expand(function () { var self = Container.call(this); var fishGraphics = self.attachAsset('enemyFish', { anchorX: 0.5, anchorY: 0.5 }); self.health = 2; self.speed = 2; self.shootCooldown = Math.random() * 120 + 60; self.update = function () { // Keep enemy fish in upper zone (y between 100-400) if (self.y < 100) { self.y = 100; } else if (self.y > 400) { self.y = 400; } // Move horizontally instead of vertically if (self.moveDirection === undefined) { self.moveDirection = Math.random() > 0.5 ? 1 : -1; self.horizontalSpeed = 1; } self.x += self.horizontalSpeed * self.moveDirection; // Bounce off screen edges if (self.x <= 50 || self.x >= 2048 - 50) { self.moveDirection *= -1; } if (self.shootCooldown > 0) { self.shootCooldown--; } else { self.shootEnemy(); self.shootCooldown = Math.random() * 120 + 60; } }; self.shootEnemy = function () { if (self.y > 0 && self.y < 2732 - 200) { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y + 40; enemyBullets.push(bullet); game.addChild(bullet); } }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xffffff, 200); // Add tween effect for damage feedback tween(self, { tint: 0xff4444 }, { duration: 150, onFinish: function onFinish() { tween(self, { tint: 0xffffff }, { duration: 150 }); } }); if (self.health <= 0) { LK.getSound('enemyHit').play(); return true; } return false; }; return self; }); var EnemyFish2 = Container.expand(function () { var self = Container.call(this); var fishGraphics = self.attachAsset('enemyFish2', { anchorX: 0.5, anchorY: 0.5 }); self.health = 4; self.speed = 2; self.shootCooldown = Math.random() * 100 + 50; self.update = function () { // Keep enemy fish in upper zone (y between 100-400) if (self.y < 100) { self.y = 100; } else if (self.y > 400) { self.y = 400; } // Move horizontally instead of vertically if (self.moveDirection === undefined) { self.moveDirection = Math.random() > 0.5 ? 1 : -1; self.horizontalSpeed = 1; } self.x += self.horizontalSpeed * self.moveDirection; // Bounce off screen edges if (self.x <= 50 || self.x >= 2048 - 50) { self.moveDirection *= -1; } if (self.shootCooldown > 0) { self.shootCooldown--; } else { self.shootEnemy(); self.shootCooldown = Math.random() * 100 + 50; } }; self.shootEnemy = function () { if (self.y > 0 && self.y < 2732 - 200) { var bullet = new EnemyBullet2(); bullet.x = self.x; bullet.y = self.y + 40; enemyBullets.push(bullet); game.addChild(bullet); } }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xffffff, 200); // Add tween effect for damage feedback tween(self, { tint: 0xff4444 }, { duration: 150, onFinish: function onFinish() { tween(self, { tint: 0xffffff }, { duration: 150 }); } }); if (self.health <= 0) { LK.getSound('enemyHit').play(); return true; } return false; }; return self; }); var EnemyFish3 = Container.expand(function () { var self = Container.call(this); var fishGraphics = self.attachAsset('enemyFish3', { anchorX: 0.5, anchorY: 0.5 }); self.health = 10; self.speed = 2; self.shootCooldown = Math.random() * 80 + 40; self.update = function () { // Keep enemy fish in upper zone (y between 100-400) if (self.y < 100) { self.y = 100; } else if (self.y > 400) { self.y = 400; } // Move horizontally instead of vertically if (self.moveDirection === undefined) { self.moveDirection = Math.random() > 0.5 ? 1 : -1; self.horizontalSpeed = 1; } self.x += self.horizontalSpeed * self.moveDirection; // Bounce off screen edges if (self.x <= 50 || self.x >= 2048 - 50) { self.moveDirection *= -1; } if (self.shootCooldown > 0) { self.shootCooldown--; } else { self.shootEnemy(); self.shootCooldown = Math.random() * 80 + 40; } }; self.shootEnemy = function () { if (self.y > 0 && self.y < 2732 - 200) { var bullet = new EnemyBullet3(); bullet.x = self.x; bullet.y = self.y + 40; enemyBullets.push(bullet); game.addChild(bullet); } }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xffffff, 200); // Add tween effect for damage feedback tween(self, { tint: 0xff4444 }, { duration: 150, onFinish: function onFinish() { tween(self, { tint: 0xffffff }, { duration: 150 }); } }); if (self.health <= 0) { LK.getSound('enemyHit').play(); return true; } return false; }; return self; }); var EnemyFish4 = Container.expand(function () { var self = Container.call(this); var fishGraphics = self.attachAsset('enemyFish4', { anchorX: 0.5, anchorY: 0.5 }); self.health = 15; self.speed = 2; self.shootCooldown = Math.random() * 60 + 30; self.update = function () { // Keep enemy fish in upper zone (y between 100-400) if (self.y < 100) { self.y = 100; } else if (self.y > 400) { self.y = 400; } // Move horizontally instead of vertically if (self.moveDirection === undefined) { self.moveDirection = Math.random() > 0.5 ? 1 : -1; self.horizontalSpeed = 1; } self.x += self.horizontalSpeed * self.moveDirection; // Bounce off screen edges if (self.x <= 50 || self.x >= 2048 - 50) { self.moveDirection *= -1; } if (self.shootCooldown > 0) { self.shootCooldown--; } else { self.shootEnemy(); self.shootCooldown = Math.random() * 60 + 30; } }; self.shootEnemy = function () { if (self.y > 0 && self.y < 2732 - 200) { var bullet = new EnemyBullet4(); bullet.x = self.x; bullet.y = self.y + 40; enemyBullets.push(bullet); game.addChild(bullet); } }; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xffffff, 200); // Add tween effect for damage feedback tween(self, { tint: 0xff4444 }, { duration: 150, onFinish: function onFinish() { tween(self, { tint: 0xffffff }, { duration: 150 }); } }); if (self.health <= 0) { LK.getSound('enemyHit').play(); return true; } return false; }; return self; }); var PlayerFish = Container.expand(function () { var self = Container.call(this); var fishGraphics = self.attachAsset('playerFish', { anchorX: 0.5, anchorY: 0.5 }); self.health = 3; self.damage = 1; self.maxHealth = 3; self.shootCooldown = 0; self.update = function () { // Only shoot when game is in playing state if (gameState !== 'playing') { return; } if (self.shootCooldown > 0) { self.shootCooldown--; } else { // Auto shoot every 25 frames to match cooldown self.shoot(); } }; self.takeDamage = function (damage) { if (playerInvulnerable) return; // Cannot take damage while invulnerable if (damage === undefined) damage = 1; self.health -= damage; LK.effects.flashObject(self, 0xff0000, 500); LK.getSound('playerHit').play(); // Start invulnerability period playerInvulnerable = true; invulnerabilityTimer = invulnerabilityDuration; // Create blinking effect during invulnerability tween(self, { alpha: 0.3 }, { duration: 200, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 200 }); } }); if (self.health <= 0) { LK.showGameOver(); } }; self.shoot = function () { if (self.shootCooldown <= 0) { var bubble = new Bubble(); bubble.x = self.x; bubble.y = self.y - 50; bubble.damage = self.damage; bubbles.push(bubble); game.addChild(bubble); self.shootCooldown = 25; LK.getSound('bubbleShoot').play(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x001F3F }); /**** * Game Code ****/ // Add background var background = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(background); var player; var enemies = []; var bubbles = []; var enemyBullets = []; var currentLevel = 1; var maxLevel = 10; var enemiesSpawned = 0; var enemiesKilled = 0; var spawnTimer = 0; var gameState = 'menu'; var boss = null; var playerInvulnerable = false; var invulnerabilityTimer = 0; var invulnerabilityDuration = 120; // 2 seconds at 60fps // UI Elements var healthText = new Text2('Health: 3', { size: 60, fill: 0xFFFFFF }); healthText.anchor.set(0, 0); healthText.x = 150; healthText.y = 50; healthText.visible = false; LK.gui.topLeft.addChild(healthText); var levelText = new Text2('Level: 1', { size: 60, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0); levelText.visible = false; LK.gui.top.addChild(levelText); var damageText = new Text2('Damage: 1', { size: 60, fill: 0xFFFFFF }); damageText.anchor.set(1, 0); damageText.x = -50; damageText.y = 50; damageText.visible = false; LK.gui.topRight.addChild(damageText); var bossHealthText = new Text2('', { size: 60, fill: 0xFF0000 }); bossHealthText.anchor.set(0.5, 0); bossHealthText.x = 0; bossHealthText.y = 150; bossHealthText.visible = false; LK.gui.top.addChild(bossHealthText); // Start Menu UI var startMenuContainer = new Container(); startMenuContainer.visible = true; LK.gui.center.addChild(startMenuContainer); var gameTitle = new Text2('Ocean Battle', { size: 120, fill: 0x00FFFF }); gameTitle.anchor.set(0.5, 0.5); gameTitle.y = -200; startMenuContainer.addChild(gameTitle); var startButton = LK.getAsset('playerFish', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 50, scaleX: 2, scaleY: 2 }); startMenuContainer.addChild(startButton); var startButtonText = new Text2('Iniciar', { size: 80, fill: 0xFFFFFF }); startButtonText.anchor.set(0.5, 0.5); startButtonText.x = 0; startButtonText.y = 150; startMenuContainer.addChild(startButtonText); // Upgrade UI (hidden initially) var upgradeContainer = new Container(); upgradeContainer.visible = false; LK.gui.center.addChild(upgradeContainer); var upgradeTitle = new Text2('Choose Upgrade:', { size: 80, fill: 0xFFFFFF }); upgradeTitle.anchor.set(0.5, 0.5); upgradeTitle.y = -150; upgradeContainer.addChild(upgradeTitle); var healthUpgradeButton = LK.getAsset('playerFish', { anchorX: 0.5, anchorY: 0.5, x: -200, y: 0, scaleX: 1.5, scaleY: 1.5 }); upgradeContainer.addChild(healthUpgradeButton); var healthUpgradeText = new Text2('+2 Health', { size: 50, fill: 0xFFFFFF }); healthUpgradeText.anchor.set(0.5, 0); healthUpgradeText.x = -200; healthUpgradeText.y = 150; upgradeContainer.addChild(healthUpgradeText); var damageUpgradeButton = LK.getAsset('bubble', { anchorX: 0.5, anchorY: 0.5, x: 200, y: 0, scaleX: 2, scaleY: 2 }); upgradeContainer.addChild(damageUpgradeButton); var damageUpgradeText = new Text2('+1 Damage', { size: 50, fill: 0xFFFFFF }); damageUpgradeText.anchor.set(0.5, 0); damageUpgradeText.x = 200; damageUpgradeText.y = 150; upgradeContainer.addChild(damageUpgradeText); // Initialize player player = game.addChild(new PlayerFish()); player.x = 1024; player.y = 2500; function updateUI() { healthText.setText('Health: ' + player.health); levelText.setText('Level: ' + currentLevel); damageText.setText('Damage: ' + player.damage); // Update boss health display if (boss && boss.health > 0) { bossHealthText.setText('Boss Health: ' + boss.health); bossHealthText.visible = true; // Position the text below the boss var bossPosition = game.toLocal(boss.parent.toGlobal(boss.position)); var guiPosition = LK.gui.top.toLocal(game.toGlobal(bossPosition)); bossHealthText.x = guiPosition.x; bossHealthText.y = guiPosition.y + 450; // Position below boss (boss height is ~400px + margin) } else { bossHealthText.visible = false; } } function spawnEnemy() { var enemy; if (currentLevel === 10 && !boss) { boss = new BossFish(); boss.x = 1024; boss.y = 200; enemies.push(boss); game.addChild(boss); } else if (currentLevel < 10) { // Count already spawned fish types var alreadySpawnedFish1 = 0; var alreadySpawnedFish2 = 0; var alreadySpawnedFish3 = 0; var alreadySpawnedFish4 = 0; for (var e = 0; e < enemies.length; e++) { if (enemies[e] instanceof EnemyFish4) { alreadySpawnedFish4++; } else if (enemies[e] instanceof EnemyFish3) { alreadySpawnedFish3++; } else if (enemies[e] instanceof EnemyFish2) { alreadySpawnedFish2++; } else if (enemies[e] instanceof EnemyFish) { alreadySpawnedFish1++; } } // Calculate required numbers for this level var requiredFish1 = 10; // Always 10 level 1 fish var requiredFish2 = Math.max(0, currentLevel - 1); // Level 2 = 1, Level 3 = 2, etc. var requiredFish3 = Math.max(0, currentLevel - 4); // Level 5 = 1, Level 6 = 2, etc. var requiredFish4 = Math.max(0, currentLevel - 6); // Level 7 = 1, Level 8 = 2, etc. // Decide what type to spawn based on requirements if (currentLevel >= 7 && alreadySpawnedFish4 < requiredFish4) { enemy = new EnemyFish4(); } else if (currentLevel >= 5 && alreadySpawnedFish3 < requiredFish3) { enemy = new EnemyFish3(); } else if (currentLevel >= 2 && alreadySpawnedFish2 < requiredFish2) { enemy = new EnemyFish2(); } else if (alreadySpawnedFish1 < requiredFish1) { enemy = new EnemyFish(); } else { // All required fish spawned, don't spawn more return; } enemy.x = Math.random() * (2048 - 200) + 100; enemy.y = Math.random() * 200 + 100; // Spawn in upper zone (100-300) enemies.push(enemy); game.addChild(enemy); enemiesSpawned++; } } function getEnemiesForLevel(level) { if (level === 1) { return 10; // 10 level 1 fish only } else if (level >= 2 && level <= 4) { return 10 + (level - 1); // 10 level 1 fish + increasing level 2 fish } else if (level >= 5 && level <= 6) { return 10 + (level - 1) + (level - 4); // 10 level 1 fish + level 2 fish + level 3 fish } else if (level >= 7 && level <= 9) { return 10 + (level - 1) + (level - 4) + (level - 6); // 10 level 1 fish + level 2 fish + level 3 fish + level 4 fish } else { return 0; // Level 10 is boss only } } function startLevel() { enemiesSpawned = 0; enemiesKilled = 0; spawnTimer = 0; gameState = 'playing'; boss = null; // Change background for level 6 and beyond if (currentLevel >= 6) { background.destroy(); background = LK.getAsset('background2', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChildAt(background, 0); // Add at bottom layer // Change music for level 6 LK.playMusic('oceanAmbient2'); } // Restore player health to maximum at start of each level player.health = player.maxHealth; if (currentLevel === 10) { spawnEnemy(); // Spawn boss immediately } } function showUpgradeScreen() { gameState = 'upgrading'; upgradeContainer.visible = true; // Update upgrade text based on current level if (currentLevel >= 7) { healthUpgradeText.setText('+4 Health'); damageUpgradeText.setText('+2 Damage'); } else { healthUpgradeText.setText('+2 Health'); damageUpgradeText.setText('+1 Damage'); } } function hideUpgradeScreen() { upgradeContainer.visible = false; } function selectHealthUpgrade() { if (gameState === 'upgrading') { var healthIncrease = currentLevel >= 7 ? 4 : 2; player.health += healthIncrease; player.maxHealth += healthIncrease; hideUpgradeScreen(); nextLevel(); } } function selectDamageUpgrade() { if (gameState === 'upgrading') { var damageIncrease = currentLevel >= 7 ? 2 : 1; player.damage += damageIncrease; hideUpgradeScreen(); nextLevel(); } } function startGame() { gameState = 'playing'; startMenuContainer.visible = false; healthText.visible = true; levelText.visible = true; damageText.visible = true; startLevel(); updateUI(); } function nextLevel() { currentLevel++; if (currentLevel > maxLevel) { LK.showYouWin(); return; } startLevel(); updateUI(); } // Event handlers startButton.down = function (x, y, obj) { startGame(); }; healthUpgradeButton.down = function (x, y, obj) { selectHealthUpgrade(); }; damageUpgradeButton.down = function (x, y, obj) { selectDamageUpgrade(); }; game.down = function (x, y, obj) { // Player now shoots automatically, no manual shooting needed }; game.move = function (x, y, obj) { if (gameState === 'playing') { player.x = Math.max(60, Math.min(2048 - 60, x)); player.y = Math.max(2000, Math.min(2732 - 60, y)); } }; // Play background music LK.playMusic('oceanAmbient'); game.update = function () { if (gameState === 'menu') { return; } if (gameState !== 'playing') { // Stop player from shooting when not in playing state player.shootCooldown = 25; return; } // Handle player invulnerability if (playerInvulnerable) { invulnerabilityTimer--; // Create blinking effect every 10 frames if (invulnerabilityTimer % 20 < 10) { player.alpha = 0.3; } else { player.alpha = 1; } // End invulnerability if (invulnerabilityTimer <= 0) { playerInvulnerable = false; player.alpha = 1; // Ensure player is fully visible tween.stop(player, { alpha: true }); // Stop any ongoing alpha tweens } } // Spawn enemies if (currentLevel < 10) { spawnTimer++; var maxEnemies = getEnemiesForLevel(currentLevel); if (spawnTimer >= 90 && enemiesSpawned < maxEnemies) { spawnEnemy(); spawnTimer = 0; } } // Update bubbles for (var i = bubbles.length - 1; i >= 0; i--) { var bubble = bubbles[i]; if (bubble.lastY === undefined) bubble.lastY = bubble.y; // Remove off-screen bubbles if (bubble.lastY >= -30 && bubble.y < -30) { bubble.destroy(); bubbles.splice(i, 1); continue; } // Check bubble-enemy collisions var hit = false; for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bubble.intersects(enemy)) { if (enemy.takeDamage(bubble.damage)) { enemy.destroy(); enemies.splice(j, 1); enemiesKilled++; } bubble.destroy(); bubbles.splice(i, 1); hit = true; break; } } if (!hit) { bubble.lastY = bubble.y; } } // Update enemy bullets for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; if (bullet.lastY === undefined) bullet.lastY = bullet.y; // Remove off-screen bullets if (bullet.lastY <= 2732 + 30 && bullet.y > 2732 + 30) { bullet.destroy(); enemyBullets.splice(i, 1); continue; } // Check bullet-player collision if (bullet.intersects(player) && !playerInvulnerable) { player.takeDamage(bullet.damage); bullet.destroy(); enemyBullets.splice(i, 1); continue; } bullet.lastY = bullet.y; } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.lastY === undefined) enemy.lastY = enemy.y; // Remove off-screen enemies (not boss) if (enemy !== boss && enemy.lastY <= 2732 + 50 && enemy.y > 2732 + 50) { enemy.destroy(); enemies.splice(i, 1); continue; } // Check enemy-player collision if (enemy.intersects(player) && !playerInvulnerable) { player.takeDamage(1); } enemy.lastY = enemy.y; } // Check level completion if (currentLevel < 10) { var maxEnemies = getEnemiesForLevel(currentLevel); if (enemiesKilled >= maxEnemies && enemies.length === 0) { // Clear all enemy bullets when level is completed for (var k = enemyBullets.length - 1; k >= 0; k--) { enemyBullets[k].destroy(); enemyBullets.splice(k, 1); } showUpgradeScreen(); } } else { // Boss level if (enemies.length === 0) { // Clear all enemy bullets when boss is defeated for (var k = enemyBullets.length - 1; k >= 0; k--) { enemyBullets[k].destroy(); enemyBullets.splice(k, 1); } LK.showYouWin(); } } updateUI(); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var BossBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bossBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 5;
self.update = function () {
self.y += self.speed;
};
return self;
});
var BossFish = Container.expand(function () {
var self = Container.call(this);
var fishGraphics = self.attachAsset('bossFish', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 500;
self.speed = 2;
self.shootCooldown = 30;
self.moveDirection = 1;
self.attackPattern = 0; // 0: triple shot, 1: spread shot, 2: rapid fire
self.attackCooldown = 0;
self.pauseCooldown = 0;
self.attacksInPattern = 0;
self.maxAttacksPerPattern = 5;
self.update = function () {
self.x += self.speed * self.moveDirection;
if (self.x <= 100 || self.x >= 2048 - 100) {
self.moveDirection *= -1;
}
// Handle pauses between attack patterns
if (self.pauseCooldown > 0) {
self.pauseCooldown--;
return;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
} else {
self.executeAttackPattern();
self.attacksInPattern++;
// Check if we need to switch patterns or pause
if (self.attacksInPattern >= self.maxAttacksPerPattern) {
self.attacksInPattern = 0;
self.attackPattern = (self.attackPattern + 1) % 3;
self.pauseCooldown = 90; // 1.5 second pause between patterns
} else {
// Set cooldown based on attack pattern
if (self.attackPattern === 2) {
// Rapid fire
self.shootCooldown = 10;
} else {
self.shootCooldown = 25;
}
}
}
};
self.executeAttackPattern = function () {
if (self.attackPattern === 0) {
// Pattern 1: Triple shot (original)
for (var i = 0; i < 3; i++) {
var bullet = new BossBullet();
bullet.x = self.x + (i - 1) * 50;
bullet.y = self.y + 70;
enemyBullets.push(bullet);
game.addChild(bullet);
}
} else if (self.attackPattern === 1) {
// Pattern 2: Spread shot (5 bullets in wide arc)
for (var i = 0; i < 5; i++) {
var bullet = new BossBullet();
bullet.x = self.x + (i - 2) * 80;
bullet.y = self.y + 70;
// Add slight angle variation
var angle = (i - 2) * 0.2;
bullet.speedX = Math.sin(angle) * 2;
bullet.speedY = bullet.speed + Math.abs(Math.cos(angle)) * 2;
bullet.update = function () {
this.x += this.speedX || 0;
this.y += this.speedY || this.speed;
};
enemyBullets.push(bullet);
game.addChild(bullet);
}
} else if (self.attackPattern === 2) {
// Pattern 3: Rapid fire (single bullet aimed at player)
var bullet = new BossBullet();
bullet.x = self.x;
bullet.y = self.y + 70;
// Aim towards player
var deltaX = player.x - bullet.x;
var deltaY = player.y - bullet.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 0) {
bullet.speedX = deltaX / distance * 3;
bullet.speedY = deltaY / distance * 3;
bullet.update = function () {
this.x += this.speedX;
this.y += this.speedY;
};
}
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
self.shootEnemy = function () {
for (var i = 0; i < 3; i++) {
var bullet = new BossBullet();
bullet.x = self.x + (i - 1) * 50;
bullet.y = self.y + 70;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xffffff, 200);
// Visual feedback when boss takes significant damage
if (self.health <= 75 && self.health > 50) {
tween(self, {
tint: 0xff9999
}, {
duration: 300,
onFinish: function onFinish() {
tween(self, {
tint: 0xffffff
}, {
duration: 300
});
}
});
} else if (self.health <= 50 && self.health > 25) {
tween(self, {
tint: 0xff6666
}, {
duration: 300,
onFinish: function onFinish() {
tween(self, {
tint: 0xffffff
}, {
duration: 300
});
}
});
} else if (self.health <= 25) {
tween(self, {
tint: 0xff3333
}, {
duration: 300,
onFinish: function onFinish() {
tween(self, {
tint: 0xffffff
}, {
duration: 300
});
}
});
}
if (self.health <= 0) {
LK.getSound('enemyHit').play();
return true;
}
return false;
};
return self;
});
var Bubble = Container.expand(function () {
var self = Container.call(this);
var bubbleGraphics = self.attachAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -16;
self.damage = 1;
self.update = function () {
self.y += self.speed;
};
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 = 4;
self.damage = 1;
self.update = function () {
self.y += self.speed;
};
return self;
});
var EnemyBullet2 = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet2', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.damage = 2;
self.update = function () {
self.y += self.speed;
};
return self;
});
var EnemyBullet3 = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet3', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.damage = 3;
self.update = function () {
self.y += self.speed;
};
return self;
});
var EnemyBullet4 = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet4', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 7;
self.damage = 4;
self.update = function () {
self.y += self.speed;
};
return self;
});
var EnemyFish = Container.expand(function () {
var self = Container.call(this);
var fishGraphics = self.attachAsset('enemyFish', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 2;
self.speed = 2;
self.shootCooldown = Math.random() * 120 + 60;
self.update = function () {
// Keep enemy fish in upper zone (y between 100-400)
if (self.y < 100) {
self.y = 100;
} else if (self.y > 400) {
self.y = 400;
}
// Move horizontally instead of vertically
if (self.moveDirection === undefined) {
self.moveDirection = Math.random() > 0.5 ? 1 : -1;
self.horizontalSpeed = 1;
}
self.x += self.horizontalSpeed * self.moveDirection;
// Bounce off screen edges
if (self.x <= 50 || self.x >= 2048 - 50) {
self.moveDirection *= -1;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
} else {
self.shootEnemy();
self.shootCooldown = Math.random() * 120 + 60;
}
};
self.shootEnemy = function () {
if (self.y > 0 && self.y < 2732 - 200) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 40;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xffffff, 200);
// Add tween effect for damage feedback
tween(self, {
tint: 0xff4444
}, {
duration: 150,
onFinish: function onFinish() {
tween(self, {
tint: 0xffffff
}, {
duration: 150
});
}
});
if (self.health <= 0) {
LK.getSound('enemyHit').play();
return true;
}
return false;
};
return self;
});
var EnemyFish2 = Container.expand(function () {
var self = Container.call(this);
var fishGraphics = self.attachAsset('enemyFish2', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 4;
self.speed = 2;
self.shootCooldown = Math.random() * 100 + 50;
self.update = function () {
// Keep enemy fish in upper zone (y between 100-400)
if (self.y < 100) {
self.y = 100;
} else if (self.y > 400) {
self.y = 400;
}
// Move horizontally instead of vertically
if (self.moveDirection === undefined) {
self.moveDirection = Math.random() > 0.5 ? 1 : -1;
self.horizontalSpeed = 1;
}
self.x += self.horizontalSpeed * self.moveDirection;
// Bounce off screen edges
if (self.x <= 50 || self.x >= 2048 - 50) {
self.moveDirection *= -1;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
} else {
self.shootEnemy();
self.shootCooldown = Math.random() * 100 + 50;
}
};
self.shootEnemy = function () {
if (self.y > 0 && self.y < 2732 - 200) {
var bullet = new EnemyBullet2();
bullet.x = self.x;
bullet.y = self.y + 40;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xffffff, 200);
// Add tween effect for damage feedback
tween(self, {
tint: 0xff4444
}, {
duration: 150,
onFinish: function onFinish() {
tween(self, {
tint: 0xffffff
}, {
duration: 150
});
}
});
if (self.health <= 0) {
LK.getSound('enemyHit').play();
return true;
}
return false;
};
return self;
});
var EnemyFish3 = Container.expand(function () {
var self = Container.call(this);
var fishGraphics = self.attachAsset('enemyFish3', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 10;
self.speed = 2;
self.shootCooldown = Math.random() * 80 + 40;
self.update = function () {
// Keep enemy fish in upper zone (y between 100-400)
if (self.y < 100) {
self.y = 100;
} else if (self.y > 400) {
self.y = 400;
}
// Move horizontally instead of vertically
if (self.moveDirection === undefined) {
self.moveDirection = Math.random() > 0.5 ? 1 : -1;
self.horizontalSpeed = 1;
}
self.x += self.horizontalSpeed * self.moveDirection;
// Bounce off screen edges
if (self.x <= 50 || self.x >= 2048 - 50) {
self.moveDirection *= -1;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
} else {
self.shootEnemy();
self.shootCooldown = Math.random() * 80 + 40;
}
};
self.shootEnemy = function () {
if (self.y > 0 && self.y < 2732 - 200) {
var bullet = new EnemyBullet3();
bullet.x = self.x;
bullet.y = self.y + 40;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xffffff, 200);
// Add tween effect for damage feedback
tween(self, {
tint: 0xff4444
}, {
duration: 150,
onFinish: function onFinish() {
tween(self, {
tint: 0xffffff
}, {
duration: 150
});
}
});
if (self.health <= 0) {
LK.getSound('enemyHit').play();
return true;
}
return false;
};
return self;
});
var EnemyFish4 = Container.expand(function () {
var self = Container.call(this);
var fishGraphics = self.attachAsset('enemyFish4', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 15;
self.speed = 2;
self.shootCooldown = Math.random() * 60 + 30;
self.update = function () {
// Keep enemy fish in upper zone (y between 100-400)
if (self.y < 100) {
self.y = 100;
} else if (self.y > 400) {
self.y = 400;
}
// Move horizontally instead of vertically
if (self.moveDirection === undefined) {
self.moveDirection = Math.random() > 0.5 ? 1 : -1;
self.horizontalSpeed = 1;
}
self.x += self.horizontalSpeed * self.moveDirection;
// Bounce off screen edges
if (self.x <= 50 || self.x >= 2048 - 50) {
self.moveDirection *= -1;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
} else {
self.shootEnemy();
self.shootCooldown = Math.random() * 60 + 30;
}
};
self.shootEnemy = function () {
if (self.y > 0 && self.y < 2732 - 200) {
var bullet = new EnemyBullet4();
bullet.x = self.x;
bullet.y = self.y + 40;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xffffff, 200);
// Add tween effect for damage feedback
tween(self, {
tint: 0xff4444
}, {
duration: 150,
onFinish: function onFinish() {
tween(self, {
tint: 0xffffff
}, {
duration: 150
});
}
});
if (self.health <= 0) {
LK.getSound('enemyHit').play();
return true;
}
return false;
};
return self;
});
var PlayerFish = Container.expand(function () {
var self = Container.call(this);
var fishGraphics = self.attachAsset('playerFish', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 3;
self.damage = 1;
self.maxHealth = 3;
self.shootCooldown = 0;
self.update = function () {
// Only shoot when game is in playing state
if (gameState !== 'playing') {
return;
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
} else {
// Auto shoot every 25 frames to match cooldown
self.shoot();
}
};
self.takeDamage = function (damage) {
if (playerInvulnerable) return; // Cannot take damage while invulnerable
if (damage === undefined) damage = 1;
self.health -= damage;
LK.effects.flashObject(self, 0xff0000, 500);
LK.getSound('playerHit').play();
// Start invulnerability period
playerInvulnerable = true;
invulnerabilityTimer = invulnerabilityDuration;
// Create blinking effect during invulnerability
tween(self, {
alpha: 0.3
}, {
duration: 200,
onFinish: function onFinish() {
tween(self, {
alpha: 1
}, {
duration: 200
});
}
});
if (self.health <= 0) {
LK.showGameOver();
}
};
self.shoot = function () {
if (self.shootCooldown <= 0) {
var bubble = new Bubble();
bubble.x = self.x;
bubble.y = self.y - 50;
bubble.damage = self.damage;
bubbles.push(bubble);
game.addChild(bubble);
self.shootCooldown = 25;
LK.getSound('bubbleShoot').play();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x001F3F
});
/****
* Game Code
****/
// Add background
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(background);
var player;
var enemies = [];
var bubbles = [];
var enemyBullets = [];
var currentLevel = 1;
var maxLevel = 10;
var enemiesSpawned = 0;
var enemiesKilled = 0;
var spawnTimer = 0;
var gameState = 'menu';
var boss = null;
var playerInvulnerable = false;
var invulnerabilityTimer = 0;
var invulnerabilityDuration = 120; // 2 seconds at 60fps
// UI Elements
var healthText = new Text2('Health: 3', {
size: 60,
fill: 0xFFFFFF
});
healthText.anchor.set(0, 0);
healthText.x = 150;
healthText.y = 50;
healthText.visible = false;
LK.gui.topLeft.addChild(healthText);
var levelText = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
levelText.visible = false;
LK.gui.top.addChild(levelText);
var damageText = new Text2('Damage: 1', {
size: 60,
fill: 0xFFFFFF
});
damageText.anchor.set(1, 0);
damageText.x = -50;
damageText.y = 50;
damageText.visible = false;
LK.gui.topRight.addChild(damageText);
var bossHealthText = new Text2('', {
size: 60,
fill: 0xFF0000
});
bossHealthText.anchor.set(0.5, 0);
bossHealthText.x = 0;
bossHealthText.y = 150;
bossHealthText.visible = false;
LK.gui.top.addChild(bossHealthText);
// Start Menu UI
var startMenuContainer = new Container();
startMenuContainer.visible = true;
LK.gui.center.addChild(startMenuContainer);
var gameTitle = new Text2('Ocean Battle', {
size: 120,
fill: 0x00FFFF
});
gameTitle.anchor.set(0.5, 0.5);
gameTitle.y = -200;
startMenuContainer.addChild(gameTitle);
var startButton = LK.getAsset('playerFish', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 50,
scaleX: 2,
scaleY: 2
});
startMenuContainer.addChild(startButton);
var startButtonText = new Text2('Iniciar', {
size: 80,
fill: 0xFFFFFF
});
startButtonText.anchor.set(0.5, 0.5);
startButtonText.x = 0;
startButtonText.y = 150;
startMenuContainer.addChild(startButtonText);
// Upgrade UI (hidden initially)
var upgradeContainer = new Container();
upgradeContainer.visible = false;
LK.gui.center.addChild(upgradeContainer);
var upgradeTitle = new Text2('Choose Upgrade:', {
size: 80,
fill: 0xFFFFFF
});
upgradeTitle.anchor.set(0.5, 0.5);
upgradeTitle.y = -150;
upgradeContainer.addChild(upgradeTitle);
var healthUpgradeButton = LK.getAsset('playerFish', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: 0,
scaleX: 1.5,
scaleY: 1.5
});
upgradeContainer.addChild(healthUpgradeButton);
var healthUpgradeText = new Text2('+2 Health', {
size: 50,
fill: 0xFFFFFF
});
healthUpgradeText.anchor.set(0.5, 0);
healthUpgradeText.x = -200;
healthUpgradeText.y = 150;
upgradeContainer.addChild(healthUpgradeText);
var damageUpgradeButton = LK.getAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 0,
scaleX: 2,
scaleY: 2
});
upgradeContainer.addChild(damageUpgradeButton);
var damageUpgradeText = new Text2('+1 Damage', {
size: 50,
fill: 0xFFFFFF
});
damageUpgradeText.anchor.set(0.5, 0);
damageUpgradeText.x = 200;
damageUpgradeText.y = 150;
upgradeContainer.addChild(damageUpgradeText);
// Initialize player
player = game.addChild(new PlayerFish());
player.x = 1024;
player.y = 2500;
function updateUI() {
healthText.setText('Health: ' + player.health);
levelText.setText('Level: ' + currentLevel);
damageText.setText('Damage: ' + player.damage);
// Update boss health display
if (boss && boss.health > 0) {
bossHealthText.setText('Boss Health: ' + boss.health);
bossHealthText.visible = true;
// Position the text below the boss
var bossPosition = game.toLocal(boss.parent.toGlobal(boss.position));
var guiPosition = LK.gui.top.toLocal(game.toGlobal(bossPosition));
bossHealthText.x = guiPosition.x;
bossHealthText.y = guiPosition.y + 450; // Position below boss (boss height is ~400px + margin)
} else {
bossHealthText.visible = false;
}
}
function spawnEnemy() {
var enemy;
if (currentLevel === 10 && !boss) {
boss = new BossFish();
boss.x = 1024;
boss.y = 200;
enemies.push(boss);
game.addChild(boss);
} else if (currentLevel < 10) {
// Count already spawned fish types
var alreadySpawnedFish1 = 0;
var alreadySpawnedFish2 = 0;
var alreadySpawnedFish3 = 0;
var alreadySpawnedFish4 = 0;
for (var e = 0; e < enemies.length; e++) {
if (enemies[e] instanceof EnemyFish4) {
alreadySpawnedFish4++;
} else if (enemies[e] instanceof EnemyFish3) {
alreadySpawnedFish3++;
} else if (enemies[e] instanceof EnemyFish2) {
alreadySpawnedFish2++;
} else if (enemies[e] instanceof EnemyFish) {
alreadySpawnedFish1++;
}
}
// Calculate required numbers for this level
var requiredFish1 = 10; // Always 10 level 1 fish
var requiredFish2 = Math.max(0, currentLevel - 1); // Level 2 = 1, Level 3 = 2, etc.
var requiredFish3 = Math.max(0, currentLevel - 4); // Level 5 = 1, Level 6 = 2, etc.
var requiredFish4 = Math.max(0, currentLevel - 6); // Level 7 = 1, Level 8 = 2, etc.
// Decide what type to spawn based on requirements
if (currentLevel >= 7 && alreadySpawnedFish4 < requiredFish4) {
enemy = new EnemyFish4();
} else if (currentLevel >= 5 && alreadySpawnedFish3 < requiredFish3) {
enemy = new EnemyFish3();
} else if (currentLevel >= 2 && alreadySpawnedFish2 < requiredFish2) {
enemy = new EnemyFish2();
} else if (alreadySpawnedFish1 < requiredFish1) {
enemy = new EnemyFish();
} else {
// All required fish spawned, don't spawn more
return;
}
enemy.x = Math.random() * (2048 - 200) + 100;
enemy.y = Math.random() * 200 + 100; // Spawn in upper zone (100-300)
enemies.push(enemy);
game.addChild(enemy);
enemiesSpawned++;
}
}
function getEnemiesForLevel(level) {
if (level === 1) {
return 10; // 10 level 1 fish only
} else if (level >= 2 && level <= 4) {
return 10 + (level - 1); // 10 level 1 fish + increasing level 2 fish
} else if (level >= 5 && level <= 6) {
return 10 + (level - 1) + (level - 4); // 10 level 1 fish + level 2 fish + level 3 fish
} else if (level >= 7 && level <= 9) {
return 10 + (level - 1) + (level - 4) + (level - 6); // 10 level 1 fish + level 2 fish + level 3 fish + level 4 fish
} else {
return 0; // Level 10 is boss only
}
}
function startLevel() {
enemiesSpawned = 0;
enemiesKilled = 0;
spawnTimer = 0;
gameState = 'playing';
boss = null;
// Change background for level 6 and beyond
if (currentLevel >= 6) {
background.destroy();
background = LK.getAsset('background2', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChildAt(background, 0); // Add at bottom layer
// Change music for level 6
LK.playMusic('oceanAmbient2');
}
// Restore player health to maximum at start of each level
player.health = player.maxHealth;
if (currentLevel === 10) {
spawnEnemy(); // Spawn boss immediately
}
}
function showUpgradeScreen() {
gameState = 'upgrading';
upgradeContainer.visible = true;
// Update upgrade text based on current level
if (currentLevel >= 7) {
healthUpgradeText.setText('+4 Health');
damageUpgradeText.setText('+2 Damage');
} else {
healthUpgradeText.setText('+2 Health');
damageUpgradeText.setText('+1 Damage');
}
}
function hideUpgradeScreen() {
upgradeContainer.visible = false;
}
function selectHealthUpgrade() {
if (gameState === 'upgrading') {
var healthIncrease = currentLevel >= 7 ? 4 : 2;
player.health += healthIncrease;
player.maxHealth += healthIncrease;
hideUpgradeScreen();
nextLevel();
}
}
function selectDamageUpgrade() {
if (gameState === 'upgrading') {
var damageIncrease = currentLevel >= 7 ? 2 : 1;
player.damage += damageIncrease;
hideUpgradeScreen();
nextLevel();
}
}
function startGame() {
gameState = 'playing';
startMenuContainer.visible = false;
healthText.visible = true;
levelText.visible = true;
damageText.visible = true;
startLevel();
updateUI();
}
function nextLevel() {
currentLevel++;
if (currentLevel > maxLevel) {
LK.showYouWin();
return;
}
startLevel();
updateUI();
}
// Event handlers
startButton.down = function (x, y, obj) {
startGame();
};
healthUpgradeButton.down = function (x, y, obj) {
selectHealthUpgrade();
};
damageUpgradeButton.down = function (x, y, obj) {
selectDamageUpgrade();
};
game.down = function (x, y, obj) {
// Player now shoots automatically, no manual shooting needed
};
game.move = function (x, y, obj) {
if (gameState === 'playing') {
player.x = Math.max(60, Math.min(2048 - 60, x));
player.y = Math.max(2000, Math.min(2732 - 60, y));
}
};
// Play background music
LK.playMusic('oceanAmbient');
game.update = function () {
if (gameState === 'menu') {
return;
}
if (gameState !== 'playing') {
// Stop player from shooting when not in playing state
player.shootCooldown = 25;
return;
}
// Handle player invulnerability
if (playerInvulnerable) {
invulnerabilityTimer--;
// Create blinking effect every 10 frames
if (invulnerabilityTimer % 20 < 10) {
player.alpha = 0.3;
} else {
player.alpha = 1;
}
// End invulnerability
if (invulnerabilityTimer <= 0) {
playerInvulnerable = false;
player.alpha = 1; // Ensure player is fully visible
tween.stop(player, {
alpha: true
}); // Stop any ongoing alpha tweens
}
}
// Spawn enemies
if (currentLevel < 10) {
spawnTimer++;
var maxEnemies = getEnemiesForLevel(currentLevel);
if (spawnTimer >= 90 && enemiesSpawned < maxEnemies) {
spawnEnemy();
spawnTimer = 0;
}
}
// Update bubbles
for (var i = bubbles.length - 1; i >= 0; i--) {
var bubble = bubbles[i];
if (bubble.lastY === undefined) bubble.lastY = bubble.y;
// Remove off-screen bubbles
if (bubble.lastY >= -30 && bubble.y < -30) {
bubble.destroy();
bubbles.splice(i, 1);
continue;
}
// Check bubble-enemy collisions
var hit = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bubble.intersects(enemy)) {
if (enemy.takeDamage(bubble.damage)) {
enemy.destroy();
enemies.splice(j, 1);
enemiesKilled++;
}
bubble.destroy();
bubbles.splice(i, 1);
hit = true;
break;
}
}
if (!hit) {
bubble.lastY = bubble.y;
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.lastY === undefined) bullet.lastY = bullet.y;
// Remove off-screen bullets
if (bullet.lastY <= 2732 + 30 && bullet.y > 2732 + 30) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check bullet-player collision
if (bullet.intersects(player) && !playerInvulnerable) {
player.takeDamage(bullet.damage);
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
bullet.lastY = bullet.y;
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.lastY === undefined) enemy.lastY = enemy.y;
// Remove off-screen enemies (not boss)
if (enemy !== boss && enemy.lastY <= 2732 + 50 && enemy.y > 2732 + 50) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Check enemy-player collision
if (enemy.intersects(player) && !playerInvulnerable) {
player.takeDamage(1);
}
enemy.lastY = enemy.y;
}
// Check level completion
if (currentLevel < 10) {
var maxEnemies = getEnemiesForLevel(currentLevel);
if (enemiesKilled >= maxEnemies && enemies.length === 0) {
// Clear all enemy bullets when level is completed
for (var k = enemyBullets.length - 1; k >= 0; k--) {
enemyBullets[k].destroy();
enemyBullets.splice(k, 1);
}
showUpgradeScreen();
}
} else {
// Boss level
if (enemies.length === 0) {
// Clear all enemy bullets when boss is defeated
for (var k = enemyBullets.length - 1; k >= 0; k--) {
enemyBullets[k].destroy();
enemyBullets.splice(k, 1);
}
LK.showYouWin();
}
}
updateUI();
};
Water Bubble. In-Game asset. High contrast. No shadows. 2D
a orange water bubble. In-Game asset. 2d. High contrast. No shadows
a orange fish seen from top to bottom. In-Game asset. 2d. High contrast. No shadows
a blue fish seen from above, looking up. In-Game asset. 2d. High contrast. No shadows
a purple evil fish seen from top to bottom. In-Game asset. 2d. High contrast. No shadows
a red fish seen from top to bottom. In-Game asset. 2d. High contrast. No shadows
a gold fish seen from top to bottom. In-Game asset. 2d. High contrast. No shadows
a gold dark fish seen from top to bottom. In-Game asset. 2d. High contrast. No shadows
image of the ocean bottom. In-Game asset. 2d. High contrast. No shadows
image of the bottom of the ocean, dark background. In-Game asset. 2d. High contrast. No shadows