User prompt
Ana menü butonuna tıklanıldığında ve Store butonuna tıklanıldığında oyun durmalı
User prompt
Ana menü butonuna tıklanıldığında Mağaza Butonu olmalı
User prompt
Please fix the bug: 'Uncaught TypeError: LK.pauseGame is not a function' in or related to this line: 'LK.pauseGame();' Line Number: 417
User prompt
Ana menü butonunu dahada aşağıya koy
User prompt
Menu yazısı biraz daha aşağıda olmalı
User prompt
Ekrana ana Menü butonu ekle
User prompt
Coin ve diğer metinler biraz dahada gözükmesi gerek
User prompt
Metinler dahada görünür olmalı
User prompt
Eğer Cam Ballı geçerse 1 canımız gitmeli
User prompt
Her cama vurulduğunda canımız gitmesin
User prompt
Canımızın gittiği gözükmeli
User prompt
İki kere Mouse tıklanırsa Ball yükseğe zıplamalı
User prompt
Eğer Ball camı kıramassa 1 canı gitmeli
User prompt
Oyundaki Leveller biraz uzun olsun
User prompt
Oyunda coinler her level kazandığımızda 500 olarak verilmeli ↪💡 Consider importing and using the following plugins: @upit/storage.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Glass Smasher: First-Person Ball
Initial prompt
Create a 2D first-person-style game where the player controls a metal ball from its own point of view (POV). The game starts at Level 1, and in each level, the player must smash through glass obstacles to progress. The ball automatically moves forward, and the player can control its speed and jump. If the ball fails to break a glass, it loses 1 life. The player has 3 lives total. After breaking all required glass pieces in a level, the player earns 500 coins. Coins can be used in the shop to buy new balls with unique appearances and superpowers, such as: Fireball mode (instantly melts glass), Shockwave burst (breaks multiple glasses at once), Time slow (slows time to react faster), Steel upgrade (makes the ball stronger for 10 seconds). As levels progress, the glass becomes thicker, moves, or includes trap glass (explodes or reduces vision). The game gets harder with each level, adding new challenges and faster pace. The camera is always from the ball’s perspective, creating a fast, immersive, smashing experience. Add background music, particle effects on smash, and intense sound design. Make the game visually satisfying. Include a main menu, a level selection screen, and a shop interface. Make it playable with keyboard or touch controls.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { coins: 0, highScore: 0, ballLevel: 1, speedLevel: 1 }); /**** * Classes ****/ var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1 }); self.velocityY = 0; self.gravity = 0.5; self.jumpForce = -15; self.grounded = false; self.canJump = true; self.health = 3; self.speed = 5 + (storage.speedLevel - 1) * 2; self.radius = 50; self.power = storage.ballLevel; // Set color based on ball level/power if (self.power === 2) { ballGraphics.tint = 0xFF6600; // Orange for fireball } else if (self.power === 3) { ballGraphics.tint = 0xFFD700; // Gold color for golden ball } else if (self.power === 4) { ballGraphics.tint = 0x666666; // Dark gray for steel } else if (self.power === 5) { ballGraphics.tint = 0x88CCFF; // Light blue for ice ball } else if (self.power === 6) { ballGraphics.tint = 0x00FF00; // Green color for poison ball } else if (self.power === 7) { ballGraphics.tint = 0x333333; // Dark color for dark ball } self.jump = function (isDoubleJump) { if (self.grounded && self.canJump) { // Higher jump force for double-click if (isDoubleJump) { self.velocityY = self.jumpForce * 1.5; // 50% higher jump LK.effects.flashObject(self, 0x00FF00, 300); // Visual feedback - green flash } else { self.velocityY = self.jumpForce; } self.grounded = false; LK.getSound('jump').play(); // Jump cooldown self.canJump = false; LK.setTimeout(function () { self.canJump = true; }, 300); } }; self.takeDamage = function () { self.health--; LK.getSound('damage').play(); LK.effects.flashObject(self, 0xFF0000, 500); // Visual feedback for health loss var healthLossText = new Text2("-1 Health!", { size: 90, fill: 0xFF0000, stroke: 0x000000, strokeThickness: 5 }); healthLossText.anchor.set(0.5, 0.5); healthLossText.x = self.x; healthLossText.y = self.y - 100; game.addChild(healthLossText); // Animate and remove tween(healthLossText, { y: healthLossText.y - 150, alpha: 0 }, { duration: 800, onFinish: function onFinish() { game.removeChild(healthLossText); } }); // Update the health display updateHealthDisplay(); if (self.health <= 0) { LK.showGameOver(); } }; self.update = function () { // Apply gravity self.velocityY += self.gravity; self.y += self.velocityY; // Visual rotation to simulate rolling ballGraphics.rotation += 0.05 * self.speed; // Ground collision if (self.y + self.radius > groundY) { self.y = groundY - self.radius; self.velocityY = 0; self.grounded = true; } }; return self; }); var Coin = Container.expand(function () { var self = Container.call(this); var coinGraphics = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); self.collected = false; self.collect = function () { if (!self.collected) { self.collected = true; LK.getSound('coinCollect').play(); // Animation tween(self, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 300, onFinish: function onFinish() { self.destroy(); } }); // Update coins storage.coins += 1; updateCoinsDisplay(); } }; self.update = function () { // Coin rotation animation coinGraphics.rotation += 0.05; // Move coin toward player self.x -= ball.speed; // Floating animation self.y += Math.sin(LK.ticks / 10) * 0.5; // Remove if passed player if (self.x < -100) { if (collectibles.indexOf(self) !== -1) { collectibles.splice(collectibles.indexOf(self), 1); } self.destroy(); } }; return self; }); var Glass = Container.expand(function () { var self = Container.call(this); var glassGraphics = self.attachAsset('glass', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); self.width = glassGraphics.width; self.height = glassGraphics.height; self.broken = false; self.health = 1; self.type = 'normal'; // normal, moving, trap self.movingDirection = 1; self.movingSpeed = 0; self.lastPassed = false; // Track if ball has passed through this glass self.setup = function (type, difficulty) { self.type = type || 'normal'; self.health = difficulty || 1; if (self.type === 'moving') { self.movingSpeed = Math.random() * 3 + 2; glassGraphics.tint = 0x33CCFF; } else if (self.type === 'trap') { glassGraphics.tint = 0xFF3333; } }; self["break"] = function () { if (!self.broken) { self.broken = true; LK.getSound('glassBreak').play(); // Create glass breaking particles self.createParticles(); // Remove from active obstacles after animation LK.setTimeout(function () { if (obstacles.includes(self)) { var index = obstacles.indexOf(self); if (index !== -1) { obstacles.splice(index, 1); } } self.destroy(); }, 100); } }; self.createParticles = function () { for (var i = 0; i < 8; i++) { var particle = LK.getAsset('particleGlass', { anchorX: 0.5, anchorY: 0.5, x: self.x + (Math.random() * 100 - 50), y: self.y + (Math.random() * 100 - 50), alpha: 0.8 }); game.addChild(particle); // Animate particle flying out var targetX = particle.x + (Math.random() * 200 - 100); var targetY = particle.y + (Math.random() * 200 - 100); tween(particle, { x: targetX, y: targetY, alpha: 0, rotation: Math.random() * Math.PI * 2 }, { duration: 500, onFinish: function onFinish() { particle.destroy(); } }); } }; self.takeDamage = function (power) { self.health -= power; LK.effects.flashObject(self, 0xFFFFFF, 100); if (self.health <= 0) { self["break"](); // If trap glass, damage player if (self.type === 'trap') { ball.takeDamage(); } // Add score based on glass type var scoreValue = 10; if (self.type === 'moving') scoreValue = 20; if (self.type === 'trap') scoreValue = 30; LK.setScore(LK.getScore() + scoreValue); updateScoreDisplay(); } else { // Just show crack effect glassGraphics.alpha -= 0.2; } }; self.update = function () { if (self.type === 'moving' && !self.broken) { self.y += self.movingDirection * self.movingSpeed; // Reverse direction when reaching boundaries if (self.y < 500 || self.y > groundY - 400) { self.movingDirection *= -1; } } // Move obstacle toward player (creating the effect of moving forward) self.x -= ball.speed; // Remove if passed player if (self.x < -300) { if (obstacles.includes(self)) { var index = obstacles.indexOf(self); if (index !== -1) { obstacles.splice(index, 1); } } self.destroy(); } }; return self; }); var Powerup = Container.expand(function () { var self = Container.call(this); var type = "speed"; // Default var graphics; self.setup = function (powerupType) { type = powerupType || "speed"; if (type === "speed") { graphics = self.attachAsset('speedBoost', { anchorX: 0.5, anchorY: 0.5 }); } else if (type === "health") { graphics = self.attachAsset('health', { anchorX: 0.5, anchorY: 0.5 }); } }; self.collect = function () { LK.getSound('coinCollect').play(); if (type === "speed") { // Temporary speed boost var originalSpeed = ball.speed; ball.speed += 5; LK.setTimeout(function () { ball.speed = originalSpeed; }, 5000); } else if (type === "health") { // Health up to maximum 5 if (ball.health < 5) { ball.health++; updateHealthDisplay(); } } // Animation tween(self, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 300, onFinish: function onFinish() { self.destroy(); } }); if (collectibles.indexOf(self) !== -1) { collectibles.splice(collectibles.indexOf(self), 1); } }; self.update = function () { // Rotate the powerup if (graphics) { graphics.rotation += 0.05; } // Move powerup toward player self.x -= ball.speed; // Floating animation self.y += Math.sin(LK.ticks / 8) * 0.7; // Remove if passed player if (self.x < -100) { if (collectibles.indexOf(self) !== -1) { collectibles.splice(collectibles.indexOf(self), 1); } self.destroy(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB // Sky blue background }); /**** * Game Code ****/ // Game variables var obstacles = []; var collectibles = []; var groundY = 2732 - 250; // Ground position var distance = 0; var nextObstacleDistance = 500; var level = 1; var levelDistance = 2500; // Distance required to advance a level - increased for longer levels var isPaused = false; var upgradeMenuOpen = false; var lastClickTime = 0; var doubleClickSpeed = 300; // Time in ms between clicks to count as double-click var fireballUsesCount = 0; // Track the number of times the fireball button is used var maxFireballUses = 3; // Maximum number of times the fireball button can be used // Initialize ground var ground = LK.getAsset('ground', { anchorX: 0.5, anchorY: 0, scaleX: 1, scaleY: 1 }); ground.x = 2048 / 2; ground.y = groundY; game.addChild(ground); // Create player ball with steel (metal) appearance var ball = new Ball(); ball.x = 400; ball.y = groundY - ball.radius; // Set initial ball to be steel/metal type ball.power = 4; // Level 4 is steel/metal ball ball.children[0].tint = 0x666666; // Dark gray for steel game.addChild(ball); // Create UI elements // Main menu button var menuButton = new Container(); var menuButtonBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.25, tint: 0x555555 }); menuButton.addChild(menuButtonBg); var menuButtonText = new Text2("MENU", { size: 70, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 3 }); menuButtonText.anchor.set(0.5, 0.5); menuButtonText.y = 10; // Position the text a bit lower in the button menuButton.addChild(menuButtonText); menuButton.x = 120; menuButton.y = 200; // Moved further down LK.gui.topLeft.addChild(menuButton); // Fireball button removed // Handle menu button interactions menuButton.interactive = true; menuButton.down = function (x, y, obj) { LK.effects.flashObject(menuButton, 0xFFFFFF, 200); // Toggle pause when menu button is clicked isPaused = !isPaused; if (isPaused) { // Create store button var storeButton = new Container(); var storeButtonBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.3, tint: 0x333333 }); storeButton.addChild(storeButtonBg); var storeButtonText = new Text2("STORE", { size: 80, fill: 0xFFD700, stroke: 0x000000, strokeThickness: 4 }); storeButtonText.anchor.set(0.5, 0.5); storeButtonText.y = 10; storeButton.addChild(storeButtonText); storeButton.x = 2048 / 2; storeButton.y = 2732 / 2; game.addChild(storeButton); // Store button interaction storeButton.interactive = true; storeButton.down = function (x, y, obj) { LK.effects.flashObject(storeButton, 0xFFFFFF, 200); // Game should stay paused when store button is clicked isPaused = true; // Remove store button when clicked game.removeChild(storeButton); // Create full-screen store page var storePage = new Container(); // Background covering the entire screen var storePageBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 20, scaleY: 40, tint: 0x222222, alpha: 0.95 }); storePage.addChild(storePageBg); storePage.x = 2048 / 2; storePage.y = 2732 / 2; game.addChild(storePage); // Store page title var storeTitle = new Text2("STORE", { size: 150, fill: 0xFFD700, stroke: 0x000000, strokeThickness: 6 }); storeTitle.anchor.set(0.5, 0.5); storeTitle.y = -1000; storePage.addChild(storeTitle); // Display available coins var coinsDisplay = new Text2("Your Coins: " + storage.coins, { size: 100, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); coinsDisplay.anchor.set(0.5, 0.5); coinsDisplay.y = -800; storePage.addChild(coinsDisplay); // Fireball upgrade button var fireballButton = new Container(); var fireballBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.4, tint: 0xFF6600 }); fireballButton.addChild(fireballBg); var fireballText = new Text2("FIREBALL BALL - 1000 COINS", { size: 90, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); fireballText.anchor.set(0.5, 0.5); fireballButton.addChild(fireballText); fireballButton.y = -400; storePage.addChild(fireballButton); // Add interactive property fireballButton.interactive = true; fireballButton.down = function () { if (storage.coins >= 1000 && storage.ballLevel < 2) { // Purchase successful storage.coins -= 1000; storage.ballLevel = 2; updateCoinsDisplay(); // Update ball appearance immediately if (ball) { ball.power = 2; ball.children[0].tint = 0xFF6600; // Orange for fireball // Make fireball button visible since player now has fireball fireballButton.visible = true; } // Update ball level text ballLevelTxt.setText("Ball Power: " + storage.ballLevel); // Success message var successMsg = new Text2("PURCHASED! Fireball Activated!", { size: 80, fill: 0x00FF00, stroke: 0x000000, strokeThickness: 4 }); successMsg.anchor.set(0.5, 0.5); successMsg.y = 400; storePage.addChild(successMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(successMsg); }, 2000); } else if (storage.ballLevel >= 2) { // If fireball is already purchased, activate it if (ball.power !== 2) { // Change ball to fireball appearance ball.power = 2; ball.children[0].tint = 0xFF6600; // Orange for fireball // Success message var activateMsg = new Text2("Fireball Activated!", { size: 80, fill: 0x00FF00, stroke: 0x000000, strokeThickness: 4 }); activateMsg.anchor.set(0.5, 0.5); activateMsg.y = 400; storePage.addChild(activateMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(activateMsg); }, 2000); } else { // Already activated var alreadyMsg = new Text2("Fireball Already Active!", { size: 80, fill: 0xFFFF00, stroke: 0x000000, strokeThickness: 4 }); alreadyMsg.anchor.set(0.5, 0.5); alreadyMsg.y = 400; storePage.addChild(alreadyMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(alreadyMsg); }, 2000); } } else { // Not enough coins var errorMsg = new Text2("Not enough coins!", { size: 80, fill: 0xFF0000, stroke: 0x000000, strokeThickness: 4 }); errorMsg.anchor.set(0.5, 0.5); errorMsg.y = 400; storePage.addChild(errorMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(errorMsg); }, 2000); } // Update coins display coinsDisplay.setText("Your Coins: " + storage.coins); }; // Golden Ball upgrade button var goldenBallButton = new Container(); var goldenBallBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.4, tint: 0xFFD700 // Gold color }); goldenBallButton.addChild(goldenBallBg); var goldenBallText = new Text2("GOLDEN BALL - 2000 COINS", { size: 90, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); goldenBallText.anchor.set(0.5, 0.5); goldenBallButton.addChild(goldenBallText); goldenBallButton.y = -200; // Position below the fireball button storePage.addChild(goldenBallButton); // Add interactive property goldenBallButton.interactive = true; goldenBallButton.down = function () { if (storage.coins >= 2000 && storage.ballLevel < 3) { // Purchase successful storage.coins -= 2000; storage.ballLevel = 3; updateCoinsDisplay(); // Update ball appearance immediately if (ball) { ball.power = 3; ball.children[0].tint = 0xFFD700; // Gold color for golden ball } // Update ball level text ballLevelTxt.setText("Ball Power: " + storage.ballLevel); // Success message var successMsg = new Text2("PURCHASED! Golden Ball Activated!", { size: 80, fill: 0x00FF00, stroke: 0x000000, strokeThickness: 4 }); successMsg.anchor.set(0.5, 0.5); successMsg.y = 400; storePage.addChild(successMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(successMsg); }, 2000); } else if (storage.ballLevel >= 3) { // If golden ball is already purchased, activate it if (ball.power !== 3) { // Change ball to golden ball appearance ball.power = 3; ball.children[0].tint = 0xFFD700; // Gold color for golden ball // Success message var activateMsg = new Text2("Golden Ball Activated!", { size: 80, fill: 0x00FF00, stroke: 0x000000, strokeThickness: 4 }); activateMsg.anchor.set(0.5, 0.5); activateMsg.y = 400; storePage.addChild(activateMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(activateMsg); }, 2000); } else { // Already activated var alreadyMsg = new Text2("Golden Ball Already Active!", { size: 80, fill: 0xFFFF00, stroke: 0x000000, strokeThickness: 4 }); alreadyMsg.anchor.set(0.5, 0.5); alreadyMsg.y = 400; storePage.addChild(alreadyMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(alreadyMsg); }, 2000); } } else { // Not enough coins var errorMsg = new Text2("Not enough coins!", { size: 80, fill: 0xFF0000, stroke: 0x000000, strokeThickness: 4 }); errorMsg.anchor.set(0.5, 0.5); errorMsg.y = 400; storePage.addChild(errorMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(errorMsg); }, 2000); } // Update coins display coinsDisplay.setText("Your Coins: " + storage.coins); }; // Ice Ball upgrade button var iceBallButton = new Container(); var iceBallBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.4, tint: 0x88CCFF // Light blue color for ice }); iceBallButton.addChild(iceBallBg); var iceBallText = new Text2("ICE BALL - 3000 COINS", { size: 90, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); iceBallText.anchor.set(0.5, 0.5); iceBallButton.addChild(iceBallText); iceBallButton.y = 0; // Position below the golden ball button storePage.addChild(iceBallButton); // Poison Ball upgrade button var poisonBallButton = new Container(); var poisonBallBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.4, tint: 0x00FF00 // Green color for poison }); poisonBallButton.addChild(poisonBallBg); var poisonBallText = new Text2("POISON BALL - 4000 COINS", { size: 90, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); poisonBallText.anchor.set(0.5, 0.5); poisonBallButton.addChild(poisonBallText); poisonBallButton.y = 200; // Position below the ice ball button storePage.addChild(poisonBallButton); // Dark Ball upgrade button var darkBallButton = new Container(); var darkBallBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.4, tint: 0x333333 // Dark color for dark ball }); darkBallButton.addChild(darkBallBg); var darkBallText = new Text2("DARK BALL - 5000 COINS", { size: 90, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); darkBallText.anchor.set(0.5, 0.5); darkBallButton.addChild(darkBallText); darkBallButton.y = 400; // Position below the poison ball button storePage.addChild(darkBallButton); // Add interactive property iceBallButton.interactive = true; iceBallButton.down = function () { if (storage.coins >= 3000 && storage.ballLevel < 5) { // Purchase successful storage.coins -= 3000; storage.ballLevel = 5; updateCoinsDisplay(); // Update ball appearance immediately if (ball) { ball.power = 5; ball.children[0].tint = 0x88CCFF; // Light blue color for ice ball } // Update ball level text ballLevelTxt.setText("Ball Power: " + storage.ballLevel); // Success message var successMsg = new Text2("PURCHASED! Ice Ball Activated!", { size: 80, fill: 0x00FF00, stroke: 0x000000, strokeThickness: 4 }); successMsg.anchor.set(0.5, 0.5); successMsg.y = 400; storePage.addChild(successMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(successMsg); }, 2000); } else if (storage.ballLevel >= 5) { // If ice ball is already purchased, activate it if (ball.power !== 5) { // Change ball to ice ball appearance ball.power = 5; ball.children[0].tint = 0x88CCFF; // Light blue color for ice ball // Success message var activateMsg = new Text2("Ice Ball Activated!", { size: 80, fill: 0x00FF00, stroke: 0x000000, strokeThickness: 4 }); activateMsg.anchor.set(0.5, 0.5); activateMsg.y = 400; storePage.addChild(activateMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(activateMsg); }, 2000); } else { // Already activated var alreadyMsg = new Text2("Ice Ball Already Active!", { size: 80, fill: 0xFFFF00, stroke: 0x000000, strokeThickness: 4 }); alreadyMsg.anchor.set(0.5, 0.5); alreadyMsg.y = 400; storePage.addChild(alreadyMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(alreadyMsg); }, 2000); } } else { // Not enough coins var errorMsg = new Text2("Not enough coins!", { size: 80, fill: 0xFF0000, stroke: 0x000000, strokeThickness: 4 }); errorMsg.anchor.set(0.5, 0.5); errorMsg.y = 400; storePage.addChild(errorMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(errorMsg); }, 2000); } // Update coins display coinsDisplay.setText("Your Coins: " + storage.coins); }; // Add interactive property for Poison Ball poisonBallButton.interactive = true; poisonBallButton.down = function () { if (storage.coins >= 4000 && storage.ballLevel < 6) { // Purchase successful storage.coins -= 4000; storage.ballLevel = 6; updateCoinsDisplay(); // Update ball appearance immediately if (ball) { ball.power = 6; ball.children[0].tint = 0x00FF00; // Green color for poison ball } // Update ball level text ballLevelTxt.setText("Ball Power: " + storage.ballLevel); // Success message var successMsg = new Text2("PURCHASED! Poison Ball Activated!", { size: 80, fill: 0x00FF00, stroke: 0x000000, strokeThickness: 4 }); successMsg.anchor.set(0.5, 0.5); successMsg.y = 400; storePage.addChild(successMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(successMsg); }, 2000); } else if (storage.ballLevel >= 6) { // If poison ball is already purchased, activate it if (ball.power !== 6) { // Change ball to poison ball appearance ball.power = 6; ball.children[0].tint = 0x00FF00; // Green color for poison ball // Success message var activateMsg = new Text2("Poison Ball Activated!", { size: 80, fill: 0x00FF00, stroke: 0x000000, strokeThickness: 4 }); activateMsg.anchor.set(0.5, 0.5); activateMsg.y = 400; storePage.addChild(activateMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(activateMsg); }, 2000); } else { // Already activated var alreadyMsg = new Text2("Poison Ball Already Active!", { size: 80, fill: 0xFFFF00, stroke: 0x000000, strokeThickness: 4 }); alreadyMsg.anchor.set(0.5, 0.5); alreadyMsg.y = 400; storePage.addChild(alreadyMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(alreadyMsg); }, 2000); } } else { // Not enough coins var errorMsg = new Text2("Not enough coins!", { size: 80, fill: 0xFF0000, stroke: 0x000000, strokeThickness: 4 }); errorMsg.anchor.set(0.5, 0.5); errorMsg.y = 400; storePage.addChild(errorMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(errorMsg); }, 2000); } // Update coins display coinsDisplay.setText("Your Coins: " + storage.coins); }; // Add interactive property for Dark Ball darkBallButton.interactive = true; darkBallButton.down = function () { if (storage.coins >= 5000 && storage.ballLevel < 7) { // Purchase successful storage.coins -= 5000; storage.ballLevel = 7; updateCoinsDisplay(); // Update ball appearance immediately if (ball) { ball.power = 7; ball.children[0].tint = 0x333333; // Dark color for dark ball } // Update ball level text ballLevelTxt.setText("Ball Power: " + storage.ballLevel); // Success message var successMsg = new Text2("PURCHASED! Dark Ball Activated!", { size: 80, fill: 0x00FF00, stroke: 0x000000, strokeThickness: 4 }); successMsg.anchor.set(0.5, 0.5); successMsg.y = 400; storePage.addChild(successMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(successMsg); }, 2000); } else if (storage.ballLevel >= 7) { // If dark ball is already purchased, activate it if (ball.power !== 7) { // Change ball to dark ball appearance ball.power = 7; ball.children[0].tint = 0x333333; // Dark color for dark ball // Success message var activateMsg = new Text2("Dark Ball Activated!", { size: 80, fill: 0x00FF00, stroke: 0x000000, strokeThickness: 4 }); activateMsg.anchor.set(0.5, 0.5); activateMsg.y = 400; storePage.addChild(activateMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(activateMsg); }, 2000); } else { // Already activated var alreadyMsg = new Text2("Dark Ball Already Active!", { size: 80, fill: 0xFFFF00, stroke: 0x000000, strokeThickness: 4 }); alreadyMsg.anchor.set(0.5, 0.5); alreadyMsg.y = 400; storePage.addChild(alreadyMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(alreadyMsg); }, 2000); } } else { // Not enough coins var errorMsg = new Text2("Not enough coins!", { size: 80, fill: 0xFF0000, stroke: 0x000000, strokeThickness: 4 }); errorMsg.anchor.set(0.5, 0.5); errorMsg.y = 400; storePage.addChild(errorMsg); // Make message disappear after a while LK.setTimeout(function () { storePage.removeChild(errorMsg); }, 2000); } // Update coins display coinsDisplay.setText("Your Coins: " + storage.coins); }; // Next button var nextButton = new Container(); var nextButtonBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.3, tint: 0x006600 }); nextButton.addChild(nextButtonBg); var nextButtonText = new Text2("NEXT", { size: 80, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); nextButtonText.anchor.set(0.5, 0.5); nextButton.addChild(nextButtonText); nextButton.x = 250; nextButton.y = 1000; storePage.addChild(nextButton); // Add interactive property nextButton.interactive = true; nextButton.down = function () { // Flash button when clicked LK.effects.flashObject(nextButton, 0xFFFFFF, 200); // Hide current store page storePage.visible = false; // Create new page var newPage = new Container(); // Background covering the entire screen var newPageBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 20, scaleY: 40, tint: 0x222266, // Slightly different background color alpha: 0.95 }); newPage.addChild(newPageBg); newPage.x = 2048 / 2; newPage.y = 2732 / 2; game.addChild(newPage); // New page title var newPageTitle = new Text2("MORE UPGRADES", { size: 150, fill: 0xFFD700, stroke: 0x000000, strokeThickness: 6 }); newPageTitle.anchor.set(0.5, 0.5); newPageTitle.y = -1000; newPage.addChild(newPageTitle); // Display available coins var coinsDisplay = new Text2("Your Coins: " + storage.coins, { size: 100, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); coinsDisplay.anchor.set(0.5, 0.5); coinsDisplay.y = -800; newPage.addChild(coinsDisplay); // Add Fire Power Button var firePowerButton = new Container(); var firePowerBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.4, tint: 0xFF3300 // Fire red-orange color }); firePowerButton.addChild(firePowerBg); var firePowerText = new Text2("FIRE POWER - 2000 COINS", { size: 90, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); firePowerText.anchor.set(0.5, 0.5); firePowerButton.addChild(firePowerText); firePowerButton.y = -600; // Position above speed upgrade button newPage.addChild(firePowerButton); // Add Coming Soon text for Super Powers section var comingSoonText = new Text2("COMING SOON", { size: 120, fill: 0xFFFF00, stroke: 0x000000, strokeThickness: 6 }); comingSoonText.anchor.set(0.5, 0.5); comingSoonText.y = -350; // Position below the Fire Power button newPage.addChild(comingSoonText); // Add interactive property firePowerButton.interactive = true; firePowerButton.down = function () { // Create fireballButton on the main game screen var fireballButtonOnGame = new Container(); var fireballButtonBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.3, tint: 0xFF6600 // Orange for fireball }); fireballButtonOnGame.addChild(fireballButtonBg); var fireballButtonText = new Text2("Ateş Topu Butonu (3/3)", { size: 90, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); fireballButtonText.anchor.set(0.5, 0.5); fireballButtonOnGame.addChild(fireballButtonText); fireballButtonOnGame.x = 400; // Position more to the left side fireballButtonOnGame.y = 2732 / 2; game.addChild(fireballButtonOnGame); // Make fireball button interactive fireballButtonOnGame.interactive = true; fireballButtonOnGame.down = function () { // Check if we still have uses left if (fireballUsesCount < maxFireballUses) { // Increment the usage counter fireballUsesCount++; // Update the button text to show remaining uses fireballButtonText.setText("Ateş Topu Butonu (" + (maxFireballUses - fireballUsesCount) + "/3)"); // Burn all glass obstacles for (var i = 0; i < obstacles.length; i++) { var obstacle = obstacles[i]; if (obstacle instanceof Glass && !obstacle.broken) { // Create fire effect on the glass LK.effects.flashObject(obstacle, 0xFF6600, 500); // Make glass burn with animated tint tween(obstacle.children[0], { tint: 0xFF3300 }, { duration: 500, onFinish: function onFinish() { // Store obstacle reference in a safer way to avoid cross-origin issues var glassObstacle = obstacle; // Check if glass obstacle exists and isn't broken yet if (glassObstacle && typeof glassObstacle.broken !== 'undefined' && !glassObstacle.broken) { glassObstacle["break"](); } } }); } } // If we've used all attempts, remove the button if (fireballUsesCount >= maxFireballUses) { // Show message before removing fireballButtonText.setText("Ateş Topu Hakkı Bitti!"); // Wait a moment to show the message before removing LK.setTimeout(function () { // Remove button from game game.removeChild(fireballButtonOnGame); }, 1000); } } }; // Display only fireball button text when button is clicked var fireballText = new Text2("Ateş Topu Butonu", { size: 100, fill: 0xFFFF00, stroke: 0x000000, strokeThickness: 5 }); fireballText.anchor.set(0.5, 0.5); fireballText.y = -200; newPage.addChild(fireballText); if (storage.coins >= 2000) { // Purchase successful storage.coins -= 2000; updateCoinsDisplay(); // Add fire power effect var successMsg = new Text2("PURCHASED! Fire Power Upgraded!", { size: 80, fill: 0x00FF00, stroke: 0x000000, strokeThickness: 4 }); successMsg.anchor.set(0.5, 0.5); successMsg.y = 400; newPage.addChild(successMsg); // Make message disappear after a while LK.setTimeout(function () { newPage.removeChild(successMsg); }, 2000); // Update coins display coinsDisplay.setText("Your Coins: " + storage.coins); } else { // Not enough coins var errorMsg = new Text2("Not enough coins!", { size: 80, fill: 0xFF0000, stroke: 0x000000, strokeThickness: 4 }); errorMsg.anchor.set(0.5, 0.5); errorMsg.y = 400; newPage.addChild(errorMsg); // Make message disappear after a while LK.setTimeout(function () { newPage.removeChild(errorMsg); }, 2000); } }; // Add speed upgrade button var speedUpgradeButton = new Container(); var speedUpgradeBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.4, tint: 0x00AAFF }); speedUpgradeButton.addChild(speedUpgradeBg); var speedUpgradeText = new Text2("SPEED UPGRADE - 1000 COINS", { size: 90, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); speedUpgradeText.anchor.set(0.5, 0.5); speedUpgradeButton.addChild(speedUpgradeText); speedUpgradeButton.y = -400; newPage.addChild(speedUpgradeButton); // Add interactive property speedUpgradeButton.interactive = true; speedUpgradeButton.down = function () { if (storage.coins >= 1000) { // Purchase successful storage.coins -= 1000; storage.speedLevel += 1; updateCoinsDisplay(); // Update speed display ball.speed = 5 + (storage.speedLevel - 1) * 2; speedLevelTxt.setText("Speed: " + storage.speedLevel); // Success message var successMsg = new Text2("PURCHASED! Speed Upgraded!", { size: 80, fill: 0x00FF00, stroke: 0x000000, strokeThickness: 4 }); successMsg.anchor.set(0.5, 0.5); successMsg.y = 400; newPage.addChild(successMsg); // Make message disappear after a while LK.setTimeout(function () { newPage.removeChild(successMsg); }, 2000); // Update coins display coinsDisplay.setText("Your Coins: " + storage.coins); } else { // Not enough coins var errorMsg = new Text2("Not enough coins!", { size: 80, fill: 0xFF0000, stroke: 0x000000, strokeThickness: 4 }); errorMsg.anchor.set(0.5, 0.5); errorMsg.y = 400; newPage.addChild(errorMsg); // Make message disappear after a while LK.setTimeout(function () { newPage.removeChild(errorMsg); }, 2000); } }; // Close button var closeButton = new Container(); var closeButtonBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.3, tint: 0x990000 }); closeButton.addChild(closeButtonBg); var closeButtonText = new Text2("CLOSE", { size: 80, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); closeButtonText.anchor.set(0.5, 0.5); closeButton.addChild(closeButtonText); closeButton.x = 0; closeButton.y = 1000; newPage.addChild(closeButton); // Add interactive property closeButton.interactive = true; closeButton.down = function () { game.removeChild(newPage); storePage.visible = true; }; // Back button var backButton = new Container(); var backButtonBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.3, tint: 0x006666 }); backButton.addChild(backButtonBg); var backButtonText = new Text2("BACK", { size: 80, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); backButtonText.anchor.set(0.5, 0.5); backButton.addChild(backButtonText); backButton.x = -250; backButton.y = 1000; newPage.addChild(backButton); // Add interactive property backButton.interactive = true; backButton.down = function () { game.removeChild(newPage); storePage.visible = true; }; }; // Close button var closeButton = new Container(); var closeButtonBg = LK.getAsset('glass', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.3, tint: 0x990000 }); closeButton.addChild(closeButtonBg); var closeButtonText = new Text2("CLOSE", { size: 80, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); closeButtonText.anchor.set(0.5, 0.5); closeButton.addChild(closeButtonText); closeButton.x = -250; closeButton.y = 1000; storePage.addChild(closeButton); // Add interactive property closeButton.interactive = true; closeButton.down = function () { game.removeChild(storePage); }; }; } else { // Remove all store UI elements if game is resumed for (var i = game.children.length - 1; i >= 0; i--) { var child = game.children[i]; if (child instanceof Container && child.children.length > 0 && child.children[0].tint === 0x333333) { game.removeChild(child); } } } }; var scoreTxt = new Text2("Score: 0", { size: 85, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); scoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(scoreTxt); var coinsTxt = new Text2("Coins: " + storage.coins, { size: 85, fill: 0xFFD700, stroke: 0x000000, strokeThickness: 4 }); coinsTxt.anchor.set(0, 0); coinsTxt.y = 60; LK.gui.topRight.addChild(coinsTxt); var levelTxt = new Text2("Level: 1", { size: 90, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 5 }); levelTxt.anchor.set(0.5, 0); LK.gui.top.addChild(levelTxt); var healthDisplay = new Container(); LK.gui.topLeft.addChild(healthDisplay); healthDisplay.x = 120; // Add some margin from the left edge healthDisplay.y = 50; // Show stats and upgrades var ballLevelTxt = new Text2("Ball Power: " + storage.ballLevel, { size: 75, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); ballLevelTxt.anchor.set(0, 0); ballLevelTxt.y = 150; LK.gui.topRight.addChild(ballLevelTxt); var speedLevelTxt = new Text2("Speed: " + storage.speedLevel, { size: 75, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 4 }); speedLevelTxt.anchor.set(0, 0); speedLevelTxt.y = 200; LK.gui.topRight.addChild(speedLevelTxt); function updateHealthDisplay() { // Clear existing health icons while (healthDisplay.children.length > 0) { healthDisplay.removeChild(healthDisplay.children[0]); } // Add health icons for (var i = 0; i < ball.health; i++) { var healthIcon = LK.getAsset('health', { anchorX: 0.5, anchorY: 0.5, x: i * 40, y: 0, scaleX: 1, scaleY: 1 }); healthDisplay.addChild(healthIcon); } } function updateScoreDisplay() { scoreTxt.setText("Score: " + LK.getScore()); } function updateCoinsDisplay() { coinsTxt.setText("Coins: " + storage.coins); } function updateLevelDisplay() { levelTxt.setText("Level: " + level); } function createGlassObstacle() { var glass = new Glass(); // Determine glass type based on level var typeRand = Math.random(); var type = 'normal'; if (level >= 3 && typeRand > 0.7) { type = 'moving'; } else if (level >= 5 && typeRand > 0.8) { type = 'trap'; } // Create additional obstacles for longer levels if (Math.random() > 0.6) { var secondGlass = new Glass(); var secondType = 'normal'; if (level >= 2 && typeRand > 0.6) { secondType = 'moving'; } else if (level >= 4 && typeRand > 0.85) { secondType = 'trap'; } secondGlass.setup(secondType, Math.min(Math.floor(level / 2) + 1, 5)); secondGlass.x = 2500 + Math.random() * 300 + 200; secondGlass.y = Math.random() * (groundY - 700) + 500; game.addChild(secondGlass); obstacles.push(secondGlass); } // Difficulty increases with level var difficulty = Math.min(Math.floor(level / 2) + 1, 5); glass.setup(type, difficulty); // Position glass ahead of player glass.x = 2500; // Random vertical position for some obstacles if (type === 'normal') { glass.y = groundY - glass.height / 2; } else { glass.y = Math.random() * (groundY - 700) + 500; } game.addChild(glass); obstacles.push(glass); // Sometimes add coins near obstacles if (Math.random() > 0.5) { createCoin(glass.x + Math.random() * 300 - 150, glass.y - 200 - Math.random() * 200); } // Sometimes add powerups if (Math.random() > 0.9) { if (Math.random() > 0.7) { createPowerup("health", glass.x + Math.random() * 300 - 150, glass.y - 300); } else { createPowerup("speed", glass.x + Math.random() * 300 - 150, glass.y - 300); } } // Sometimes add ground obstacles if (level >= 2 && Math.random() > 0.7) { var groundObstacle = LK.getAsset('obstacleGround', { anchorX: 0.5, anchorY: 0.5, x: glass.x - 300 - Math.random() * 300, y: groundY - 50 }); game.addChild(groundObstacle); // Add to obstacles array var obstacleObj = { object: groundObstacle, x: groundObstacle.x, update: function update() { this.x -= ball.speed; this.object.x = this.x; if (this.object.x < -200) { game.removeChild(this.object); var index = obstacles.indexOf(this); if (index !== -1) { obstacles.splice(index, 1); } } } }; obstacles.push(obstacleObj); } } function createCoin(x, y) { var coin = new Coin(); coin.x = x; coin.y = y; game.addChild(coin); collectibles.push(coin); } function createPowerup(type, x, y) { var powerup = new Powerup(); powerup.setup(type); powerup.x = x; powerup.y = y; game.addChild(powerup); collectibles.push(powerup); } function checkCollisions() { // Check collision with obstacles for (var i = 0; i < obstacles.length; i++) { var obstacle = obstacles[i]; // Handle different obstacle types if (obstacle instanceof Glass) { // Distance-based check for glass var dx = ball.x - obstacle.x; var dy = ball.y - obstacle.y; var distance = Math.sqrt(dx * dx + dy * dy); // Consider the obstacle width if (distance < ball.radius + obstacle.width / 2 && !obstacle.broken) { // Handle collision if (ball.power >= obstacle.health) { obstacle.takeDamage(ball.power); } else { // Ball not powerful enough - take damage ball.takeDamage(); // Player loses health when can't break glass obstacle.takeDamage(ball.power); } } // Check if ball passed through unbroken glass if (ball.x > obstacle.x && !obstacle.lastPassed && !obstacle.broken) { obstacle.lastPassed = true; ball.takeDamage(); // Lose health when passing through unbroken glass } } else if (obstacle.object && obstacle.object.name === 'obstacleGround') { // Simple box collision for ground obstacles var obstacleObj = obstacle.object; var ballRight = ball.x + ball.radius; var ballLeft = ball.x - ball.radius; var ballBottom = ball.y + ball.radius; var obstacleLeft = obstacleObj.x - obstacleObj.width / 2; var obstacleRight = obstacleObj.x + obstacleObj.width / 2; var obstacleTop = obstacleObj.y - obstacleObj.height / 2; if (ballRight > obstacleLeft && ballLeft < obstacleRight && ballBottom > obstacleTop) { // Collision with ground obstacle (jump over it!) ball.takeDamage(); LK.effects.flashObject(obstacleObj, 0xFF0000, 300); } } } // Check collision with collectibles for (var j = collectibles.length - 1; j >= 0; j--) { var collectible = collectibles[j]; var cdx = ball.x - collectible.x; var cdy = ball.y - collectible.y; var cDistance = Math.sqrt(cdx * cdx + cdy * cdy); if (cDistance < ball.radius + 25) { // Collect item if (collectible instanceof Coin) { collectible.collect(); collectibles.splice(j, 1); } else if (collectible instanceof Powerup) { collectible.collect(); // Removing from collectibles is handled in the collect method } } } } function updateLevel() { if (distance >= level * levelDistance) { level++; updateLevelDisplay(); LK.effects.flashScreen(0xFFFFFF, 500); // Award coins for completing level storage.coins += 500; updateCoinsDisplay(); // Show level up message var levelUpText = new Text2("Level " + level + " Complete! +500 coins", { size: 130, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 10 }); levelUpText.anchor.set(0.5, 0.5); levelUpText.x = 2048 / 2; levelUpText.y = 2732 / 2; game.addChild(levelUpText); // Animate and remove tween(levelUpText, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 1000, onFinish: function onFinish() { game.removeChild(levelUpText); } }); } } // Initialize game state updateHealthDisplay(); updateScoreDisplay(); updateCoinsDisplay(); updateLevelDisplay(); // Play background music LK.playMusic('gameMusic'); // Handle game controls game.down = function (x, y, obj) { // Get current time for double-click detection var currentTime = Date.now(); var timeDiff = currentTime - lastClickTime; // Check if this is a double-click if (timeDiff < doubleClickSpeed) { // This is a double-click - jump higher ball.jump(true); // Reset click timer to prevent triple-click detection lastClickTime = 0; } else { // This is a single click - normal jump ball.jump(false); // Store time of this click lastClickTime = currentTime; } }; game.move = function (x, y, obj) { // Not used for main game controls }; game.up = function (x, y, obj) { // Not used for main game controls }; // Main game update loop game.update = function () { if (isPaused || upgradeMenuOpen) return; // Update player ball.update(); // Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obstacle = obstacles[i]; obstacle.update(); } // Update collectibles for (var j = collectibles.length - 1; j >= 0; j--) { var collectible = collectibles[j]; collectible.update(); } // Check for collisions checkCollisions(); // Update distance traveled distance += ball.speed; // Check for level advancement updateLevel(); // Generate obstacles if (distance > nextObstacleDistance) { createGlassObstacle(); // Increased obstacle spacing to match longer levels nextObstacleDistance = distance + 700 + Math.random() * 800; } // Update high score if (LK.getScore() > storage.highScore) { storage.highScore = LK.getScore(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
coins: 0,
highScore: 0,
ballLevel: 1,
speedLevel: 1
});
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1,
scaleY: 1
});
self.velocityY = 0;
self.gravity = 0.5;
self.jumpForce = -15;
self.grounded = false;
self.canJump = true;
self.health = 3;
self.speed = 5 + (storage.speedLevel - 1) * 2;
self.radius = 50;
self.power = storage.ballLevel;
// Set color based on ball level/power
if (self.power === 2) {
ballGraphics.tint = 0xFF6600; // Orange for fireball
} else if (self.power === 3) {
ballGraphics.tint = 0xFFD700; // Gold color for golden ball
} else if (self.power === 4) {
ballGraphics.tint = 0x666666; // Dark gray for steel
} else if (self.power === 5) {
ballGraphics.tint = 0x88CCFF; // Light blue for ice ball
} else if (self.power === 6) {
ballGraphics.tint = 0x00FF00; // Green color for poison ball
} else if (self.power === 7) {
ballGraphics.tint = 0x333333; // Dark color for dark ball
}
self.jump = function (isDoubleJump) {
if (self.grounded && self.canJump) {
// Higher jump force for double-click
if (isDoubleJump) {
self.velocityY = self.jumpForce * 1.5; // 50% higher jump
LK.effects.flashObject(self, 0x00FF00, 300); // Visual feedback - green flash
} else {
self.velocityY = self.jumpForce;
}
self.grounded = false;
LK.getSound('jump').play();
// Jump cooldown
self.canJump = false;
LK.setTimeout(function () {
self.canJump = true;
}, 300);
}
};
self.takeDamage = function () {
self.health--;
LK.getSound('damage').play();
LK.effects.flashObject(self, 0xFF0000, 500);
// Visual feedback for health loss
var healthLossText = new Text2("-1 Health!", {
size: 90,
fill: 0xFF0000,
stroke: 0x000000,
strokeThickness: 5
});
healthLossText.anchor.set(0.5, 0.5);
healthLossText.x = self.x;
healthLossText.y = self.y - 100;
game.addChild(healthLossText);
// Animate and remove
tween(healthLossText, {
y: healthLossText.y - 150,
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
game.removeChild(healthLossText);
}
});
// Update the health display
updateHealthDisplay();
if (self.health <= 0) {
LK.showGameOver();
}
};
self.update = function () {
// Apply gravity
self.velocityY += self.gravity;
self.y += self.velocityY;
// Visual rotation to simulate rolling
ballGraphics.rotation += 0.05 * self.speed;
// Ground collision
if (self.y + self.radius > groundY) {
self.y = groundY - self.radius;
self.velocityY = 0;
self.grounded = true;
}
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.collect = function () {
if (!self.collected) {
self.collected = true;
LK.getSound('coinCollect').play();
// Animation
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
// Update coins
storage.coins += 1;
updateCoinsDisplay();
}
};
self.update = function () {
// Coin rotation animation
coinGraphics.rotation += 0.05;
// Move coin toward player
self.x -= ball.speed;
// Floating animation
self.y += Math.sin(LK.ticks / 10) * 0.5;
// Remove if passed player
if (self.x < -100) {
if (collectibles.indexOf(self) !== -1) {
collectibles.splice(collectibles.indexOf(self), 1);
}
self.destroy();
}
};
return self;
});
var Glass = Container.expand(function () {
var self = Container.call(this);
var glassGraphics = self.attachAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.width = glassGraphics.width;
self.height = glassGraphics.height;
self.broken = false;
self.health = 1;
self.type = 'normal'; // normal, moving, trap
self.movingDirection = 1;
self.movingSpeed = 0;
self.lastPassed = false; // Track if ball has passed through this glass
self.setup = function (type, difficulty) {
self.type = type || 'normal';
self.health = difficulty || 1;
if (self.type === 'moving') {
self.movingSpeed = Math.random() * 3 + 2;
glassGraphics.tint = 0x33CCFF;
} else if (self.type === 'trap') {
glassGraphics.tint = 0xFF3333;
}
};
self["break"] = function () {
if (!self.broken) {
self.broken = true;
LK.getSound('glassBreak').play();
// Create glass breaking particles
self.createParticles();
// Remove from active obstacles after animation
LK.setTimeout(function () {
if (obstacles.includes(self)) {
var index = obstacles.indexOf(self);
if (index !== -1) {
obstacles.splice(index, 1);
}
}
self.destroy();
}, 100);
}
};
self.createParticles = function () {
for (var i = 0; i < 8; i++) {
var particle = LK.getAsset('particleGlass', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x + (Math.random() * 100 - 50),
y: self.y + (Math.random() * 100 - 50),
alpha: 0.8
});
game.addChild(particle);
// Animate particle flying out
var targetX = particle.x + (Math.random() * 200 - 100);
var targetY = particle.y + (Math.random() * 200 - 100);
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
rotation: Math.random() * Math.PI * 2
}, {
duration: 500,
onFinish: function onFinish() {
particle.destroy();
}
});
}
};
self.takeDamage = function (power) {
self.health -= power;
LK.effects.flashObject(self, 0xFFFFFF, 100);
if (self.health <= 0) {
self["break"]();
// If trap glass, damage player
if (self.type === 'trap') {
ball.takeDamage();
}
// Add score based on glass type
var scoreValue = 10;
if (self.type === 'moving') scoreValue = 20;
if (self.type === 'trap') scoreValue = 30;
LK.setScore(LK.getScore() + scoreValue);
updateScoreDisplay();
} else {
// Just show crack effect
glassGraphics.alpha -= 0.2;
}
};
self.update = function () {
if (self.type === 'moving' && !self.broken) {
self.y += self.movingDirection * self.movingSpeed;
// Reverse direction when reaching boundaries
if (self.y < 500 || self.y > groundY - 400) {
self.movingDirection *= -1;
}
}
// Move obstacle toward player (creating the effect of moving forward)
self.x -= ball.speed;
// Remove if passed player
if (self.x < -300) {
if (obstacles.includes(self)) {
var index = obstacles.indexOf(self);
if (index !== -1) {
obstacles.splice(index, 1);
}
}
self.destroy();
}
};
return self;
});
var Powerup = Container.expand(function () {
var self = Container.call(this);
var type = "speed"; // Default
var graphics;
self.setup = function (powerupType) {
type = powerupType || "speed";
if (type === "speed") {
graphics = self.attachAsset('speedBoost', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (type === "health") {
graphics = self.attachAsset('health', {
anchorX: 0.5,
anchorY: 0.5
});
}
};
self.collect = function () {
LK.getSound('coinCollect').play();
if (type === "speed") {
// Temporary speed boost
var originalSpeed = ball.speed;
ball.speed += 5;
LK.setTimeout(function () {
ball.speed = originalSpeed;
}, 5000);
} else if (type === "health") {
// Health up to maximum 5
if (ball.health < 5) {
ball.health++;
updateHealthDisplay();
}
}
// Animation
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
if (collectibles.indexOf(self) !== -1) {
collectibles.splice(collectibles.indexOf(self), 1);
}
};
self.update = function () {
// Rotate the powerup
if (graphics) {
graphics.rotation += 0.05;
}
// Move powerup toward player
self.x -= ball.speed;
// Floating animation
self.y += Math.sin(LK.ticks / 8) * 0.7;
// Remove if passed player
if (self.x < -100) {
if (collectibles.indexOf(self) !== -1) {
collectibles.splice(collectibles.indexOf(self), 1);
}
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue background
});
/****
* Game Code
****/
// Game variables
var obstacles = [];
var collectibles = [];
var groundY = 2732 - 250; // Ground position
var distance = 0;
var nextObstacleDistance = 500;
var level = 1;
var levelDistance = 2500; // Distance required to advance a level - increased for longer levels
var isPaused = false;
var upgradeMenuOpen = false;
var lastClickTime = 0;
var doubleClickSpeed = 300; // Time in ms between clicks to count as double-click
var fireballUsesCount = 0; // Track the number of times the fireball button is used
var maxFireballUses = 3; // Maximum number of times the fireball button can be used
// Initialize ground
var ground = LK.getAsset('ground', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1,
scaleY: 1
});
ground.x = 2048 / 2;
ground.y = groundY;
game.addChild(ground);
// Create player ball with steel (metal) appearance
var ball = new Ball();
ball.x = 400;
ball.y = groundY - ball.radius;
// Set initial ball to be steel/metal type
ball.power = 4; // Level 4 is steel/metal ball
ball.children[0].tint = 0x666666; // Dark gray for steel
game.addChild(ball);
// Create UI elements
// Main menu button
var menuButton = new Container();
var menuButtonBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.25,
tint: 0x555555
});
menuButton.addChild(menuButtonBg);
var menuButtonText = new Text2("MENU", {
size: 70,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3
});
menuButtonText.anchor.set(0.5, 0.5);
menuButtonText.y = 10; // Position the text a bit lower in the button
menuButton.addChild(menuButtonText);
menuButton.x = 120;
menuButton.y = 200; // Moved further down
LK.gui.topLeft.addChild(menuButton);
// Fireball button removed
// Handle menu button interactions
menuButton.interactive = true;
menuButton.down = function (x, y, obj) {
LK.effects.flashObject(menuButton, 0xFFFFFF, 200);
// Toggle pause when menu button is clicked
isPaused = !isPaused;
if (isPaused) {
// Create store button
var storeButton = new Container();
var storeButtonBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.3,
tint: 0x333333
});
storeButton.addChild(storeButtonBg);
var storeButtonText = new Text2("STORE", {
size: 80,
fill: 0xFFD700,
stroke: 0x000000,
strokeThickness: 4
});
storeButtonText.anchor.set(0.5, 0.5);
storeButtonText.y = 10;
storeButton.addChild(storeButtonText);
storeButton.x = 2048 / 2;
storeButton.y = 2732 / 2;
game.addChild(storeButton);
// Store button interaction
storeButton.interactive = true;
storeButton.down = function (x, y, obj) {
LK.effects.flashObject(storeButton, 0xFFFFFF, 200);
// Game should stay paused when store button is clicked
isPaused = true;
// Remove store button when clicked
game.removeChild(storeButton);
// Create full-screen store page
var storePage = new Container();
// Background covering the entire screen
var storePageBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 20,
scaleY: 40,
tint: 0x222222,
alpha: 0.95
});
storePage.addChild(storePageBg);
storePage.x = 2048 / 2;
storePage.y = 2732 / 2;
game.addChild(storePage);
// Store page title
var storeTitle = new Text2("STORE", {
size: 150,
fill: 0xFFD700,
stroke: 0x000000,
strokeThickness: 6
});
storeTitle.anchor.set(0.5, 0.5);
storeTitle.y = -1000;
storePage.addChild(storeTitle);
// Display available coins
var coinsDisplay = new Text2("Your Coins: " + storage.coins, {
size: 100,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
coinsDisplay.anchor.set(0.5, 0.5);
coinsDisplay.y = -800;
storePage.addChild(coinsDisplay);
// Fireball upgrade button
var fireballButton = new Container();
var fireballBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.4,
tint: 0xFF6600
});
fireballButton.addChild(fireballBg);
var fireballText = new Text2("FIREBALL BALL - 1000 COINS", {
size: 90,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
fireballText.anchor.set(0.5, 0.5);
fireballButton.addChild(fireballText);
fireballButton.y = -400;
storePage.addChild(fireballButton);
// Add interactive property
fireballButton.interactive = true;
fireballButton.down = function () {
if (storage.coins >= 1000 && storage.ballLevel < 2) {
// Purchase successful
storage.coins -= 1000;
storage.ballLevel = 2;
updateCoinsDisplay();
// Update ball appearance immediately
if (ball) {
ball.power = 2;
ball.children[0].tint = 0xFF6600; // Orange for fireball
// Make fireball button visible since player now has fireball
fireballButton.visible = true;
}
// Update ball level text
ballLevelTxt.setText("Ball Power: " + storage.ballLevel);
// Success message
var successMsg = new Text2("PURCHASED! Fireball Activated!", {
size: 80,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 4
});
successMsg.anchor.set(0.5, 0.5);
successMsg.y = 400;
storePage.addChild(successMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(successMsg);
}, 2000);
} else if (storage.ballLevel >= 2) {
// If fireball is already purchased, activate it
if (ball.power !== 2) {
// Change ball to fireball appearance
ball.power = 2;
ball.children[0].tint = 0xFF6600; // Orange for fireball
// Success message
var activateMsg = new Text2("Fireball Activated!", {
size: 80,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 4
});
activateMsg.anchor.set(0.5, 0.5);
activateMsg.y = 400;
storePage.addChild(activateMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(activateMsg);
}, 2000);
} else {
// Already activated
var alreadyMsg = new Text2("Fireball Already Active!", {
size: 80,
fill: 0xFFFF00,
stroke: 0x000000,
strokeThickness: 4
});
alreadyMsg.anchor.set(0.5, 0.5);
alreadyMsg.y = 400;
storePage.addChild(alreadyMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(alreadyMsg);
}, 2000);
}
} else {
// Not enough coins
var errorMsg = new Text2("Not enough coins!", {
size: 80,
fill: 0xFF0000,
stroke: 0x000000,
strokeThickness: 4
});
errorMsg.anchor.set(0.5, 0.5);
errorMsg.y = 400;
storePage.addChild(errorMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(errorMsg);
}, 2000);
}
// Update coins display
coinsDisplay.setText("Your Coins: " + storage.coins);
};
// Golden Ball upgrade button
var goldenBallButton = new Container();
var goldenBallBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.4,
tint: 0xFFD700 // Gold color
});
goldenBallButton.addChild(goldenBallBg);
var goldenBallText = new Text2("GOLDEN BALL - 2000 COINS", {
size: 90,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
goldenBallText.anchor.set(0.5, 0.5);
goldenBallButton.addChild(goldenBallText);
goldenBallButton.y = -200; // Position below the fireball button
storePage.addChild(goldenBallButton);
// Add interactive property
goldenBallButton.interactive = true;
goldenBallButton.down = function () {
if (storage.coins >= 2000 && storage.ballLevel < 3) {
// Purchase successful
storage.coins -= 2000;
storage.ballLevel = 3;
updateCoinsDisplay();
// Update ball appearance immediately
if (ball) {
ball.power = 3;
ball.children[0].tint = 0xFFD700; // Gold color for golden ball
}
// Update ball level text
ballLevelTxt.setText("Ball Power: " + storage.ballLevel);
// Success message
var successMsg = new Text2("PURCHASED! Golden Ball Activated!", {
size: 80,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 4
});
successMsg.anchor.set(0.5, 0.5);
successMsg.y = 400;
storePage.addChild(successMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(successMsg);
}, 2000);
} else if (storage.ballLevel >= 3) {
// If golden ball is already purchased, activate it
if (ball.power !== 3) {
// Change ball to golden ball appearance
ball.power = 3;
ball.children[0].tint = 0xFFD700; // Gold color for golden ball
// Success message
var activateMsg = new Text2("Golden Ball Activated!", {
size: 80,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 4
});
activateMsg.anchor.set(0.5, 0.5);
activateMsg.y = 400;
storePage.addChild(activateMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(activateMsg);
}, 2000);
} else {
// Already activated
var alreadyMsg = new Text2("Golden Ball Already Active!", {
size: 80,
fill: 0xFFFF00,
stroke: 0x000000,
strokeThickness: 4
});
alreadyMsg.anchor.set(0.5, 0.5);
alreadyMsg.y = 400;
storePage.addChild(alreadyMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(alreadyMsg);
}, 2000);
}
} else {
// Not enough coins
var errorMsg = new Text2("Not enough coins!", {
size: 80,
fill: 0xFF0000,
stroke: 0x000000,
strokeThickness: 4
});
errorMsg.anchor.set(0.5, 0.5);
errorMsg.y = 400;
storePage.addChild(errorMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(errorMsg);
}, 2000);
}
// Update coins display
coinsDisplay.setText("Your Coins: " + storage.coins);
};
// Ice Ball upgrade button
var iceBallButton = new Container();
var iceBallBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.4,
tint: 0x88CCFF // Light blue color for ice
});
iceBallButton.addChild(iceBallBg);
var iceBallText = new Text2("ICE BALL - 3000 COINS", {
size: 90,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
iceBallText.anchor.set(0.5, 0.5);
iceBallButton.addChild(iceBallText);
iceBallButton.y = 0; // Position below the golden ball button
storePage.addChild(iceBallButton);
// Poison Ball upgrade button
var poisonBallButton = new Container();
var poisonBallBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.4,
tint: 0x00FF00 // Green color for poison
});
poisonBallButton.addChild(poisonBallBg);
var poisonBallText = new Text2("POISON BALL - 4000 COINS", {
size: 90,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
poisonBallText.anchor.set(0.5, 0.5);
poisonBallButton.addChild(poisonBallText);
poisonBallButton.y = 200; // Position below the ice ball button
storePage.addChild(poisonBallButton);
// Dark Ball upgrade button
var darkBallButton = new Container();
var darkBallBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.4,
tint: 0x333333 // Dark color for dark ball
});
darkBallButton.addChild(darkBallBg);
var darkBallText = new Text2("DARK BALL - 5000 COINS", {
size: 90,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
darkBallText.anchor.set(0.5, 0.5);
darkBallButton.addChild(darkBallText);
darkBallButton.y = 400; // Position below the poison ball button
storePage.addChild(darkBallButton);
// Add interactive property
iceBallButton.interactive = true;
iceBallButton.down = function () {
if (storage.coins >= 3000 && storage.ballLevel < 5) {
// Purchase successful
storage.coins -= 3000;
storage.ballLevel = 5;
updateCoinsDisplay();
// Update ball appearance immediately
if (ball) {
ball.power = 5;
ball.children[0].tint = 0x88CCFF; // Light blue color for ice ball
}
// Update ball level text
ballLevelTxt.setText("Ball Power: " + storage.ballLevel);
// Success message
var successMsg = new Text2("PURCHASED! Ice Ball Activated!", {
size: 80,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 4
});
successMsg.anchor.set(0.5, 0.5);
successMsg.y = 400;
storePage.addChild(successMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(successMsg);
}, 2000);
} else if (storage.ballLevel >= 5) {
// If ice ball is already purchased, activate it
if (ball.power !== 5) {
// Change ball to ice ball appearance
ball.power = 5;
ball.children[0].tint = 0x88CCFF; // Light blue color for ice ball
// Success message
var activateMsg = new Text2("Ice Ball Activated!", {
size: 80,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 4
});
activateMsg.anchor.set(0.5, 0.5);
activateMsg.y = 400;
storePage.addChild(activateMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(activateMsg);
}, 2000);
} else {
// Already activated
var alreadyMsg = new Text2("Ice Ball Already Active!", {
size: 80,
fill: 0xFFFF00,
stroke: 0x000000,
strokeThickness: 4
});
alreadyMsg.anchor.set(0.5, 0.5);
alreadyMsg.y = 400;
storePage.addChild(alreadyMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(alreadyMsg);
}, 2000);
}
} else {
// Not enough coins
var errorMsg = new Text2("Not enough coins!", {
size: 80,
fill: 0xFF0000,
stroke: 0x000000,
strokeThickness: 4
});
errorMsg.anchor.set(0.5, 0.5);
errorMsg.y = 400;
storePage.addChild(errorMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(errorMsg);
}, 2000);
}
// Update coins display
coinsDisplay.setText("Your Coins: " + storage.coins);
};
// Add interactive property for Poison Ball
poisonBallButton.interactive = true;
poisonBallButton.down = function () {
if (storage.coins >= 4000 && storage.ballLevel < 6) {
// Purchase successful
storage.coins -= 4000;
storage.ballLevel = 6;
updateCoinsDisplay();
// Update ball appearance immediately
if (ball) {
ball.power = 6;
ball.children[0].tint = 0x00FF00; // Green color for poison ball
}
// Update ball level text
ballLevelTxt.setText("Ball Power: " + storage.ballLevel);
// Success message
var successMsg = new Text2("PURCHASED! Poison Ball Activated!", {
size: 80,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 4
});
successMsg.anchor.set(0.5, 0.5);
successMsg.y = 400;
storePage.addChild(successMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(successMsg);
}, 2000);
} else if (storage.ballLevel >= 6) {
// If poison ball is already purchased, activate it
if (ball.power !== 6) {
// Change ball to poison ball appearance
ball.power = 6;
ball.children[0].tint = 0x00FF00; // Green color for poison ball
// Success message
var activateMsg = new Text2("Poison Ball Activated!", {
size: 80,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 4
});
activateMsg.anchor.set(0.5, 0.5);
activateMsg.y = 400;
storePage.addChild(activateMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(activateMsg);
}, 2000);
} else {
// Already activated
var alreadyMsg = new Text2("Poison Ball Already Active!", {
size: 80,
fill: 0xFFFF00,
stroke: 0x000000,
strokeThickness: 4
});
alreadyMsg.anchor.set(0.5, 0.5);
alreadyMsg.y = 400;
storePage.addChild(alreadyMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(alreadyMsg);
}, 2000);
}
} else {
// Not enough coins
var errorMsg = new Text2("Not enough coins!", {
size: 80,
fill: 0xFF0000,
stroke: 0x000000,
strokeThickness: 4
});
errorMsg.anchor.set(0.5, 0.5);
errorMsg.y = 400;
storePage.addChild(errorMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(errorMsg);
}, 2000);
}
// Update coins display
coinsDisplay.setText("Your Coins: " + storage.coins);
};
// Add interactive property for Dark Ball
darkBallButton.interactive = true;
darkBallButton.down = function () {
if (storage.coins >= 5000 && storage.ballLevel < 7) {
// Purchase successful
storage.coins -= 5000;
storage.ballLevel = 7;
updateCoinsDisplay();
// Update ball appearance immediately
if (ball) {
ball.power = 7;
ball.children[0].tint = 0x333333; // Dark color for dark ball
}
// Update ball level text
ballLevelTxt.setText("Ball Power: " + storage.ballLevel);
// Success message
var successMsg = new Text2("PURCHASED! Dark Ball Activated!", {
size: 80,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 4
});
successMsg.anchor.set(0.5, 0.5);
successMsg.y = 400;
storePage.addChild(successMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(successMsg);
}, 2000);
} else if (storage.ballLevel >= 7) {
// If dark ball is already purchased, activate it
if (ball.power !== 7) {
// Change ball to dark ball appearance
ball.power = 7;
ball.children[0].tint = 0x333333; // Dark color for dark ball
// Success message
var activateMsg = new Text2("Dark Ball Activated!", {
size: 80,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 4
});
activateMsg.anchor.set(0.5, 0.5);
activateMsg.y = 400;
storePage.addChild(activateMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(activateMsg);
}, 2000);
} else {
// Already activated
var alreadyMsg = new Text2("Dark Ball Already Active!", {
size: 80,
fill: 0xFFFF00,
stroke: 0x000000,
strokeThickness: 4
});
alreadyMsg.anchor.set(0.5, 0.5);
alreadyMsg.y = 400;
storePage.addChild(alreadyMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(alreadyMsg);
}, 2000);
}
} else {
// Not enough coins
var errorMsg = new Text2("Not enough coins!", {
size: 80,
fill: 0xFF0000,
stroke: 0x000000,
strokeThickness: 4
});
errorMsg.anchor.set(0.5, 0.5);
errorMsg.y = 400;
storePage.addChild(errorMsg);
// Make message disappear after a while
LK.setTimeout(function () {
storePage.removeChild(errorMsg);
}, 2000);
}
// Update coins display
coinsDisplay.setText("Your Coins: " + storage.coins);
};
// Next button
var nextButton = new Container();
var nextButtonBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.3,
tint: 0x006600
});
nextButton.addChild(nextButtonBg);
var nextButtonText = new Text2("NEXT", {
size: 80,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
nextButtonText.anchor.set(0.5, 0.5);
nextButton.addChild(nextButtonText);
nextButton.x = 250;
nextButton.y = 1000;
storePage.addChild(nextButton);
// Add interactive property
nextButton.interactive = true;
nextButton.down = function () {
// Flash button when clicked
LK.effects.flashObject(nextButton, 0xFFFFFF, 200);
// Hide current store page
storePage.visible = false;
// Create new page
var newPage = new Container();
// Background covering the entire screen
var newPageBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 20,
scaleY: 40,
tint: 0x222266,
// Slightly different background color
alpha: 0.95
});
newPage.addChild(newPageBg);
newPage.x = 2048 / 2;
newPage.y = 2732 / 2;
game.addChild(newPage);
// New page title
var newPageTitle = new Text2("MORE UPGRADES", {
size: 150,
fill: 0xFFD700,
stroke: 0x000000,
strokeThickness: 6
});
newPageTitle.anchor.set(0.5, 0.5);
newPageTitle.y = -1000;
newPage.addChild(newPageTitle);
// Display available coins
var coinsDisplay = new Text2("Your Coins: " + storage.coins, {
size: 100,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
coinsDisplay.anchor.set(0.5, 0.5);
coinsDisplay.y = -800;
newPage.addChild(coinsDisplay);
// Add Fire Power Button
var firePowerButton = new Container();
var firePowerBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.4,
tint: 0xFF3300 // Fire red-orange color
});
firePowerButton.addChild(firePowerBg);
var firePowerText = new Text2("FIRE POWER - 2000 COINS", {
size: 90,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
firePowerText.anchor.set(0.5, 0.5);
firePowerButton.addChild(firePowerText);
firePowerButton.y = -600; // Position above speed upgrade button
newPage.addChild(firePowerButton);
// Add Coming Soon text for Super Powers section
var comingSoonText = new Text2("COMING SOON", {
size: 120,
fill: 0xFFFF00,
stroke: 0x000000,
strokeThickness: 6
});
comingSoonText.anchor.set(0.5, 0.5);
comingSoonText.y = -350; // Position below the Fire Power button
newPage.addChild(comingSoonText);
// Add interactive property
firePowerButton.interactive = true;
firePowerButton.down = function () {
// Create fireballButton on the main game screen
var fireballButtonOnGame = new Container();
var fireballButtonBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.3,
tint: 0xFF6600 // Orange for fireball
});
fireballButtonOnGame.addChild(fireballButtonBg);
var fireballButtonText = new Text2("Ateş Topu Butonu (3/3)", {
size: 90,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
fireballButtonText.anchor.set(0.5, 0.5);
fireballButtonOnGame.addChild(fireballButtonText);
fireballButtonOnGame.x = 400; // Position more to the left side
fireballButtonOnGame.y = 2732 / 2;
game.addChild(fireballButtonOnGame);
// Make fireball button interactive
fireballButtonOnGame.interactive = true;
fireballButtonOnGame.down = function () {
// Check if we still have uses left
if (fireballUsesCount < maxFireballUses) {
// Increment the usage counter
fireballUsesCount++;
// Update the button text to show remaining uses
fireballButtonText.setText("Ateş Topu Butonu (" + (maxFireballUses - fireballUsesCount) + "/3)");
// Burn all glass obstacles
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (obstacle instanceof Glass && !obstacle.broken) {
// Create fire effect on the glass
LK.effects.flashObject(obstacle, 0xFF6600, 500);
// Make glass burn with animated tint
tween(obstacle.children[0], {
tint: 0xFF3300
}, {
duration: 500,
onFinish: function onFinish() {
// Store obstacle reference in a safer way to avoid cross-origin issues
var glassObstacle = obstacle;
// Check if glass obstacle exists and isn't broken yet
if (glassObstacle && typeof glassObstacle.broken !== 'undefined' && !glassObstacle.broken) {
glassObstacle["break"]();
}
}
});
}
}
// If we've used all attempts, remove the button
if (fireballUsesCount >= maxFireballUses) {
// Show message before removing
fireballButtonText.setText("Ateş Topu Hakkı Bitti!");
// Wait a moment to show the message before removing
LK.setTimeout(function () {
// Remove button from game
game.removeChild(fireballButtonOnGame);
}, 1000);
}
}
};
// Display only fireball button text when button is clicked
var fireballText = new Text2("Ateş Topu Butonu", {
size: 100,
fill: 0xFFFF00,
stroke: 0x000000,
strokeThickness: 5
});
fireballText.anchor.set(0.5, 0.5);
fireballText.y = -200;
newPage.addChild(fireballText);
if (storage.coins >= 2000) {
// Purchase successful
storage.coins -= 2000;
updateCoinsDisplay();
// Add fire power effect
var successMsg = new Text2("PURCHASED! Fire Power Upgraded!", {
size: 80,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 4
});
successMsg.anchor.set(0.5, 0.5);
successMsg.y = 400;
newPage.addChild(successMsg);
// Make message disappear after a while
LK.setTimeout(function () {
newPage.removeChild(successMsg);
}, 2000);
// Update coins display
coinsDisplay.setText("Your Coins: " + storage.coins);
} else {
// Not enough coins
var errorMsg = new Text2("Not enough coins!", {
size: 80,
fill: 0xFF0000,
stroke: 0x000000,
strokeThickness: 4
});
errorMsg.anchor.set(0.5, 0.5);
errorMsg.y = 400;
newPage.addChild(errorMsg);
// Make message disappear after a while
LK.setTimeout(function () {
newPage.removeChild(errorMsg);
}, 2000);
}
};
// Add speed upgrade button
var speedUpgradeButton = new Container();
var speedUpgradeBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.4,
tint: 0x00AAFF
});
speedUpgradeButton.addChild(speedUpgradeBg);
var speedUpgradeText = new Text2("SPEED UPGRADE - 1000 COINS", {
size: 90,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
speedUpgradeText.anchor.set(0.5, 0.5);
speedUpgradeButton.addChild(speedUpgradeText);
speedUpgradeButton.y = -400;
newPage.addChild(speedUpgradeButton);
// Add interactive property
speedUpgradeButton.interactive = true;
speedUpgradeButton.down = function () {
if (storage.coins >= 1000) {
// Purchase successful
storage.coins -= 1000;
storage.speedLevel += 1;
updateCoinsDisplay();
// Update speed display
ball.speed = 5 + (storage.speedLevel - 1) * 2;
speedLevelTxt.setText("Speed: " + storage.speedLevel);
// Success message
var successMsg = new Text2("PURCHASED! Speed Upgraded!", {
size: 80,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 4
});
successMsg.anchor.set(0.5, 0.5);
successMsg.y = 400;
newPage.addChild(successMsg);
// Make message disappear after a while
LK.setTimeout(function () {
newPage.removeChild(successMsg);
}, 2000);
// Update coins display
coinsDisplay.setText("Your Coins: " + storage.coins);
} else {
// Not enough coins
var errorMsg = new Text2("Not enough coins!", {
size: 80,
fill: 0xFF0000,
stroke: 0x000000,
strokeThickness: 4
});
errorMsg.anchor.set(0.5, 0.5);
errorMsg.y = 400;
newPage.addChild(errorMsg);
// Make message disappear after a while
LK.setTimeout(function () {
newPage.removeChild(errorMsg);
}, 2000);
}
};
// Close button
var closeButton = new Container();
var closeButtonBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.3,
tint: 0x990000
});
closeButton.addChild(closeButtonBg);
var closeButtonText = new Text2("CLOSE", {
size: 80,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
closeButtonText.anchor.set(0.5, 0.5);
closeButton.addChild(closeButtonText);
closeButton.x = 0;
closeButton.y = 1000;
newPage.addChild(closeButton);
// Add interactive property
closeButton.interactive = true;
closeButton.down = function () {
game.removeChild(newPage);
storePage.visible = true;
};
// Back button
var backButton = new Container();
var backButtonBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.3,
tint: 0x006666
});
backButton.addChild(backButtonBg);
var backButtonText = new Text2("BACK", {
size: 80,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
backButtonText.anchor.set(0.5, 0.5);
backButton.addChild(backButtonText);
backButton.x = -250;
backButton.y = 1000;
newPage.addChild(backButton);
// Add interactive property
backButton.interactive = true;
backButton.down = function () {
game.removeChild(newPage);
storePage.visible = true;
};
};
// Close button
var closeButton = new Container();
var closeButtonBg = LK.getAsset('glass', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.3,
tint: 0x990000
});
closeButton.addChild(closeButtonBg);
var closeButtonText = new Text2("CLOSE", {
size: 80,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
closeButtonText.anchor.set(0.5, 0.5);
closeButton.addChild(closeButtonText);
closeButton.x = -250;
closeButton.y = 1000;
storePage.addChild(closeButton);
// Add interactive property
closeButton.interactive = true;
closeButton.down = function () {
game.removeChild(storePage);
};
};
} else {
// Remove all store UI elements if game is resumed
for (var i = game.children.length - 1; i >= 0; i--) {
var child = game.children[i];
if (child instanceof Container && child.children.length > 0 && child.children[0].tint === 0x333333) {
game.removeChild(child);
}
}
}
};
var scoreTxt = new Text2("Score: 0", {
size: 85,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
var coinsTxt = new Text2("Coins: " + storage.coins, {
size: 85,
fill: 0xFFD700,
stroke: 0x000000,
strokeThickness: 4
});
coinsTxt.anchor.set(0, 0);
coinsTxt.y = 60;
LK.gui.topRight.addChild(coinsTxt);
var levelTxt = new Text2("Level: 1", {
size: 90,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 5
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
var healthDisplay = new Container();
LK.gui.topLeft.addChild(healthDisplay);
healthDisplay.x = 120; // Add some margin from the left edge
healthDisplay.y = 50;
// Show stats and upgrades
var ballLevelTxt = new Text2("Ball Power: " + storage.ballLevel, {
size: 75,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
ballLevelTxt.anchor.set(0, 0);
ballLevelTxt.y = 150;
LK.gui.topRight.addChild(ballLevelTxt);
var speedLevelTxt = new Text2("Speed: " + storage.speedLevel, {
size: 75,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 4
});
speedLevelTxt.anchor.set(0, 0);
speedLevelTxt.y = 200;
LK.gui.topRight.addChild(speedLevelTxt);
function updateHealthDisplay() {
// Clear existing health icons
while (healthDisplay.children.length > 0) {
healthDisplay.removeChild(healthDisplay.children[0]);
}
// Add health icons
for (var i = 0; i < ball.health; i++) {
var healthIcon = LK.getAsset('health', {
anchorX: 0.5,
anchorY: 0.5,
x: i * 40,
y: 0,
scaleX: 1,
scaleY: 1
});
healthDisplay.addChild(healthIcon);
}
}
function updateScoreDisplay() {
scoreTxt.setText("Score: " + LK.getScore());
}
function updateCoinsDisplay() {
coinsTxt.setText("Coins: " + storage.coins);
}
function updateLevelDisplay() {
levelTxt.setText("Level: " + level);
}
function createGlassObstacle() {
var glass = new Glass();
// Determine glass type based on level
var typeRand = Math.random();
var type = 'normal';
if (level >= 3 && typeRand > 0.7) {
type = 'moving';
} else if (level >= 5 && typeRand > 0.8) {
type = 'trap';
}
// Create additional obstacles for longer levels
if (Math.random() > 0.6) {
var secondGlass = new Glass();
var secondType = 'normal';
if (level >= 2 && typeRand > 0.6) {
secondType = 'moving';
} else if (level >= 4 && typeRand > 0.85) {
secondType = 'trap';
}
secondGlass.setup(secondType, Math.min(Math.floor(level / 2) + 1, 5));
secondGlass.x = 2500 + Math.random() * 300 + 200;
secondGlass.y = Math.random() * (groundY - 700) + 500;
game.addChild(secondGlass);
obstacles.push(secondGlass);
}
// Difficulty increases with level
var difficulty = Math.min(Math.floor(level / 2) + 1, 5);
glass.setup(type, difficulty);
// Position glass ahead of player
glass.x = 2500;
// Random vertical position for some obstacles
if (type === 'normal') {
glass.y = groundY - glass.height / 2;
} else {
glass.y = Math.random() * (groundY - 700) + 500;
}
game.addChild(glass);
obstacles.push(glass);
// Sometimes add coins near obstacles
if (Math.random() > 0.5) {
createCoin(glass.x + Math.random() * 300 - 150, glass.y - 200 - Math.random() * 200);
}
// Sometimes add powerups
if (Math.random() > 0.9) {
if (Math.random() > 0.7) {
createPowerup("health", glass.x + Math.random() * 300 - 150, glass.y - 300);
} else {
createPowerup("speed", glass.x + Math.random() * 300 - 150, glass.y - 300);
}
}
// Sometimes add ground obstacles
if (level >= 2 && Math.random() > 0.7) {
var groundObstacle = LK.getAsset('obstacleGround', {
anchorX: 0.5,
anchorY: 0.5,
x: glass.x - 300 - Math.random() * 300,
y: groundY - 50
});
game.addChild(groundObstacle);
// Add to obstacles array
var obstacleObj = {
object: groundObstacle,
x: groundObstacle.x,
update: function update() {
this.x -= ball.speed;
this.object.x = this.x;
if (this.object.x < -200) {
game.removeChild(this.object);
var index = obstacles.indexOf(this);
if (index !== -1) {
obstacles.splice(index, 1);
}
}
}
};
obstacles.push(obstacleObj);
}
}
function createCoin(x, y) {
var coin = new Coin();
coin.x = x;
coin.y = y;
game.addChild(coin);
collectibles.push(coin);
}
function createPowerup(type, x, y) {
var powerup = new Powerup();
powerup.setup(type);
powerup.x = x;
powerup.y = y;
game.addChild(powerup);
collectibles.push(powerup);
}
function checkCollisions() {
// Check collision with obstacles
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
// Handle different obstacle types
if (obstacle instanceof Glass) {
// Distance-based check for glass
var dx = ball.x - obstacle.x;
var dy = ball.y - obstacle.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Consider the obstacle width
if (distance < ball.radius + obstacle.width / 2 && !obstacle.broken) {
// Handle collision
if (ball.power >= obstacle.health) {
obstacle.takeDamage(ball.power);
} else {
// Ball not powerful enough - take damage
ball.takeDamage(); // Player loses health when can't break glass
obstacle.takeDamage(ball.power);
}
}
// Check if ball passed through unbroken glass
if (ball.x > obstacle.x && !obstacle.lastPassed && !obstacle.broken) {
obstacle.lastPassed = true;
ball.takeDamage(); // Lose health when passing through unbroken glass
}
} else if (obstacle.object && obstacle.object.name === 'obstacleGround') {
// Simple box collision for ground obstacles
var obstacleObj = obstacle.object;
var ballRight = ball.x + ball.radius;
var ballLeft = ball.x - ball.radius;
var ballBottom = ball.y + ball.radius;
var obstacleLeft = obstacleObj.x - obstacleObj.width / 2;
var obstacleRight = obstacleObj.x + obstacleObj.width / 2;
var obstacleTop = obstacleObj.y - obstacleObj.height / 2;
if (ballRight > obstacleLeft && ballLeft < obstacleRight && ballBottom > obstacleTop) {
// Collision with ground obstacle (jump over it!)
ball.takeDamage();
LK.effects.flashObject(obstacleObj, 0xFF0000, 300);
}
}
}
// Check collision with collectibles
for (var j = collectibles.length - 1; j >= 0; j--) {
var collectible = collectibles[j];
var cdx = ball.x - collectible.x;
var cdy = ball.y - collectible.y;
var cDistance = Math.sqrt(cdx * cdx + cdy * cdy);
if (cDistance < ball.radius + 25) {
// Collect item
if (collectible instanceof Coin) {
collectible.collect();
collectibles.splice(j, 1);
} else if (collectible instanceof Powerup) {
collectible.collect();
// Removing from collectibles is handled in the collect method
}
}
}
}
function updateLevel() {
if (distance >= level * levelDistance) {
level++;
updateLevelDisplay();
LK.effects.flashScreen(0xFFFFFF, 500);
// Award coins for completing level
storage.coins += 500;
updateCoinsDisplay();
// Show level up message
var levelUpText = new Text2("Level " + level + " Complete! +500 coins", {
size: 130,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 10
});
levelUpText.anchor.set(0.5, 0.5);
levelUpText.x = 2048 / 2;
levelUpText.y = 2732 / 2;
game.addChild(levelUpText);
// Animate and remove
tween(levelUpText, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 1000,
onFinish: function onFinish() {
game.removeChild(levelUpText);
}
});
}
}
// Initialize game state
updateHealthDisplay();
updateScoreDisplay();
updateCoinsDisplay();
updateLevelDisplay();
// Play background music
LK.playMusic('gameMusic');
// Handle game controls
game.down = function (x, y, obj) {
// Get current time for double-click detection
var currentTime = Date.now();
var timeDiff = currentTime - lastClickTime;
// Check if this is a double-click
if (timeDiff < doubleClickSpeed) {
// This is a double-click - jump higher
ball.jump(true);
// Reset click timer to prevent triple-click detection
lastClickTime = 0;
} else {
// This is a single click - normal jump
ball.jump(false);
// Store time of this click
lastClickTime = currentTime;
}
};
game.move = function (x, y, obj) {
// Not used for main game controls
};
game.up = function (x, y, obj) {
// Not used for main game controls
};
// Main game update loop
game.update = function () {
if (isPaused || upgradeMenuOpen) return;
// Update player
ball.update();
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
obstacle.update();
}
// Update collectibles
for (var j = collectibles.length - 1; j >= 0; j--) {
var collectible = collectibles[j];
collectible.update();
}
// Check for collisions
checkCollisions();
// Update distance traveled
distance += ball.speed;
// Check for level advancement
updateLevel();
// Generate obstacles
if (distance > nextObstacleDistance) {
createGlassObstacle();
// Increased obstacle spacing to match longer levels
nextObstacleDistance = distance + 700 + Math.random() * 800;
}
// Update high score
if (LK.getScore() > storage.highScore) {
storage.highScore = LK.getScore();
}
};