User prompt
Please fix the bug: 'Timeout.tick error: createScoreBackground is not defined' in or related to this line: 'createScoreBackground();' Line Number: 533
User prompt
Please fix the bug: 'Timeout.tick error: createScoreBackground is not defined' in or related to this line: 'createScoreBackground();' Line Number: 532
User prompt
Please fix the bug: 'Timeout.tick error: createScoreBackground is not defined' in or related to this line: 'createScoreBackground();' Line Number: 532
User prompt
Please fix the bug: 'Timeout.tick error: createScoreBackground is not defined' in or related to this line: 'createScoreBackground();' Line Number: 531
User prompt
show scores texts in background2 if win or lose.
User prompt
Add text of score by name of the new player, as an option : the highest score on the top and other scores below it.
User prompt
Please fix the bug: 'Timeout.tick error: saveHighscore is not defined' in or related to this line: 'saveHighscore(LK.getScore());' Line Number: 478
User prompt
Please fix the bug: 'Uncaught TypeError: storage.isAvailable is not a function' in or related to this line: 'if (!storage.isAvailable()) {' Line Number: 628 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Uncaught TypeError: storage.isAvailable is not a function' in or related to this line: 'if (!storage.isAvailable()) {' Line Number: 628
User prompt
save the new scores of the new players when they logged in to upit accounts.
User prompt
Please fix the bug: 'Timeout.tick error: saveHighscore is not defined' in or related to this line: 'saveHighscore(LK.getScore());' Line Number: 478
User prompt
Please fix the bug: 'Timeout.tick error: saveHighscore is not defined' in or related to this line: 'saveHighscore(LK.getScore());' Line Number: 478
User prompt
Please fix the bug: 'Timeout.tick error: saveHighscore is not defined' in or related to this line: 'saveHighscore(LK.getScore());' Line Number: 478
User prompt
Remove the scores of default players. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
add intromusic1
User prompt
Please fix the bug: 'Timeout.tick error: saveHighscore is not defined' in or related to this line: 'saveHighscore(LK.getScore());' Line Number: 477
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: saveHighscore is not defined' in or related to this line: 'saveHighscore(LK.getScore());' Line Number: 477
User prompt
fit background0 to the screen
User prompt
Please fix the bug: 'Timeout.tick error: saveHighscore is not defined' in or related to this line: 'saveHighscore(LK.getScore());' Line Number: 478
User prompt
Please fix the bug: 'Timeout.tick error: saveHighscore is not defined' in or related to this line: 'saveHighscore(LK.getScore());' Line Number: 478 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Timeout.tick error: saveHighscore is not defined' in or related to this line: 'saveHighscore(LK.getScore());' Line Number: 478
User prompt
Please fix the bug: 'Timeout.tick error: saveHighscore is not defined' in or related to this line: 'saveHighscore(LK.getScore());' Line Number: 477
User prompt
Please fix the bug: 'Timeout.tick error: saveHighscore is not defined' in or related to this line: 'saveHighscore(LK.getScore());' Line Number: 477
User prompt
Add the new score to the list always don't do default players names do real logged in players to upit.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Air Enemy Class (Snake Segment - Simplified for MVP) var AirEnemy = Container.expand(function (startX, startY) { var self = Container.call(this); var enemyGraphics = self.attachAsset('airEnemy', { anchorX: 0.5, anchorY: 0.5 }); self.x = startX; self.y = startY; self.speedX = 4 + Math.random() * 2; // Horizontal speed self.amplitudeY = 100 + Math.random() * 100; // Vertical movement range self.frequencyY = 0.01 + Math.random() * 0.01; // Vertical movement speed self.fireRate = 150; // Ticks between shots self.fireCooldown = Math.random() * self.fireRate; self.update = function () { // Basic horizontal and sinusoidal vertical movement self.x -= self.speedX; self.y = startY + Math.sin(LK.ticks * self.frequencyY + startX) * self.amplitudeY; // Use startX for phase offset // Firing logic self.fireCooldown++; if (self.fireCooldown >= self.fireRate) { self.fireCooldown = 0; // Fire a single bullet straight left var bulletSpeed = 8; fireEnemyBullet(self.x, self.y, -bulletSpeed, 0); // vx = -speed, vy = 0 } // Boundary check (simple respawn logic) if (self.x < -enemyGraphics.width) { self.x = 2048 + enemyGraphics.width; // Respawn on the right startY = Math.random() * (2732 - 400) + 200; // Random Y position } }; return self; }); // Boss Class (Basic structure for future) var Boss = Container.expand(function () { var self = Container.call(this); var bossGraphics = self.attachAsset('boss', { anchorX: 0.5, anchorY: 0.5 }); self.x = 2048 - 300; // Position on the right self.y = 2732 / 2; // Center vertically self.fireRate = 180; // Ticks between laser bursts self.fireCooldown = 0; self.health = 100; // Example health self.update = function () { // Add movement logic if needed self.fireCooldown++; if (self.fireCooldown >= self.fireRate) { self.fireCooldown = 0; fireBossLasers(self.x, self.y); } }; return self; }); // Boss Laser Class (Basic structure for future) var BossLaser = Container.expand(function (startX, startY, vx, vy) { var self = Container.call(this); var laserGraphics = self.attachAsset('bossLaser', { anchorX: 0.5, anchorY: 0.5 // Anchor center }); self.x = startX; self.y = startY; self.vx = vx; self.vy = vy; // Set rotation based on velocity direction self.rotation = Math.atan2(vy, vx) + Math.PI / 2; // Point laser in direction of travel (+90deg adjustment needed depending on asset orientation) self.update = function () { self.x += self.vx; self.y += self.vy; }; return self; }); // Bottom Mountain Obstacle Class var BottomMountain = Container.expand(function () { var self = Container.call(this); var mountainGraphics = self.attachAsset('bottommountain', { anchorX: 0.5, anchorY: 0.75 // Anchor base at terrain edge }); self.speed = 5; // Should match terrain speed self.update = function () { self.x -= self.speed; }; return self; }); // Enemy Bullet Class var EnemyBullet = Container.expand(function (startX, startY, vx, vy) { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.x = startX; self.y = startY; self.vx = vx; // Horizontal velocity self.vy = vy; // Vertical velocity self.update = function () { self.x += self.vx; self.y += self.vy; }; return self; }); // Ground Enemy Class var GroundEnemy = Container.expand(function (isTop) { var self = Container.call(this); var enemyGraphics = self.attachAsset(isTop ? 'groundEnemytop' : 'groundEnemybottom', { anchorX: 0.5, anchorY: isTop ? 0 : 1 // Anchor base at terrain edge }); self.isTop = isTop; self.speed = 5; // Should match terrain speed self.fireRate = 120; // Ticks between firing sequences (2 seconds) self.fireCooldown = Math.random() * self.fireRate; // Random initial delay self.shotsInBurst = 3; self.burstDelay = 10; // Ticks between shots in a burst self.update = function () { self.x -= self.speed; self.fireCooldown++; if (self.fireCooldown >= self.fireRate) { self.fireCooldown = 0; // Reset cooldown // Fire burst for (var i = 0; i < self.shotsInBurst; i++) { LK.setTimeout(function () { // Check if enemy still exists before firing if (!self.destroyed) { var bulletSpeed = 8; // Calculate direction logic is now in fireEnemyBullet, but still need to pass initial values var vx = -bulletSpeed * 0.707; // Default direction if player not available var vy = self.isTop ? bulletSpeed * 0.707 : -bulletSpeed * 0.707; // Default direction fireEnemyBullet(self.x, self.y, vx, vy); } }, i * self.burstDelay); } } }; return self; }); // Player Bullet Class var PlayerBullet = Container.expand(function (startX, startY) { var self = Container.call(this); var bulletGraphics = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5 }); self.x = startX; self.y = startY; self.speed = 20; // Moves to the right self.update = function () { self.x += self.speed; }; return self; }); // Terrain Segment Class var TerrainSegment = Container.expand(function (isTop) { var self = Container.call(this); var terrainGraphics = self.attachAsset('terrain', { anchorX: 0, anchorY: isTop ? 0 : 1 // Anchor at top for top terrain, bottom for bottom terrain }); self.isTop = isTop; self.speed = 5; // Horizontal scroll speed self.update = function () { self.x -= self.speed; }; return self; }); // Top Mountain Obstacle Class var TopMountain = Container.expand(function () { var self = Container.call(this); var mountainGraphics = self.attachAsset('topmountain', { anchorX: 0.5, anchorY: 0.3 // Anchor base at terrain edge }); self.speed = 5; // Should match terrain speed self.update = function () { self.x -= self.speed; }; return self; }); // Player UFO Class var UFO = Container.expand(function () { var self = Container.call(this); var ufoGraphics = self.attachAsset('ufo', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; // Movement speed multiplier, adjust as needed self.isDead = false; self.invincibleUntil = 0; // Keep UFO within game boundaries self.clampPosition = function () { var halfWidth = ufoGraphics.width / 2; var halfHeight = ufoGraphics.height / 2; if (self.x < halfWidth) { self.x = halfWidth; } if (self.x > 2048 - halfWidth) { self.x = 2048 - halfWidth; } if (self.y < halfHeight + 100) { self.y = halfHeight + 100; } // Avoid top-left menu area if (self.y > 2732 - halfHeight) { self.y = 2732 - halfHeight; } // Adjust based on terrain phase if (gamePhase === 0) { // Find the current terrain height at the UFO's x position (simplified) var terrainHeight = 200; // Assuming constant terrain height for now if (self.y < terrainHeight + halfHeight) { self.y = terrainHeight + halfHeight; } if (self.y > 2732 - terrainHeight - halfHeight) { self.y = 2732 - terrainHeight - halfHeight; } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x101030 // Dark space blue background }); /**** * Game Code ****/ // LK.init.image('mountain', {width:150, height:250, id:'6819884bc4a0c8bae9e84ae0'}) // Removed - Replaced by top/bottom mountains // Minimalistic tween library which should be used for animations over time // Boss Laser Beam // Boss // Air Enemy (Placeholder shape) // Enemy Bullet // Ground Enemy // Mountain Obstacle (simplified) // Ground/Ceiling // Player UFO // Initialize assets used in this game. Scale them according to what is needed for the game. /**** * Assets * Assets are automatically created and loaded either dynamically during gameplay * or via static code analysis based on their usage in the code. ****/ // Game State var isGameStarted = false; // Flag to track if game has started var showingHighscores = false; // Flag to track if highscore screen is shown var gamePhase = 0; // 0: Terrain, 1: Space, 2: Boss var phaseStartTime = LK.ticks; var phaseDuration = 3600; // 1 minute (60 seconds * 60 fps = 3600 ticks) var terrainSpeed = 5; var scoreIncrementTimer = 0; var highscoreBackground = null; var highscoreTexts = []; // Game Objects var player = null; var terrainSegmentsTop = []; var terrainSegmentsBottom = []; var mountains = []; var groundEnemies = []; var enemyBullets = []; var airEnemies = []; // Simple air enemies for MVP phase 2 var boss = null; var bossLasers = []; var playerBullets = []; // Array for player bullets // Player Control var dragNode = null; var playerFireRate = 15; // Ticks between shots (4 shots per second) var playerFireCooldown = 0; // Player Lives var MAX_PLAYER_LIVES = 5; var playerLives = MAX_PLAYER_LIVES; var livesTxt; // Score Display var scoreTxt = new Text2('0', { size: 100, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Position score at top center // Helper function to create terrain segments function createTerrainSegment(isTop, xPos) { var segment = new TerrainSegment(isTop); segment.x = xPos; segment.y = isTop ? 0 : 2732; segment.speed = terrainSpeed; game.addChild(segment); if (isTop) { terrainSegmentsTop.push(segment); } else { terrainSegmentsBottom.push(segment); } return segment; } // Helper function to spawn mountains on terrain function spawnMountain(terrainSegment) { var mountain; if (terrainSegment.isTop) { mountain = new TopMountain(); } else { mountain = new BottomMountain(); } // Position relative to the terrain segment // Ensure we use the actual height of the terrain graphic for positioning var terrainGraphic = terrainSegment.children[0]; // Assuming the graphic is the first child mountain.x = terrainSegment.x + Math.random() * terrainGraphic.width; // Position based on whether it's a top or bottom mountain mountain.y = terrainSegment.isTop ? terrainGraphic.height : 2732 - terrainGraphic.height; mountain.speed = terrainSpeed; game.addChild(mountain); mountains.push(mountain); } // Helper function to spawn ground enemies on terrain function spawnGroundEnemy(terrainSegment) { var enemy = new GroundEnemy(terrainSegment.isTop); // Position relative to the terrain segment // Ensure we use the actual height of the terrain graphic for positioning var terrainGraphic = terrainSegment.children[0]; // Assuming the graphic is the first child enemy.x = terrainSegment.x + Math.random() * terrainGraphic.width; enemy.y = terrainSegment.isTop ? terrainGraphic.height : 2732 - terrainGraphic.height; enemy.speed = terrainSpeed; game.addChild(enemy); groundEnemies.push(enemy); } // Helper function to fire enemy bullets function fireEnemyBullet(x, y, vx, vy) { // If player exists and is not dead, target the player instead of using fixed direction if (player && !player.isDead) { // Calculate direction vector to player var dx = player.x - x; var dy = player.y - y; // Normalize the vector var distance = Math.sqrt(dx * dx + dy * dy); // Use the bullet speed provided (or calculate from vx and vy) var bulletSpeed = Math.sqrt(vx * vx + vy * vy); // Set velocity components to target player vx = dx / distance * bulletSpeed; vy = dy / distance * bulletSpeed; } var bullet = new EnemyBullet(x, y, vx, vy); game.addChild(bullet); enemyBullets.push(bullet); LK.getSound('enemyShoot').play(); } // Helper function to spawn air enemies (simple version) function spawnAirEnemy() { var startY = Math.random() * (2732 - 400) + 200; // Avoid edges var enemy = new AirEnemy(2048 + 100, startY); // Start off-screen right game.addChild(enemy); airEnemies.push(enemy); } // Helper function to fire boss lasers function fireBossLasers(x, y) { var directions = 5; var laserSpeed = 12; var verticalSpread = 4; // Max vertical speed component for (var i = 0; i < directions; i++) { // Calculate vertical velocity component for spread // Example: i=0 -> -4, i=1 -> -2, i=2 -> 0, i=3 -> 2, i=4 -> 4 var vy = -verticalSpread + verticalSpread * 2 / (directions - 1) * i; // Keep horizontal speed constant (moving left) var vx = -laserSpeed; var laser = new BossLaser(x, y, vx, vy); game.addChild(laser); bossLasers.push(laser); } // Add sound effect for laser fire (consider adding one e.g., LK.getSound('bossShoot').play(); if asset exists) } // Initialize Game Elements function initGame() { // Reset state LK.setScore(0); scoreTxt.setText('0'); // Hide score during intro scoreTxt.visible = !isGameStarted; // Initialize Lives playerLives = MAX_PLAYER_LIVES; if (!livesTxt) { // Create only if it doesn't exist (for game restarts) livesTxt = new Text2("Lives: x" + playerLives, { size: 80, // Slightly smaller than score fill: 0xFFFFFF }); livesTxt.anchor.set(1, 0); // Anchor top-right LK.gui.topRight.addChild(livesTxt); } else { livesTxt.setText("Lives: x" + playerLives); } gamePhase = 0; phaseStartTime = LK.ticks; dragNode = null; playerBullets = []; // Clear player bullets playerFireCooldown = 0; // Reset fire cooldown // Clear existing elements from previous game (if any) // Note: LK engine handles full reset on GameOver/YouWin, but manual cleanup might be needed if restarting mid-game (not typical) // Let's assume full reset is handled by LK. // Create Player player = new UFO(); player.x = 300; player.y = 2732 / 2; player.isDead = false; player.invincibleUntil = 0; player.alpha = 1; // Ensure player is visible game.addChild(player); // Create initial terrain var terrainWidth = LK.getAsset('terrain', {}).width; // Get width from asset for (var i = 0; i < Math.ceil(2048 / terrainWidth) + 1; i++) { createTerrainSegment(true, i * terrainWidth); createTerrainSegment(false, i * terrainWidth); } // Start Phase 1 Music LK.playMusic('phase1Music'); } // Helper function to handle player death function handlePlayerDeath() { if (!player || player.isDead) { return; } // Event Handlers player.isDead = true; player.alpha = 0; // Make player invisible during death processing LK.getSound('playerExplosion').play(); // Optional: Flash the player before making them fully invisible, or flash screen // LK.effects.flashObject(player, 0xFF0000, 500); LK.effects.flashScreen(0xFF0000, 200); // Short screen flash playerLives--; if (livesTxt) { livesTxt.setText("Lives: x" + playerLives); } LK.setTimeout(function () { if (playerLives > 0) { respawnPlayer(); } else { // Save highscore before showing Game Over saveHighscore(LK.getScore()); LK.showGameOver(); } }, 1000); // 1 second delay for effects and sound } // Helper function to respawn player at checkpoint function respawnPlayer() { if (!player) { return; } player.x = 300; player.y = 2732 / 2; player.clampPosition(); player.alpha = 1; // Make player visible again player.isDead = false; player.invincibleUntil = LK.ticks + 120; // 2 seconds of invincibility // Clear active threats for (var i = enemyBullets.length - 1; i >= 0; i--) { if (enemyBullets[i] && !enemyBullets[i].destroyed) { enemyBullets[i].destroy(); } } enemyBullets = []; if (gamePhase === 2) { // Boss phase for (var i = bossLasers.length - 1; i >= 0; i--) { if (bossLasers[i] && !bossLasers[i].destroyed) { bossLasers[i].destroy(); } } bossLasers = []; } // Player is reset, other game elements (enemies, boss health) remain. } // Create intro screen elements var background = game.addChild(LK.getAsset('Background0', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 20.48, scaleY: 27.32 })); var startButton = game.addChild(LK.getAsset('Startgamebutton', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 - 200, scaleX: 1.5, scaleY: 1.5 })); var highscoreButton = game.addChild(LK.getAsset('Highscorebutton', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 + 200, scaleX: 1.5, scaleY: 1.5 })); function startGame() { // Remove intro elements background.destroy(); startButton.destroy(); highscoreButton.destroy(); // Set game as started isGameStarted = true; // Show score scoreTxt.visible = true; // Initialize the game initGame(); } function showHighscore() { // If already showing highscores, hide them and return to intro if (showingHighscores) { // Remove highscore display if (highscoreBackground) { highscoreBackground.destroy(); highscoreBackground = null; } // Remove all highscore texts highscoreTexts.forEach(function (text) { text.destroy(); }); highscoreTexts = []; showingHighscores = false; return; } // Show custom highscore screen showingHighscores = true; // Create background highscoreBackground = game.addChild(LK.getAsset('Background2', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 20.48, scaleY: 27.32 })); // Create highscore title var titleText = new Text2("HIGHSCORES", { size: 120, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0); titleText.x = 2048 / 2; titleText.y = 200; game.addChild(titleText); highscoreTexts.push(titleText); // Get highscores from storage or use default ones if none exist var highscores = []; try { // Try to parse the serialized highscores data if (storage.highscoresData) { highscores = JSON.parse(storage.highscoresData); } } catch (e) { console.log("Error parsing highscores:", e); } // Use defaults if no valid highscores found if (!highscores || !highscores.length) { highscores = [{ name: "FRVR Player", score: 12500 }, { name: "Guest", score: 10000 }, { name: "Anonymous", score: 7500 }, { name: "Player 4", score: 5000 }, { name: "Player 5", score: 2500 }]; } // Sort highscores by score (descending) highscores.sort(function (a, b) { return b.score - a.score; }); // Display top 5 highscores var maxToShow = Math.min(highscores.length, 5); for (var i = 0; i < maxToShow; i++) { var scoreEntry = new Text2(i + 1 + ". " + highscores[i].name + ": " + highscores[i].score, { size: 80, fill: i === 0 ? "#FFD700" : "#FFFFFF" // Gold for highest score }); scoreEntry.anchor.set(0.5, 0); scoreEntry.x = 2048 / 2; scoreEntry.y = 400 + i * 150; game.addChild(scoreEntry); highscoreTexts.push(scoreEntry); } // Add back button text var backText = new Text2("TAP ANYWHERE TO RETURN", { size: 70, fill: 0xFFFFFF }); backText.anchor.set(0.5, 0); backText.x = 2048 / 2; backText.y = 2200; game.addChild(backText); highscoreTexts.push(backText); // Check if there's a LK API for showing leaderboard as backup if (typeof LK.showLeaderboard === 'function') { // Add fallback to standard leaderboard LK.setTimeout(function () { if (showingHighscores) { // If our custom screen hasn't been dismissed after 5 seconds, show official leaderboard showingHighscores = false; if (highscoreBackground) { highscoreBackground.destroy(); highscoreBackground = null; } highscoreTexts.forEach(function (text) { text.destroy(); }); highscoreTexts = []; LK.showLeaderboard(); } }, 5000); } } // Add interactive behavior to buttons startButton.interactive = true; startButton.buttonMode = true; startButton.down = function () { startGame(); }; highscoreButton.interactive = true; highscoreButton.buttonMode = true; highscoreButton.down = function () { showHighscore(); }; game.down = function (x, y, obj) { // Handle tapping on highscore screen to return to intro if (showingHighscores) { showHighscore(); // This will toggle off the highscore display return; } // Only process player dragging if game has started if (isGameStarted && player) { // Check if touch is on the player UFO var localPos = player.toLocal(game.toGlobal({ x: x, y: y })); // Convert game coords to player's local coords // Use a slightly larger hit area for easier dragging var hitWidth = player.width * 1.5; var hitHeight = player.height * 1.5; if (Math.abs(localPos.x) < hitWidth / 2 && Math.abs(localPos.y) < hitHeight / 2) { dragNode = player; // Instantly move player to touch position for responsive feel var gamePos = game.toLocal(obj.global); // Use obj.global for precise position player.x = gamePos.x; player.y = gamePos.y; player.clampPosition(); } else { dragNode = null; } } }; game.move = function (x, y, obj) { if (dragNode) { var gamePos = game.toLocal(obj.global); // Convert event global position to game coordinates dragNode.x = gamePos.x; dragNode.y = gamePos.y; // Clamp player position within bounds immediately after move if (dragNode === player) { player.clampPosition(); } } }; game.up = function (x, y, obj) { dragNode = null; }; // Game Update Logic game.update = function () { // If game hasn't started yet or player is gone, don't process game logic if (!isGameStarted || !player || player.destroyed) { // Make sure score is hidden during intro scoreTxt.visible = false; return; // Game not started or player fully gone, nothing to do. } // Make sure score is visible during gameplay scoreTxt.visible = true; // If player is dead, stop their specific logic & wait for respawn/game over timeout // Other game elements (enemies, bullets) might still update. // Player input and collisions will be gated by player.isDead or invincibility. // Player invincibility blinking if (player && !player.isDead && LK.ticks < player.invincibleUntil) { player.alpha = LK.ticks % 20 < 10 ? 0.5 : 1; // Blink } else if (player && !player.isDead && player.alpha !== 1) { player.alpha = 1; // Ensure alpha is reset } // --- Global Updates --- // Player Shooting playerFireCooldown++; if (!player.isDead && dragNode === player && playerFireCooldown >= playerFireRate) { // Only shoot while dragging/controlling and alive playerFireCooldown = 0; var bullet = new PlayerBullet(player.x + player.width / 2, player.y); game.addChild(bullet); playerBullets.push(bullet); LK.getSound('playerShoot').play(); } // Score increases over time scoreIncrementTimer++; if (scoreIncrementTimer >= 60) { // Add 10 points every second scoreIncrementTimer = 0; LK.setScore(LK.getScore() + 10); scoreTxt.setText(LK.getScore()); } // --- Phase Management --- var elapsedTicks = LK.ticks - phaseStartTime; if (gamePhase === 0 && elapsedTicks >= phaseDuration) { // Transition to Phase 1 (Space) gamePhase = 1; phaseStartTime = LK.ticks; // Reset timer for next phase if needed console.log("Transitioning to Phase 1: Space"); // Clean up terrain-specific elements terrainSegmentsTop.forEach(function (s) { return s.destroy(); }); terrainSegmentsBottom.forEach(function (s) { return s.destroy(); }); mountains.forEach(function (m) { return m.destroy(); }); groundEnemies.forEach(function (ge) { return ge.destroy(); }); terrainSegmentsTop = []; terrainSegmentsBottom = []; mountains = []; groundEnemies = []; // Spawn initial air enemies for (var i = 0; i < 5; i++) { // Start with 5 air enemies spawnAirEnemy(); } LK.playMusic('phase2Music'); // Switch music } else if (gamePhase === 1 && elapsedTicks >= phaseDuration * 1.5) { // Example: Boss after 1.5x phase duration // Transition to Phase 2 (Boss) if (!boss) { // Ensure boss only spawns once gamePhase = 2; phaseStartTime = LK.ticks; console.log("Transitioning to Phase 2: Boss"); // Clean up air enemies airEnemies.forEach(function (ae) { return ae.destroy(); }); airEnemies = []; // Spawn Boss boss = new Boss(); game.addChild(boss); LK.playMusic('bossMusic'); // Boss music } } // --- Phase 1: Terrain Logic --- if (gamePhase === 0) { // Update and manage terrain segments var terrainWidth = LK.getAsset('terrain', {}).width; for (var i = terrainSegmentsTop.length - 1; i >= 0; i--) { var segment = terrainSegmentsTop[i]; if (segment.x < -terrainWidth) { // Reposition segment to the right var maxX = 0; terrainSegmentsTop.forEach(function (s) { if (s.x > maxX) { maxX = s.x; } }); segment.x = maxX + terrainWidth; // Always spawn an enemy on the reused segment spawnGroundEnemy(segment); // Additionally, 50% chance for a mountain if (Math.random() < 0.5) { spawnMountain(segment); } } } // Repeat for bottom terrain for (var i = terrainSegmentsBottom.length - 1; i >= 0; i--) { var segment = terrainSegmentsBottom[i]; if (segment.x < -terrainWidth) { var maxX = 0; terrainSegmentsBottom.forEach(function (s) { if (s.x > maxX) { maxX = s.x; } }); segment.x = maxX + terrainWidth; // Always spawn an enemy on the reused segment spawnGroundEnemy(segment); // Additionally, 50% chance for a mountain if (Math.random() < 0.5) { spawnMountain(segment); } } } // Update mountains & check collision for (var i = mountains.length - 1; i >= 0; i--) { var mountain = mountains[i]; if (mountain.x < -mountain.width) { mountain.destroy(); mountains.splice(i, 1); } else { if (!player.isDead && LK.ticks > player.invincibleUntil && player.intersects(mountain)) { handlePlayerDeath(); return; // Stop update processing } } } // Update ground enemies & check collision for (var i = groundEnemies.length - 1; i >= 0; i--) { var enemy = groundEnemies[i]; if (enemy.x < -enemy.width) { enemy.destroy(); groundEnemies.splice(i, 1); } else { // Collision check: Player vs Ground Enemy if (!player.isDead && LK.ticks > player.invincibleUntil && player.intersects(enemy)) { LK.getSound('enemyExplosion').play(); //{3L} // Enemy explodes enemy.destroy(); // Destroy enemy on collision too groundEnemies.splice(i, 1); handlePlayerDeath(); return; } } } // Re-clamp player position based on potentially moving terrain (simple clamp for now) player.clampPosition(); } // --- Phase 1/2: Air Enemy Logic --- if (gamePhase === 1) { // Add more air enemies periodically? if (LK.ticks % 180 === 0 && airEnemies.length < 10) { // Spawn if less than 10, every 3 seconds spawnAirEnemy(); } // Update air enemies & check collision for (var i = airEnemies.length - 1; i >= 0; i--) { var enemy = airEnemies[i]; // Air enemies handle their own off-screen logic (respawn) in their update // Collision check: Player vs Air Enemy if (!player.isDead && LK.ticks > player.invincibleUntil && player.intersects(enemy)) { LK.getSound('enemyExplosion').play(); //{41} // Enemy explodes enemy.destroy(); // Destroy enemy on collision airEnemies.splice(i, 1); // LK.setScore(LK.getScore() + 50); // Score for destroying enemy - player died, maybe no score for this? Or keep it. Let's keep for now. // scoreTxt.setText(LK.getScore()); handlePlayerDeath(); return; } } } // --- Phase 3: Boss Logic --- if (gamePhase === 2 && boss) { // Check collision: Player vs Boss if (!player.isDead && LK.ticks > player.invincibleUntil && player.intersects(boss)) { // Don't destroy boss on collision handlePlayerDeath(); return; } // Update boss lasers & check collision for (var i = bossLasers.length - 1; i >= 0; i--) { var laser = bossLasers[i]; // Check if laser is off-screen if (laser.x < -laser.width || laser.x > 2048 + laser.width || laser.y < -laser.height || laser.y > 2732 + laser.height) { laser.destroy(); bossLasers.splice(i, 1); } else { // Collision check: Player vs Boss Laser if (!player.isDead && LK.ticks > player.invincibleUntil && player.intersects(laser)) { laser.destroy(); // Destroy laser bossLasers.splice(i, 1); handlePlayerDeath(); return; } } } // Note: Boss defeat condition is now handled within the player bullet collision check loop. } // --- Update Enemy Bullets & Check Collision (All Phases) --- for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; // Check if bullet is off-screen if (bullet.y < -bullet.height || bullet.y > 2732 + bullet.height) { bullet.destroy(); enemyBullets.splice(i, 1); } else { // Collision check: Player vs Enemy Bullet if (!player.isDead && LK.ticks > player.invincibleUntil && player.intersects(bullet)) { bullet.destroy(); // Destroy bullet enemyBullets.splice(i, 1); handlePlayerDeath(); // This function now handles the delay and sound return; // Stop update processing } } } // Helper function to save highscore function saveHighscore(score) { // Get existing highscores or create empty array var highscores = []; try { // Try to parse the serialized highscores data if (storage.highscoresData) { highscores = JSON.parse(storage.highscoresData); } } catch (e) { console.log("Error parsing existing highscores:", e); highscores = []; } // Get player name from Upit if available var playerName = "FRVR Player"; // Default fallback name // Check if we have user info available through Upit if (LK.profile && LK.profile.name) { playerName = LK.profile.name; // Use real player name } else if (LK.profile && LK.profile.id) { playerName = "Player " + LK.profile.id.substring(0, 5); // Use ID fragment if no name } // Add new score entry (always add it, we'll sort and filter afterward) highscores.push({ name: playerName, score: score }); // Sort highscores by score (descending) highscores.sort(function (a, b) { return b.score - a.score; }); // Keep only top 10 scores if (highscores.length > 10) { highscores = highscores.slice(0, 10); } // Save back to storage - serialize scores to avoid complex objects // The storage only supports literal values and simple structures // Convert highscores array to string to ensure compatibility try { // Convert the complex object to a JSON string var highscoresString = JSON.stringify(highscores); // Store the string representation storage.highscoresData = highscoresString; // When retrieving it, we'll need to parse it back - modify the retrieval in showHighscore function } catch (e) { console.log("Error saving highscores:", e); } } // --- Update Player Bullets & Check Collision --- for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; // Check if bullet is off-screen (right side) if (bullet.x > 2048 + bullet.width) { bullet.destroy(); playerBullets.splice(i, 1); continue; // Skip collision checks if off-screen } // Collision Check: Player Bullet vs Ground Enemy (Phase 0) if (gamePhase === 0) { for (var j = groundEnemies.length - 1; j >= 0; j--) { var enemy = groundEnemies[j]; if (bullet.intersects(enemy)) { LK.getSound('enemyExplosion').play(); LK.effects.flashObject(enemy, 0xFFFFFF, 100); // Flash enemy white enemy.destroy(); groundEnemies.splice(j, 1); bullet.destroy(); playerBullets.splice(i, 1); LK.setScore(LK.getScore() + 100); // Score for destroying ground enemy scoreTxt.setText(LK.getScore()); break; // Bullet can only hit one enemy } } if (!bullet.exists) { continue; } // Check if bullet was destroyed in previous loop } // Collision Check: Player Bullet vs Air Enemy (Phase 1) if (gamePhase === 1) { for (var j = airEnemies.length - 1; j >= 0; j--) { var enemy = airEnemies[j]; if (bullet.intersects(enemy)) { LK.getSound('enemyExplosion').play(); LK.effects.flashObject(enemy, 0xFFFFFF, 100); // Flash enemy white enemy.destroy(); airEnemies.splice(j, 1); bullet.destroy(); playerBullets.splice(i, 1); LK.setScore(LK.getScore() + 150); // Score for destroying air enemy scoreTxt.setText(LK.getScore()); break; // Bullet can only hit one enemy } } if (!bullet.exists) { continue; } // Check if bullet was destroyed in previous loop } // Collision Check: Player Bullet vs Boss (Phase 2) if (gamePhase === 2 && boss) { if (bullet.intersects(boss)) { LK.getSound('enemyExplosion').play(); // Use enemy explosion for hit sound LK.effects.flashObject(boss, 0xFFFFFF, 100); // Flash boss white bullet.destroy(); playerBullets.splice(i, 1); boss.health -= 1; // Decrease boss health LK.setScore(LK.getScore() + 10); // Small score for hitting boss scoreTxt.setText(LK.getScore()); // Boss defeat check is now inside the bullet loop if (boss.health <= 0) { LK.getSound('bossExplosion').play(); // Play boss explosion sound boss.destroy(); boss = null; // Cleanup remaining lasers bossLasers.forEach(function (l) { return l.destroy(); }); bossLasers = []; LK.setScore(LK.getScore() + 5000); // Big score bonus scoreTxt.setText(LK.getScore()); // Save highscore before showing You Win saveHighscore(LK.getScore()); // Delay showing YouWin slightly to allow sound to play LK.setTimeout(function () { LK.showYouWin(); }, 500); // Adjust delay as needed for sound length return; // Stop update processing } break; // Bullet is destroyed after hitting boss } } } // End of playerBullets loop };
===================================================================
--- original.js
+++ change.js
@@ -425,9 +425,8 @@
}
// Start Phase 1 Music
LK.playMusic('phase1Music');
}
-// This function has been moved before handlePlayerDeath to avoid the error
// Helper function to handle player death
function handlePlayerDeath() {
if (!player || player.isDead) {
return;
Alien Airships of boss, HD colors. In-Game asset. 2d. High contrast. No shadows
pack mountain, yellow, HD colors. In-Game asset. 2d. High contrast. No shadows.no black lines
shot circle. blur, light, HD colors In-Game asset. 2d. High contrast. No shadows
gunTurret aiming diagonal. yellow, HD colors. In-Game asset. 2d. High contrast. No shadows
Square & diagonal tank enemies from the future have 4 turrets on its 4 sides, HD colors. In-Game asset. 2d. High contrast. No shadows