/**** * Classes ****/ var BounceEffect = Container.expand(function (x, y, color) { var self = Container.call(this); self.x = x; self.y = y; var bounceGraphics = self.attachAsset('bounceEffect', { anchorX: 0.5, anchorY: 0.5 }); bounceGraphics.tint = color; var duration = 30; self._update_migrated = function () { duration--; bounceGraphics.scaleX += 0.1; bounceGraphics.scaleY += 0.1; bounceGraphics.alpha -= 0.033; bounceGraphics.scaleX -= 0.01; bounceGraphics.scaleY -= 0.01; if (duration <= 0) { self.destroy(); } }; game.addChild(self); }); var Challenge = Container.expand(function (color, amount, bounceLimit) { var self = Container.call(this); self.color = color; self.amount = amount; self.bounceLimit = bounceLimit; self.remainingBounces = bounceLimit; // Initialize remainingBounces correctly self.completed = false; var obstacleIcon = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5, tint: color, scaleX: 0.5, scaleY: 0.5 }); obstacleIcon.x = 250; obstacleIcon.y = 40; var challengeText = new Text2('0/' + amount, { size: 75, fill: "#ffffff", stroke: "#000000", strokeThickness: 8, anchorX: 0.5, anchorY: 0.5 }); challengeText.x = 300; challengeText.y -= 10; self.addChild(obstacleIcon); self.addChild(challengeText); self.updateProgress = function () { self.amount -= 1; challengeText.setText(amount - self.amount + '/' + amount); if (self.amount <= 0) { console.log("Objective complete for challenge with color:", self.color); self.completed = true; if (currentChallenge.every(function (challenge) { console.log("All objectives complete for current challenge set. Whole challenge complete."); return challenge.completed; })) { if (gameMode === 'challenges') { LK.setScore(LK.getScore() + 1); } hud.updateScore(LK.getScore()); showChallengeCompletePopup(self.color); currentChallenge.forEach(function (challenge) { hud.removeChild(challenge); console.log("Destroying challenge with color:", challenge.color); challenge.destroy(); }); currentChallenge = []; hud.updateChallenges(currentChallenge); self.destroy(); // Ensure the challenge container is deleted resetGameToStartingPoint(); startNextChallenge(); } else {} } }; }); var CircularObstacle = Container.expand(function (starX, starY, radius, angleSpeed, initialAngle) { var self = Container.call(this); var obstacleGraphics = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5, tint: getRandomTint() }); self.angle = initialAngle || 0; self.radius = radius; self.angleSpeed = angleSpeed * 0.75; self.starX = starX; self.starY = starY; self.updatePosition = function () { self.x = self.starX + Math.cos(self.angle) * self.radius; self.y = self.starY + Math.sin(self.angle) * self.radius; self.angle += self.angleSpeed * 0.35; obstacleGraphics.rotation += self.angleSpeed * 0.35; }; self.moveDown = function (distance, dotY) { self.starY += distance * getSpeedMultiplier(dotY); }; self.updatePosition(); }); var Cloud = Container.expand(function () { var self = Container.call(this); var cloudTypes = ['cloud1', 'cloud2', 'cloud3']; var cloudType = cloudTypes[Math.floor(Math.random() * cloudTypes.length)]; var cloudGraphics = self.attachAsset(cloudType, { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 // Make clouds even more transparent }); self.speed = Math.random() * 0.5 + 0.25; // Random speed between 0.25 and 0.75 self.alpha = 0; var fadeInDuration = 60; // Duration of the fade-in effect in frames var fadeInFrame = 0; var fadeInInterval = LK.setInterval(function () { fadeInFrame++; self.alpha += 1 / fadeInDuration; if (fadeInFrame >= fadeInDuration) { LK.clearInterval(fadeInInterval); } }, 1000 / 60); self.direction = Math.random() < 0.5 ? 1 : -1; // Random direction self._update_migrated = function () { self.x += self.speed * self.direction; if (self.x > 2048 + cloudGraphics.width / 2) { self.x = -cloudGraphics.width / 2; } else if (self.x < -cloudGraphics.width / 2) { self.x = 2048 + cloudGraphics.width / 2; } if (self.y > 2732 + cloudGraphics.height / 2) { self.y = -cloudGraphics.height / 2; } }; }); var Dot = Container.expand(function () { var self = Container.call(this); var dotGraphics = self.attachAsset('dot', { anchorX: 0.5, anchorY: 0.5 }); self.destroyed = false; self.alpha = 0; var fadeInDuration = 60; // Duration of the fade-in effect in frames var fadeInFrame = 0; var fadeInInterval = LK.setInterval(function () { fadeInFrame++; self.alpha += 1 / fadeInDuration; if (fadeInFrame >= fadeInDuration) { LK.clearInterval(fadeInInterval); } }, 1000 / 60); self.velocityY = 0; self.gravity = 0.7; self.bounce = -15; self._update_migrated = function () { if (!dotBouncing) { return; } var previousY = self.y; self.velocityY += self.gravity; if (self.velocityY > 0 && dotGraphics.scaleX < 1) { dotGraphics.scaleX += 0.02; dotGraphics.scaleY -= 0.02; } else if (self.velocityY < 0 && dotGraphics.scaleX > 0.9) { dotGraphics.scaleX -= 0.01; dotGraphics.scaleY += 0.01; } self.y += self.velocityY; if (!self.firstTouch && !self.intersects(hand)) { self.y = 2732 - self.height / 2 - 500; } else if (self.intersects(hand)) { self.bounceUp(); } else if (self.y > 2232 - self.height / 2 && self.firstTouch && !self.firstStarDestroyed) { self.velocityY = self.bounce; } else if (self.y > 2832 && !self.destroyed) { handleDotDestruction(); } self.movedDistance = self.y - previousY; }; self.bounceUp = function () { if (!self.destroyed) { self.velocityY = self.bounce; dot.scale.x *= 0.8; dot.scale.y = 1.02; LK.setTimeout(function () { dot.scale.x = 1; dot.scale.y = 1; }, 90); LK.getSound('bounce').play(); if (!self.intersects(hand)) { createBounceEffect(self.x, self.y, dotGraphics.tint); } self.firstTouch = true; if (!self.firstStarDestroyed) { self.firstStarDestroyed = true; } if (gameMode === 'challenges' && !self.intersects(hand)) { if (!currentChallenge[0].completed) { remainingBounces--; console.log("Remaining bounces decremented to:", remainingBounces); hud.remainingBouncesTxt.setText(remainingBounces.toString()); if (remainingBounces <= 0) { handleDotDestruction(); } } } } }; self.inheritStarColor = function (star) { dotGraphics.tint = star.children[0].tint; }; }); var DotParticleEffect = Container.expand(function (x, y) { var self = Container.call(this); self.x = x; self.y = y; var particles = []; var angleIncrement = Math.PI * 2 / 20; var speed = 30; var colors = [0xffe066, 0xcc66ff, 0xff6666, 0x99ccff].slice(0, CONFIG.numColors); for (var i = 0; i < 20; i++) { var particle = self.attachAsset('dotParticle', { anchorX: 0.5, anchorY: 0.5, tint: colors[Math.floor(Math.random() * colors.length)] }); particle.scaleX = particle.scaleY = 0.5; particle.alpha = 1; var angle = i * angleIncrement; particle.vx = Math.cos(angle) * speed; particle.vy = Math.sin(angle) * speed; particles.push(particle); } self._update_migrated = function () { for (var i = particles.length - 1; i >= 0; i--) { particles[i].x += particles[i].vx; particles[i].y += particles[i].vy; particles[i].rotation += 0.1; // Rotate the particle particles[i].alpha -= 0.0167; if (particles[i].alpha <= 0) { particles[i].destroy(); particles.splice(i, 1); } } if (particles.length === 0) { self.destroy(); } }; game.addChild(self); }); var HUD = Container.expand(function () { var self = Container.call(this); // Create background line for HUD var backgroundLine = self.attachAsset('backgroundLine', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5, alpha: 0.5 }); backgroundLine.x = 2048 / 2 + 200; backgroundLine.y = 75; // Create score text scoreTxt = new Text2('0', { size: 200, // Reduced size to fit within the HUD fill: "#ffffff", stroke: "#000000", strokeThickness: 8 }); scoreTxt.anchor.set(0.5, 0); scoreTxt.x = 2048 - 200 + 80; // Adjusted position to fit within the HUD scoreTxt.y = -10; // Adjusted position to fit within the HUD self.addChild(scoreTxt); // Create challenge level text self.challengeLevelTxt = new Text2('LVL 0', { size: 75, fill: "#ffffff", stroke: "#000000", strokeThickness: 8 }); self.challengeLevelTxt.anchor.set(0, 0); self.challengeLevelTxt.x = 320; self.challengeLevelTxt.y = 80; self.addChild(self.challengeLevelTxt); // Create remaining bounces text self.remainingBouncesIcon = self.attachAsset('dot', { anchorX: 1, anchorY: 0, scaleX: 0.5, scaleY: 0.5 }); self.remainingBouncesIcon.x = 2048 - 30 + 150; self.remainingBouncesIcon.y = 40; self.remainingBouncesIcon.visible = true; // Ensure the remaining bounces icon is always visible self.addChild(self.remainingBouncesIcon); self.remainingBouncesTxt = new Text2('0', { size: 75, fill: "#ffffff", stroke: "#000000", strokeThickness: 8 }); self.remainingBouncesTxt.anchor.set(1, 0); self.remainingBouncesTxt.x = 2048 + 70 + 150; self.remainingBouncesTxt.y = 30; self.remainingBouncesTxt.visible = true; // Ensure the remaining bounces text is always visible self.addChild(self.remainingBouncesTxt); // Removed challenges container self.updateScore = function (score) { scoreTxt.setText(score.toString()); }; self.updateChallenges = function (challenges) { var totalWidth = challenges.reduce(function (acc, challenge) { return acc + challenge.width + 20; // 20px gap }, -20); // Subtract the last gap var startX = (2048 - totalWidth) / 2; challenges.forEach(function (challenge, i) { challenge.x = startX + i * (challenge.width + 20); challenge.y = 40; // Ensure all challenges are aligned vertically self.addChild(challenge); }); // Keep the level text fixed in the initial spot self.challengeLevelTxt.x = 320; self.challengeLevelTxt.y = 30; self.challengeLevelTxt.visible = true; // Ensure the level text is always visible }; return self; }); // Add Hand asset below the dot var Hand = Container.expand(function () { var self = Container.call(this); var handGraphics = self.attachAsset('hand', { anchorX: 0.5, anchorY: 0, alpha: 0.7 }); self.alpha = 0; var fadeInDuration = 60; // Duration of the fade-in effect in frames var fadeInFrame = 0; var fadeInInterval = LK.setInterval(function () { fadeInFrame++; self.alpha += 1 / fadeInDuration; if (fadeInFrame >= fadeInDuration) { LK.clearInterval(fadeInInterval); } }, 1000 / 60); self._update_migrated = function (distance) { if (distance) { self.y += distance; } }; }); var HandDestroyEffect = Container.expand(function (x, y) { var self = Container.call(this); self.x = x; self.y = y; var handGraphics = self.attachAsset('hand', { anchorX: 0.5, anchorY: 0 }); self._update_migrated = function () { self.y += 10; // Move the hand downwards faster if (self.y > 2732 + handGraphics.height / 2) { // Check if the hand is off-screen self.destroy(); } }; game.addChild(self); }); var MainMenu = Container.expand(function () { var self = Container.call(this); // Removed background // Create Endless button using endless asset var endlessButton = self.attachAsset('Endless', { anchorX: 0.5, anchorY: 0.5 }); endlessButton.x = 0; endlessButton.y = 1200; endlessButton.floatDirection = 1; endlessButton.floatSpeed = 0.5; endlessButton.floatRange = 10; endlessButton.down = function () { LK.getSound('button').play(); LK.getSound('bounce').play(); // LK.stopMusic(); fadeOutElements([gameTitle, endlessButton, challengesButton, howToPlayButton].concat(mainMenuClouds), function () { startGame('endless'); }); }; endlessButton._update_migrated = function () { endlessButton.y += endlessButton.floatSpeed * endlessButton.floatDirection; if (endlessButton.y >= 1200 + endlessButton.floatRange || endlessButton.y <= 1200 - endlessButton.floatRange) { endlessButton.floatDirection *= -1; } }; LK.on('tick', function () { endlessButton._update_migrated(); }); // Create Challenges button using challenges asset var challengesButton = self.attachAsset('Challenges', { anchorX: 0.5, anchorY: 0.5 }); challengesButton.x = 0; challengesButton.y = 1450; challengesButton.floatDirection = 1; challengesButton.floatSpeed = 0.5; challengesButton.floatRange = 10; challengesButton.down = function () { LK.getSound('button').play(); LK.getSound('bounce').play(); // LK.stopMusic(); fadeOutElements([gameTitle, endlessButton, challengesButton, howToPlayButton].concat(mainMenuClouds), function () { startGame('challenges'); }); }; challengesButton._update_migrated = function () { challengesButton.y += challengesButton.floatSpeed * challengesButton.floatDirection; if (challengesButton.y >= 1450 + challengesButton.floatRange || challengesButton.y <= 1450 - challengesButton.floatRange) { challengesButton.floatDirection *= -1; } }; LK.on('tick', function () { challengesButton._update_migrated(); }); // Create game title using gametitle asset var gameTitle = self.attachAsset('gametitle', { anchorX: 0.5, anchorY: 0.5 }); gameTitle.x = 0; gameTitle.y = 600; // self.addChild(background); // Removed undefined background reference // Create How to Play button using a new asset var howToPlayButton = new Text2('how to play', { size: 50, fill: "#ffffff", stroke: "#000000", // Add border color strokeThickness: 8, // Add border thickness anchorX: 0.5, anchorY: 0.5, align: 'center' // Center justify the text }); howToPlayButton.x = -125; howToPlayButton.y = 1700; howToPlayButton.blinking = true; howToPlayButton.blinkSpeed = 0.005; howToPlayButton.blinkDirection = 1; howToPlayButton.down = function () { LK.getSound('button').play(); showHowToPlay(); }; howToPlayButton._update_migrated = function () { if (howToPlayButton.blinking) { howToPlayButton.alpha += howToPlayButton.blinkSpeed * howToPlayButton.blinkDirection; if (howToPlayButton.alpha >= 1) { howToPlayButton.alpha = 1; howToPlayButton.blinkDirection = -1; } else if (howToPlayButton.alpha <= 0.1) { howToPlayButton.alpha = 0.1; howToPlayButton.blinkDirection = 1; } } }; LK.on('tick', function () { howToPlayButton._update_migrated(); }); gameTitle.tiltDirection = 1; gameTitle.tiltSpeed = 0.001; gameTitle.maxTilt = 0.1; gameTitle._update_migrated = function () { gameTitle.rotation += gameTitle.tiltSpeed * gameTitle.tiltDirection; if (gameTitle.rotation >= gameTitle.maxTilt || gameTitle.rotation <= -gameTitle.maxTilt) { gameTitle.tiltDirection *= -1; } }; LK.on('tick', function () { gameTitle._update_migrated(); }); // Add clouds to the main menu background var mainMenuClouds = []; for (var i = 0; i < 10; i++) { var cloud = new MainMenuCloud(); cloud.x = Math.random() * 2048 - 2600; var newY; do { newY = Math.random() * 2732; } while (!isCloudPositionValid(newY, mainMenuClouds, 200)); // Ensure clouds are at least 200 pixels apart cloud.y = newY; mainMenuClouds.push(cloud); self.addChild(cloud); } self.addChild(gameTitle); self.addChild(endlessButton); self.addChild(challengesButton); self.addChild(howToPlayButton); // Update clouds on the main menu background LK.on('tick', function () { for (var i = 0; i < mainMenuClouds.length; i++) { mainMenuClouds[i]._update_migrated(); } }); // Play game music after 2 seconds LK.setTimeout(function () { LK.playMusic('gamemusic'); }, 2000); }); var MainMenuCloud = Container.expand(function () { var self = Container.call(this); var cloudTypes = ['cloud1', 'cloud2', 'cloud3']; var cloudType = cloudTypes[Math.floor(Math.random() * cloudTypes.length)]; var cloudGraphics = self.attachAsset(cloudType, { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 // Make clouds even more transparent }); self.speed = Math.random() * 0.5 + 0.25; // Random speed between 0.25 and 0.75 self.direction = Math.random() < 0.5 ? 1 : -1; // Random direction self._update_migrated = function () { self.x += self.speed * self.direction; if (self.x > 2048 + cloudGraphics.width / 2) { self.x = -cloudGraphics.width / 2; } else if (self.x < -cloudGraphics.width / 2) { self.x = 2048 + cloudGraphics.width / 2; } if (self.y > 2732 + cloudGraphics.height / 2) { self.y = -cloudGraphics.height / 2; } }; }); var ObstacleParticleEffect = Container.expand(function (x, y) { var self = Container.call(this); self.x = x; self.y = y; var particles = []; var angleIncrement = Math.PI * 2 / 30; var speed = 20; var dotColor = dot.children[0].tint; // Get the current color of the dot for (var i = 0; i < 30; i++) { var particle = self.attachAsset('obstacleParticle', { anchorX: 0.5, anchorY: 0.5, tint: dotColor }); particle.scaleX = particle.scaleY = 0.5; particle.alpha = 1; var angle = i * angleIncrement; particle.vx = Math.cos(angle) * speed; particle.vy = Math.sin(angle) * speed; particles.push(particle); } self._update_migrated = function () { for (var i = particles.length - 1; i >= 0; i--) { particles[i].x += particles[i].vx; particles[i].y += particles[i].vy; particles[i].rotation += 0.1; // Rotate the particle particles[i].alpha -= 0.0167; if (particles[i].alpha <= 0) { particles[i].destroy(); particles.splice(i, 1); } } if (particles.length === 0) { self.destroy(); particles = []; } }; game.addChild(self); }); var ObstacleScorePopup = Container.expand(function (x, y) { var self = Container.call(this); self.x = x; self.y = y; var scoreText = new Text2('+10', { size: 100, fill: "#ffffff", anchorX: 0.5, anchorY: 0.5 }); scoreText.x = -scoreText.width / 2; scoreText.y = -scoreText.height / 2; self.addChild(scoreText); self.alpha = 1; var duration = 120; self._update_migrated = function () { duration--; self.y -= 2; self.alpha -= 1 / 120; if (duration <= 0) { self.destroy(); } }; game.addChild(self); }); var OrbitLine = Container.expand(function (starX, starY, radius) { var self = Container.call(this); self.starX = starX; self.starY = starY; self.radius = radius; var segments = 50; var angleIncrement = Math.PI * 2 / segments; for (var i = 0; i < segments; i++) { var angle = i * angleIncrement; var dot = self.attachAsset('smallObstacle', { x: starX + Math.cos(angle) * radius, y: starY + Math.sin(angle) * radius, anchorX: 0.5, anchorY: 0.5, tint: [0xffe066, 0xcc66ff, 0xff6666, 0x99ccff, 0xffa500][Math.floor(Math.random() * 5)] }); if (i % 2 === 0) { dot.alpha = 0; } } self.moveDown = function (distance, dotY) { var speedMultiplier = dotY < 1200 ? 3 : dotY < 1400 ? 2 : dotY < 2000 ? 1.3 : dotY < 2300 ? 1.2 : 1; self.y += distance * speedMultiplier; }; }); var ParticleEffect = Container.expand(function (x, y, color) { var self = Container.call(this); self.x = x; self.y = y; var particles = []; for (var i = 0; i < 20; i++) { var particle = self.attachAsset('star', { anchorX: 0.5, anchorY: 0.5, tint: color }); particle.scaleX = particle.scaleY = Math.random() * 0.5 + 0.5; particle.alpha = 0.7; particle.vx = (Math.random() - 0.5) * 10; particle.vy = (Math.random() - 0.5) * 10; particles.push(particle); } self._update_migrated = function () { for (var i = particles.length - 1; i >= 0; i--) { particles[i].x += particles[i].vx; particles[i].y += particles[i].vy; particles[i].alpha -= 0.02; if (particles[i].alpha <= 0) { particles[i].destroy(); particles.splice(i, 1); } } if (particles.length === 0) { self.destroy(); } }; game.addChild(self); }); var ScorePopup = Container.expand(function (x, y) { var self = Container.call(this); self.x = x; self.y = y; var scoreText = new Text2('+' + (10 * (starCount + 1)).toString(), { size: 100, fill: "#ffffff", anchorX: 0.5, anchorY: 0.5 }); scoreText.x = -scoreText.width / 2; scoreText.y = -scoreText.height / 2; self.addChild(scoreText); self.alpha = 1; var duration = 120; self._update_migrated = function () { duration--; self.y -= 2; self.alpha -= 1 / 120; if (duration <= 0) { self.destroy(); } }; game.addChild(self); }); var Star = Container.expand(function (starNumber) { var self = Container.call(this); self.starNumber = starNumber; var starGraphics = self.attachAsset('star', { anchorX: 0.5, anchorY: 0.5, tint: getRandomTint() }); self.scaleDirection = 1; self.scaleSpeed = 0.005; self.minScale = 1; self.maxScale = 1.2; self.moveDown = function (distance, dotY) { self.y += distance * getSpeedMultiplier(dotY); if (self.y > 2732 - self.height / 2) { self.y = -self.height / 2; } for (var i = 0; i < clouds.length; i++) { clouds[i].y += distance * getSpeedMultiplier(dotY); } }; self.updateScale = function () { if (self.scaleDirection === 1 && starGraphics.scale.x < self.maxScale) { starGraphics.scale.x += self.scaleSpeed; starGraphics.scale.y += self.scaleSpeed; } else if (self.scaleDirection === -1 && starGraphics.scale.x > self.minScale) { starGraphics.scale.x -= self.scaleSpeed; starGraphics.scale.y -= self.scaleSpeed; } if (starGraphics.scale.x >= self.maxScale || starGraphics.scale.x <= self.minScale) { self.scaleDirection *= -1; } }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xD3D3D3 // Light grey color }); /**** * Game Code ****/ function fadeOutElements(elements, callback) { var duration = 60; // Duration of the fade-out effect in frames var frame = 0; var interval = LK.setInterval(function () { frame++; elements.forEach(function (element) { element.alpha -= 1 / duration; }); if (frame >= duration) { LK.clearInterval(interval); elements.forEach(function (element) { element.destroy(); }); if (callback) { callback(); } } }, 1000 / 60); } // Removed mainMenuBackground asset initialization function createHandDestroyEffect() { var effect = new HandDestroyEffect(hand.x, hand.y); LK.on('tick', function () { effect._update_migrated(); }); } function destroyHand() { if (hand) { createHandDestroyEffect(hand.x, hand.y); hand.destroy(); hand = null; } } function isCloudPositionValid(newY, existingClouds, minDistance) { for (var i = 0; i < existingClouds.length; i++) { if (Math.abs(newY - existingClouds[i].y) < minDistance) { return false; } } return true; } var remainingBounces; var clouds = []; for (var i = 0; i < 5; i++) { var cloud = new Cloud(); cloud.x = Math.random() * 2048; var newY; do { newY = Math.random() * 2732; } while (!isCloudPositionValid(newY, clouds, 200)); // Ensure clouds are at least 200 pixels apart cloud.y = newY; clouds.push(cloud); game.addChildAt(cloud, 0); // Add clouds behind other elements } function showHowToPlay() { var howToPlayScreen = new Container({ width: 2048, height: 2732, alpha: 0.5 }); var background = howToPlayScreen.attachAsset('mainMenuBackground', { anchorX: 0.5, anchorY: 0.5, alpha: 0.9, width: 2048, height: 2732 }); background.x = 2048 / 4; background.y = 2732 / 2; var endlessModeText = new Text2('Endless:\n\n• Tap to bounce!\n• Collect stars to score points and change color!\n• Avoid different colored obstacles! \n•. Destroy same colored obstacles to clear the path and get extra points!', { size: 50, fill: "#ffffff", stroke: "#000000", // Add border color strokeThickness: 8, // Add border thickness anchorX: 0.5, anchorY: 0.5, align: 'left', wordWrap: true, wordWrapWidth: 900 }); endlessModeText.x = 2048 / 4 - 900; endlessModeText.y = 2732 / 2 - 900; var challengesText = new Text2('Challenges:\n\n• Complete objectives by destroying obstacles! \n• Keep an eye on your remaining bounces! \n• Reach the higher level possible!', { size: 50, fill: "#ffffff", stroke: "#000000", // Add border color strokeThickness: 8, // Add border thickness anchorX: 0.5, anchorY: 0.5, align: 'left', wordWrap: true, wordWrapWidth: 900 }); challengesText.x = 2048 / 4 - 900; challengesText.y = 2732 / 2 - 300; var backButton = new Text2('Back', { size: 50, fill: "#ffffff", stroke: "#000000", // Add border color strokeThickness: 8, // Add border thickness anchorX: 0.5, anchorY: 0.5 }); backButton.x = 2048 / 4; backButton.y = 2732 - 200; backButton.down = function () { howToPlayScreen.destroy(); }; howToPlayScreen.addChild(background); howToPlayScreen.addChild(endlessModeText); howToPlayScreen.addChild(challengesText); howToPlayScreen.addChild(backButton); // Add event listener to close overlay when screen is touched howToPlayScreen.down = function () { howToPlayScreen.destroy(); }; LK.gui.top.addChild(howToPlayScreen); } function isValidStar(star) { return star && star.children && star.children[0] && typeof star.children[0].tint !== 'undefined' && star.y !== null && typeof star.y !== 'undefined'; } function resetGameToStartingPoint() { // Destroy all existing stars, obstacles, particles from ObstacleParticleEffect, and the dot stars.forEach(function (star) { star.destroy(); }); stars = []; obstacles.forEach(function (obstacle) { if (obstacle instanceof ObstacleParticleEffect) { obstacle.destroy(); } obstacle.destroy(); }); obstacles = []; if (dot) { dot.destroy(); dot = null; } remainingBounces = challenges[currentChallengeIndex].remainingBounces; console.log("Remaining bounces reset to initial value:", remainingBounces); // Reset star count starCount = 0; // Add initial star var star = game.addChildAt(new Star(), 1); star.x = 2048 / 2; star.y = 2732 / 2 - 500; stars.push(star); // Add initial dot if (!dot) { dot = game.addChild(new Dot()); dot.x = 2048 / 2; dot.y = 2732 - dot.height / 2 - 200; dotBouncing = true; } if (!hand) { createHand(); } handMoved = false; // Add initial orbit line var orbitLine = game.addChildAt(new OrbitLine(star.x, star.y, 300), 0); obstacles.push(orbitLine); // Add initial circular obstacle var starX = 2048 / 2; var starY = 2732 / 2 - 500; var radius = 300; var angleSpeed = 0.05; var obstacle = new CircularObstacle(starX, starY, radius, angleSpeed); game.addChildAt(obstacle, 2); obstacles.push(obstacle); // Check if the first star has at least one obstacle, if not, create it if (obstacles.length === 0) { var newObstacle = new CircularObstacle(starX, starY, radius, angleSpeed); game.addChildAt(newObstacle, 1); obstacles.push(newObstacle); } } // Ensure HUD is still over the rest of the elements game.addChild(hud); var CONFIG = { numColors: 2 // Default number of colors, can be set between 2 and 5 }; var gameMode = 'challenges'; // Default game mode var mainMenu = new MainMenu(); LK.gui.top.addChild(mainMenu); var scoreTxt; var hud = new HUD(); hud.visible = false; // Hide HUD on game start game.addChild(hud); function getRandomTint() { var colors = [0xffe066, 0xcc66ff, 0xff6666, 0x99ccff].slice(0, CONFIG.numColors); return colors[Math.floor(Math.random() * Math.min(CONFIG.numColors, colors.length))]; } function showChallengeCompletePopup(color) { var successAssets = ['success', 'success2', 'success3']; var randomSuccessAsset = successAssets[Math.floor(Math.random() * successAssets.length)]; var challengeCompletePopup = LK.getAsset(randomSuccessAsset, { anchorX: 0.5, anchorY: 0.5, tint: color, alpha: 0 }); challengeCompletePopup.x = 2048 / 2; challengeCompletePopup.y = 2732 / 2; game.addChild(challengeCompletePopup); var animationDuration = 120; var animationFrame = 0; var animationInterval = LK.setInterval(function () { if (animationFrame < animationDuration / 2) { if (animationFrame === 0) { challengeCompletePopup.alpha = 1; } challengeCompletePopup.scaleX = challengeCompletePopup.scaleY = 1 + 0.5 * (animationFrame / (animationDuration / 2)); } else { challengeCompletePopup.alpha = 1 - (animationFrame - animationDuration / 2) / (animationDuration / 2); challengeCompletePopup.scaleX = challengeCompletePopup.scaleY = 1.5 - 0.5 * (animationFrame - animationDuration / 2) / (animationDuration / 2); } animationFrame++; if (animationFrame >= animationDuration) { LK.clearInterval(animationInterval); challengeCompletePopup.destroy(); } }, 1000 / 60); } function getStarColor(starNumber) { var colors = [0xffe066, 0xcc66ff, 0xff6666, 0x99ccff].slice(0, CONFIG.numColors); return colors[starNumber % Math.min(CONFIG.numColors, colors.length)]; } function getSpeedMultiplier(dotY) { if (dotY < 1200) { return 3; } if (dotY < 1400) { return 2; } if (dotY < 2000) { return 1.3; } return 1.2; } function handleDotDestruction() { createDotParticleEffect(dot.x, dot.y); LK.getSound('explosion').play(); dot.destroyed = true; dot.destroy(); LK.setTimeout(function () { remainingBounces = challenges[currentChallengeIndex].remainingBounces; console.log("Remaining bounces reset due to dot destruction:", remainingBounces); LK.stopMusic(); LK.showGameOver(); }, 1000); } function createBounceEffect(x, y, color) { var effect = new BounceEffect(x, y + 80, color); // Adjust y position to start from a little more lower on the ball LK.on('tick', function () { // Ensure HUD is on top of everything if (game.children.indexOf(hud) !== game.children.length - 1) { game.addChild(hud); } effect._update_migrated(); }); } var shrinkFrame = 0; var shrinkDuration = 60; function startGame(mode) { gameMode = mode; hud.visible = true; // Show HUD when a game mode is selected if (!dot) { dot = game.addChild(new Dot()); dot.x = 2048 / 2; dot.y = 2732 - dot.height / 2 - 200; dotBouncing = true; } if (!hand) { hand = new Hand(); game.addChild(hand); hand.x = dot.x; hand.y = dot.y + dot.height / 2; } // Ensure obstacles are always on a higher layer than orbit lines for (var i = 0; i < obstacles.length; i++) { if (obstacles[i] instanceof CircularObstacle) { var obstacleIndex = game.children.indexOf(obstacles[i]); var orbitLineIndex = game.children.indexOf(orbitLine); if (obstacleIndex < orbitLineIndex) { game.setChildIndex(obstacles[i], orbitLineIndex + 1); } } } if (mode === 'endless') { CONFIG.numColors = 5; // Start endless mode // Add your endless mode initialization code here hud.removeChild(hud.children[0]); // Remove HUD background hud.challengeLevelTxt.visible = false; // Hide level text in endless mode hud.remainingBouncesIcon.visible = false; // Hide remaining bounces icon in endless mode hud.remainingBouncesTxt.visible = false; // Hide remaining bounces text in endless mode scoreTxt.x -= 100; // Move score text 100 pixels to the left scoreTxt.size *= 2; // Double the size of the score text scoreTxt.visible = true; // Show score text in endless mode } else if (mode === 'challenges') { CONFIG.numColors = 2; // Start challenges mode hud.challengeLevelTxt.visible = true; // Show level text in challenge mode hud.remainingBouncesIcon.visible = true; // Show remaining bounces icon in challenge mode hud.remainingBouncesTxt.visible = true; // Show remaining bounces text in challenge mode scoreTxt.visible = false; // Hide score text in challenge mode console.log("Remaining bounces reset for new game mode."); startNextChallenge(); } } // Pregame screen removed var challenges = [{ id: 1, numColors: 2, remainingBounces: 30, obstacles: [1] }, { id: 2, numColors: 2, remainingBounces: 40, obstacles: [1, 1] }, { id: 3, numColors: 2, remainingBounces: 50, obstacles: [2, 2] }, { id: 4, numColors: 3, remainingBounces: 50, obstacles: [1, 1, 1] }, { id: 5, numColors: 3, remainingBounces: 60, obstacles: [3, 2, 1] }, { id: 6, numColors: 3, remainingBounces: 70, obstacles: [2, 2, 2] }, { id: 7, numColors: 3, remainingBounces: 80, obstacles: [3, 3, 3] }, { id: 8, numColors: 4, remainingBounces: 70, obstacles: [1, 1, 1, 1] }, { id: 9, numColors: 4, remainingBounces: 80, obstacles: [1, 2, 3, 4] }, { id: 10, numColors: 4, remainingBounces: 99, obstacles: [5, 5, 5, 5] }, { id: 11, numColors: 4, remainingBounces: 99, obstacles: [5, 5, 5, 5] }, { id: 12, numColors: 4, remainingBounces: 99, obstacles: [5, 5, 5, 5] }, { id: 13, numColors: 4, remainingBounces: 99, obstacles: [5, 5, 5, 5] }, { id: 14, numColors: 4, remainingBounces: 99, obstacles: [5, 5, 5, 5] }, { id: 15, numColors: 4, remainingBounces: 99, obstacles: [5, 5, 5, 5] }]; var currentChallengeIndex = 0; var currentChallenge = null; function startNextChallenge() { if (gameMode === 'endless') { return; } if (currentChallengeIndex < challenges.length) { console.log("Starting next challenge with index:", currentChallengeIndex); // Clear previous challenge obstacles if (currentChallenge) { currentChallenge.forEach(function (challenge) { hud.removeChild(challenge); challenge.destroy(); }); currentChallenge = []; hud.updateChallenges(currentChallenge); } // Clear the challenges container hud.children.forEach(function (child) { if (child instanceof Challenge) { hud.removeChild(child); child.destroy(); } }); // Clear the challenges container hud.children.forEach(function (child) { if (child instanceof Challenge) { hud.removeChild(child); child.destroy(); } }); CONFIG.numColors = challenges[currentChallengeIndex].numColors; var challengeData = challenges[currentChallengeIndex]; var colors = [0xffe066, 0xcc66ff, 0xff6666, 0x99ccff, 0xffa500].slice(0, CONFIG.numColors); currentChallenge = []; challengeData.obstacles.forEach(function (amount, i) { var challengeColor = colors[i % colors.length]; var challenge = new Challenge(challengeColor, amount, challengeData.remainingBounces); currentChallenge.push(challenge); game.addChildAt(challenge, 2); }); bounceCount = 0; var totalWidth = currentChallenge.reduce(function (acc, challenge) { return acc + challenge.width + 20; // 20px gap }, -20); // Subtract the last gap hud.updateChallenges(currentChallenge); hud.challengeLevelTxt.setText('LVL ' + currentChallengeIndex); hud.updateScore(LK.getScore()); // Ensure score is updated in the HUD remainingBounces = challengeData.remainingBounces; hud.remainingBouncesTxt.setText(remainingBounces.toString()); // Reset remaining bounces text console.log("Remaining bounces reset to:", remainingBounces); // Ensure HUD is still over the rest of the elements if (hud.y < 0) { hud.y = 0; } if (hud.x < 0) { hud.x = 0; } if (hud.x + hud.width > 2048) { hud.x = 2048 - hud.width; } if (hud.y + hud.height > 2732) { hud.y = 2732 - hud.height; } } currentChallengeIndex++; } // startNextChallenge(); // Removed initial call to startNextChallenge function createObstacleParticleEffect(x, y) { var effect = new ObstacleParticleEffect(x, y); LK.on('tick', function () { effect._update_migrated(); }); } function changeStarColor(star) { var colors = [0xffe066, 0xcc66ff, 0xff6666, 0x99ccff].slice(0, CONFIG.numColors); var currentColorIndex = colors.indexOf(star.children[0].tint); var nextColorIndex = (currentColorIndex + 1) % Math.min(CONFIG.numColors, colors.length); star.children[0].tint = colors[nextColorIndex]; } function updateStarColors() { for (var i = 0; i < stars.length; i++) { changeStarColor(stars[i]); } } LK.setInterval(updateStarColors, 2000); var starCount = 0; // Initialize the offscreen threshold for destroying obstacles var offscreenThreshold = 2732 + 1000; function createParticleEffect(x, y, color) { var effect = new ParticleEffect(x, y, color); LK.on('tick', function () { effect._update_migrated(); }); } function createDotParticleEffect(x, y) { var effect = new DotParticleEffect(x, y); LK.on('tick', function () { effect._update_migrated(); }); } var obstacles = []; function updateObstacles() { var obstacleCount = 5 + starCount; while (obstacles.length < obstacleCount) { var obstacle = game.addChildAt(new Obstacle(), game.children.length - 1); // Ensure obstacle is in front of clouds obstacle.x = obstacle.direction === 1 ? -obstacle.width / 2 : 2048 + obstacle.width / 2; obstacle.y = Math.random() * (2732 - obstacle.height) + obstacle.height / 2; obstacles.push(obstacle); } // No longer move clouds when a star is destroyed } // Removed duplicate score text initialization and addition to the screen game.on('down', function (x, y, obj) { if (dot) { dot.bounceUp(); } }); var stars = []; var star = game.addChildAt(new Star(), 1); star.x = 2048 / 2; star.y = 2732 / 2 - 500; stars.push(star); LK.setInterval(function () { changeStarColor(star); }, 1000); // Initialize star with a random color from the obstacles // Add dotted orbit for the first star var orbitLine = game.addChild(new OrbitLine(star.x, star.y, 300)); obstacles.push(orbitLine); function spawnInitialObstacles() { var starX = 2048 / 2; var starY = 2732 / 2 - 500; var radius = 300; var angleSpeed = 0.05; var obstacle = new CircularObstacle(starX, starY, radius, angleSpeed); game.addChildAt(obstacle, game.children.length - 1); // Ensure obstacle is in front of clouds obstacles.push(obstacle); game.setChildIndex(star, game.children.length - 1); // Ensure star is in front of clouds // No additional obstacles for the first star } spawnInitialObstacles(); game.addChild(hud); LK.on('tick', function () { if (dot) { dot._update_migrated(); } for (var i = 0; i < obstacles.length; i++) { if (obstacles[i] instanceof CircularObstacle) { obstacles[i].updatePosition(); } else { if (typeof obstacles[i]._move_migrated === 'function') { obstacles[i]._move_migrated(); } } if (dot && dot.y < 2300 && dot.movedDistance < 0) { obstacles[i].moveDown(-dot.movedDistance, dot.y); } if (dot && dot.intersects && obstacles[i] && dot.intersects(obstacles[i]) && !(obstacles[i] instanceof OrbitLine) && dot !== null && obstacles[i] !== null && typeof dot.intersects === 'function') { if (dot.children[0].tint === obstacles[i].children[0].tint) { createObstacleParticleEffect(obstacles[i].x, obstacles[i].y); if (gameMode === 'endless') { if (gameMode === 'endless') { LK.setScore(LK.getScore() + 10); } else if (gameMode === 'challenges') { // Do not display points addition in challenge mode } } hud.updateScore(LK.getScore()); if (gameMode === 'endless') { var obstacleScorePopup = new ObstacleScorePopup(obstacles[i].x, obstacles[i].y); LK.on('tick', function () { obstacleScorePopup._update_migrated(); }); } LK.getSound('obstacle').play(); // Update challenge progress before destroying the obstacle if (currentChallenge) { for (var j = 0; j < currentChallenge.length; j++) { if (obstacles[i].children[0].tint === currentChallenge[j].color) { currentChallenge[j].updateProgress(); if (currentChallenge[j].completed) { currentChallenge.splice(j, 1); if (currentChallenge.length === 0) { startNextChallenge(); } } break; } } } if (obstacles[i]) { obstacles[i].destroy(); } obstacles.splice(i, 1); } else { if (!dot.destroyed) { createDotParticleEffect(dot.x, dot.y); LK.getSound('explosion').play(); dot.destroyed = true; } dot.destroy(); LK.setTimeout(function () { LK.showGameOver(); }, 1500); } } else if (obstacles[i] && obstacles[i].y > offscreenThreshold) { if (obstacles[i] && typeof obstacles[i].destroy === 'function') { obstacles[i].destroy(); } obstacles.splice(i, 1); } } for (var j = stars.length - 1; j >= 0; j--) { if (!dot || !stars[j]) { continue; } stars[j].updateScale(); if (dot && dot.intersects && stars[j] && isValidStar(stars[j]) && dot.intersects(stars[j]) && dot.y != null && stars[j].y != null && typeof dot.intersects === 'function' && dot.children && dot.children[0] && dot.children[0].y != null && stars[j].children && stars[j].children[0]) { destroyHand(); dot.inheritStarColor(stars[j]); if (gameMode === 'endless') { LK.setScore(LK.getScore() + 10 * (starCount + 1)); } else if (gameMode === 'challenges') { // Do not display points addition in challenge mode } hud.updateScore(LK.getScore()); var oldStarY = stars[j].y; createParticleEffect(stars[j].x, stars[j].y, stars[j].children[0].tint); LK.getSound('star').play(); if (gameMode === 'endless') { var scorePopup = new ScorePopup(stars[j].x, stars[j].y); LK.on('tick', function () { scorePopup._update_migrated(); }); } stars[j].destroy(); stars.splice(j, 1); starCount += 1; var newStar = game.addChildAt(new Star(), 1); game.setChildIndex(newStar, game.children.length - 1); // Ensure new star is in front of clouds newStar.x = 2048 / 2; var additionalYOffset = starCount > 1 ? (starCount - 1) * 200 : 0; newStar.y = oldStarY - 2000 - additionalYOffset; // Create new clouds if needed when a star is destroyed while (clouds.length < 5) { var cloud = new Cloud(); cloud.x = Math.random() * 2048; var newY; do { newY = Math.random() * 2732; } while (!isCloudPositionValid(newY, clouds, 200)); // Ensure clouds are at least 200 pixels apart cloud.y = newY; clouds.push(cloud); game.addChildAt(cloud, 0); // Add clouds behind other elements } stars.push(newStar); // Ensure new star also has the color change function changeStarColor(newStar); if (!handMoved && hand) { var handMoveDistance = 0; var handMoveInterval = LK.setInterval(function () { handMoveDistance += 1; hand._update_migrated(handMoveDistance); if (handMoveDistance >= 1000) { LK.clearInterval(handMoveInterval); } }, 10); handMoved = true; } // Increase the offscreen threshold for destroying obstacles offscreenThreshold += 300; // Add a cumulative number of CircularObstacles at random positions around the new star var cumulativeObstacles = 1 + starCount; for (var k = 0; k < cumulativeObstacles; k++) { var randomAngle = Math.random() * Math.PI * 2; // Random angle in radians var radiusOffset = k * 100; var circularObstacle = game.addChildAt(new CircularObstacle(newStar.x, newStar.y, 300 + radiusOffset, 0.05 * (k % 2 === 0 ? 1 : -1), randomAngle), 1); obstacles.push(circularObstacle); } // Add orbit line before creating all obstacles var orbitLine = new OrbitLine(newStar.x, newStar.y, 300 + radiusOffset); game.addChildAt(orbitLine, 1); obstacles.push(orbitLine); } else if (dot.y < 2300 && dot.movedDistance < 0) { stars[j].moveDown(-dot.movedDistance, dot.y); } } for (var i = 0; i < clouds.length; i++) { clouds[i]._update_migrated(); } }); var dot = null; var dotBouncing = false; var hand; var handMoved = false; function createHand() { hand = new Hand(); game.addChild(hand); hand.x = dot.x; hand.y = dot.y + dot.height / 2; }
/****
* Classes
****/
var BounceEffect = Container.expand(function (x, y, color) {
var self = Container.call(this);
self.x = x;
self.y = y;
var bounceGraphics = self.attachAsset('bounceEffect', {
anchorX: 0.5,
anchorY: 0.5
});
bounceGraphics.tint = color;
var duration = 30;
self._update_migrated = function () {
duration--;
bounceGraphics.scaleX += 0.1;
bounceGraphics.scaleY += 0.1;
bounceGraphics.alpha -= 0.033;
bounceGraphics.scaleX -= 0.01;
bounceGraphics.scaleY -= 0.01;
if (duration <= 0) {
self.destroy();
}
};
game.addChild(self);
});
var Challenge = Container.expand(function (color, amount, bounceLimit) {
var self = Container.call(this);
self.color = color;
self.amount = amount;
self.bounceLimit = bounceLimit;
self.remainingBounces = bounceLimit; // Initialize remainingBounces correctly
self.completed = false;
var obstacleIcon = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
tint: color,
scaleX: 0.5,
scaleY: 0.5
});
obstacleIcon.x = 250;
obstacleIcon.y = 40;
var challengeText = new Text2('0/' + amount, {
size: 75,
fill: "#ffffff",
stroke: "#000000",
strokeThickness: 8,
anchorX: 0.5,
anchorY: 0.5
});
challengeText.x = 300;
challengeText.y -= 10;
self.addChild(obstacleIcon);
self.addChild(challengeText);
self.updateProgress = function () {
self.amount -= 1;
challengeText.setText(amount - self.amount + '/' + amount);
if (self.amount <= 0) {
console.log("Objective complete for challenge with color:", self.color);
self.completed = true;
if (currentChallenge.every(function (challenge) {
console.log("All objectives complete for current challenge set. Whole challenge complete.");
return challenge.completed;
})) {
if (gameMode === 'challenges') {
LK.setScore(LK.getScore() + 1);
}
hud.updateScore(LK.getScore());
showChallengeCompletePopup(self.color);
currentChallenge.forEach(function (challenge) {
hud.removeChild(challenge);
console.log("Destroying challenge with color:", challenge.color);
challenge.destroy();
});
currentChallenge = [];
hud.updateChallenges(currentChallenge);
self.destroy(); // Ensure the challenge container is deleted
resetGameToStartingPoint();
startNextChallenge();
} else {}
}
};
});
var CircularObstacle = Container.expand(function (starX, starY, radius, angleSpeed, initialAngle) {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
tint: getRandomTint()
});
self.angle = initialAngle || 0;
self.radius = radius;
self.angleSpeed = angleSpeed * 0.75;
self.starX = starX;
self.starY = starY;
self.updatePosition = function () {
self.x = self.starX + Math.cos(self.angle) * self.radius;
self.y = self.starY + Math.sin(self.angle) * self.radius;
self.angle += self.angleSpeed * 0.35;
obstacleGraphics.rotation += self.angleSpeed * 0.35;
};
self.moveDown = function (distance, dotY) {
self.starY += distance * getSpeedMultiplier(dotY);
};
self.updatePosition();
});
var Cloud = Container.expand(function () {
var self = Container.call(this);
var cloudTypes = ['cloud1', 'cloud2', 'cloud3'];
var cloudType = cloudTypes[Math.floor(Math.random() * cloudTypes.length)];
var cloudGraphics = self.attachAsset(cloudType, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3 // Make clouds even more transparent
});
self.speed = Math.random() * 0.5 + 0.25; // Random speed between 0.25 and 0.75
self.alpha = 0;
var fadeInDuration = 60; // Duration of the fade-in effect in frames
var fadeInFrame = 0;
var fadeInInterval = LK.setInterval(function () {
fadeInFrame++;
self.alpha += 1 / fadeInDuration;
if (fadeInFrame >= fadeInDuration) {
LK.clearInterval(fadeInInterval);
}
}, 1000 / 60);
self.direction = Math.random() < 0.5 ? 1 : -1; // Random direction
self._update_migrated = function () {
self.x += self.speed * self.direction;
if (self.x > 2048 + cloudGraphics.width / 2) {
self.x = -cloudGraphics.width / 2;
} else if (self.x < -cloudGraphics.width / 2) {
self.x = 2048 + cloudGraphics.width / 2;
}
if (self.y > 2732 + cloudGraphics.height / 2) {
self.y = -cloudGraphics.height / 2;
}
};
});
var Dot = Container.expand(function () {
var self = Container.call(this);
var dotGraphics = self.attachAsset('dot', {
anchorX: 0.5,
anchorY: 0.5
});
self.destroyed = false;
self.alpha = 0;
var fadeInDuration = 60; // Duration of the fade-in effect in frames
var fadeInFrame = 0;
var fadeInInterval = LK.setInterval(function () {
fadeInFrame++;
self.alpha += 1 / fadeInDuration;
if (fadeInFrame >= fadeInDuration) {
LK.clearInterval(fadeInInterval);
}
}, 1000 / 60);
self.velocityY = 0;
self.gravity = 0.7;
self.bounce = -15;
self._update_migrated = function () {
if (!dotBouncing) {
return;
}
var previousY = self.y;
self.velocityY += self.gravity;
if (self.velocityY > 0 && dotGraphics.scaleX < 1) {
dotGraphics.scaleX += 0.02;
dotGraphics.scaleY -= 0.02;
} else if (self.velocityY < 0 && dotGraphics.scaleX > 0.9) {
dotGraphics.scaleX -= 0.01;
dotGraphics.scaleY += 0.01;
}
self.y += self.velocityY;
if (!self.firstTouch && !self.intersects(hand)) {
self.y = 2732 - self.height / 2 - 500;
} else if (self.intersects(hand)) {
self.bounceUp();
} else if (self.y > 2232 - self.height / 2 && self.firstTouch && !self.firstStarDestroyed) {
self.velocityY = self.bounce;
} else if (self.y > 2832 && !self.destroyed) {
handleDotDestruction();
}
self.movedDistance = self.y - previousY;
};
self.bounceUp = function () {
if (!self.destroyed) {
self.velocityY = self.bounce;
dot.scale.x *= 0.8;
dot.scale.y = 1.02;
LK.setTimeout(function () {
dot.scale.x = 1;
dot.scale.y = 1;
}, 90);
LK.getSound('bounce').play();
if (!self.intersects(hand)) {
createBounceEffect(self.x, self.y, dotGraphics.tint);
}
self.firstTouch = true;
if (!self.firstStarDestroyed) {
self.firstStarDestroyed = true;
}
if (gameMode === 'challenges' && !self.intersects(hand)) {
if (!currentChallenge[0].completed) {
remainingBounces--;
console.log("Remaining bounces decremented to:", remainingBounces);
hud.remainingBouncesTxt.setText(remainingBounces.toString());
if (remainingBounces <= 0) {
handleDotDestruction();
}
}
}
}
};
self.inheritStarColor = function (star) {
dotGraphics.tint = star.children[0].tint;
};
});
var DotParticleEffect = Container.expand(function (x, y) {
var self = Container.call(this);
self.x = x;
self.y = y;
var particles = [];
var angleIncrement = Math.PI * 2 / 20;
var speed = 30;
var colors = [0xffe066, 0xcc66ff, 0xff6666, 0x99ccff].slice(0, CONFIG.numColors);
for (var i = 0; i < 20; i++) {
var particle = self.attachAsset('dotParticle', {
anchorX: 0.5,
anchorY: 0.5,
tint: colors[Math.floor(Math.random() * colors.length)]
});
particle.scaleX = particle.scaleY = 0.5;
particle.alpha = 1;
var angle = i * angleIncrement;
particle.vx = Math.cos(angle) * speed;
particle.vy = Math.sin(angle) * speed;
particles.push(particle);
}
self._update_migrated = function () {
for (var i = particles.length - 1; i >= 0; i--) {
particles[i].x += particles[i].vx;
particles[i].y += particles[i].vy;
particles[i].rotation += 0.1; // Rotate the particle
particles[i].alpha -= 0.0167;
if (particles[i].alpha <= 0) {
particles[i].destroy();
particles.splice(i, 1);
}
}
if (particles.length === 0) {
self.destroy();
}
};
game.addChild(self);
});
var HUD = Container.expand(function () {
var self = Container.call(this);
// Create background line for HUD
var backgroundLine = self.attachAsset('backgroundLine', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.5
});
backgroundLine.x = 2048 / 2 + 200;
backgroundLine.y = 75;
// Create score text
scoreTxt = new Text2('0', {
size: 200,
// Reduced size to fit within the HUD
fill: "#ffffff",
stroke: "#000000",
strokeThickness: 8
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.x = 2048 - 200 + 80; // Adjusted position to fit within the HUD
scoreTxt.y = -10; // Adjusted position to fit within the HUD
self.addChild(scoreTxt);
// Create challenge level text
self.challengeLevelTxt = new Text2('LVL 0', {
size: 75,
fill: "#ffffff",
stroke: "#000000",
strokeThickness: 8
});
self.challengeLevelTxt.anchor.set(0, 0);
self.challengeLevelTxt.x = 320;
self.challengeLevelTxt.y = 80;
self.addChild(self.challengeLevelTxt);
// Create remaining bounces text
self.remainingBouncesIcon = self.attachAsset('dot', {
anchorX: 1,
anchorY: 0,
scaleX: 0.5,
scaleY: 0.5
});
self.remainingBouncesIcon.x = 2048 - 30 + 150;
self.remainingBouncesIcon.y = 40;
self.remainingBouncesIcon.visible = true; // Ensure the remaining bounces icon is always visible
self.addChild(self.remainingBouncesIcon);
self.remainingBouncesTxt = new Text2('0', {
size: 75,
fill: "#ffffff",
stroke: "#000000",
strokeThickness: 8
});
self.remainingBouncesTxt.anchor.set(1, 0);
self.remainingBouncesTxt.x = 2048 + 70 + 150;
self.remainingBouncesTxt.y = 30;
self.remainingBouncesTxt.visible = true; // Ensure the remaining bounces text is always visible
self.addChild(self.remainingBouncesTxt);
// Removed challenges container
self.updateScore = function (score) {
scoreTxt.setText(score.toString());
};
self.updateChallenges = function (challenges) {
var totalWidth = challenges.reduce(function (acc, challenge) {
return acc + challenge.width + 20; // 20px gap
}, -20); // Subtract the last gap
var startX = (2048 - totalWidth) / 2;
challenges.forEach(function (challenge, i) {
challenge.x = startX + i * (challenge.width + 20);
challenge.y = 40; // Ensure all challenges are aligned vertically
self.addChild(challenge);
});
// Keep the level text fixed in the initial spot
self.challengeLevelTxt.x = 320;
self.challengeLevelTxt.y = 30;
self.challengeLevelTxt.visible = true; // Ensure the level text is always visible
};
return self;
});
// Add Hand asset below the dot
var Hand = Container.expand(function () {
var self = Container.call(this);
var handGraphics = self.attachAsset('hand', {
anchorX: 0.5,
anchorY: 0,
alpha: 0.7
});
self.alpha = 0;
var fadeInDuration = 60; // Duration of the fade-in effect in frames
var fadeInFrame = 0;
var fadeInInterval = LK.setInterval(function () {
fadeInFrame++;
self.alpha += 1 / fadeInDuration;
if (fadeInFrame >= fadeInDuration) {
LK.clearInterval(fadeInInterval);
}
}, 1000 / 60);
self._update_migrated = function (distance) {
if (distance) {
self.y += distance;
}
};
});
var HandDestroyEffect = Container.expand(function (x, y) {
var self = Container.call(this);
self.x = x;
self.y = y;
var handGraphics = self.attachAsset('hand', {
anchorX: 0.5,
anchorY: 0
});
self._update_migrated = function () {
self.y += 10; // Move the hand downwards faster
if (self.y > 2732 + handGraphics.height / 2) {
// Check if the hand is off-screen
self.destroy();
}
};
game.addChild(self);
});
var MainMenu = Container.expand(function () {
var self = Container.call(this);
// Removed background
// Create Endless button using endless asset
var endlessButton = self.attachAsset('Endless', {
anchorX: 0.5,
anchorY: 0.5
});
endlessButton.x = 0;
endlessButton.y = 1200;
endlessButton.floatDirection = 1;
endlessButton.floatSpeed = 0.5;
endlessButton.floatRange = 10;
endlessButton.down = function () {
LK.getSound('button').play();
LK.getSound('bounce').play();
// LK.stopMusic();
fadeOutElements([gameTitle, endlessButton, challengesButton, howToPlayButton].concat(mainMenuClouds), function () {
startGame('endless');
});
};
endlessButton._update_migrated = function () {
endlessButton.y += endlessButton.floatSpeed * endlessButton.floatDirection;
if (endlessButton.y >= 1200 + endlessButton.floatRange || endlessButton.y <= 1200 - endlessButton.floatRange) {
endlessButton.floatDirection *= -1;
}
};
LK.on('tick', function () {
endlessButton._update_migrated();
});
// Create Challenges button using challenges asset
var challengesButton = self.attachAsset('Challenges', {
anchorX: 0.5,
anchorY: 0.5
});
challengesButton.x = 0;
challengesButton.y = 1450;
challengesButton.floatDirection = 1;
challengesButton.floatSpeed = 0.5;
challengesButton.floatRange = 10;
challengesButton.down = function () {
LK.getSound('button').play();
LK.getSound('bounce').play();
// LK.stopMusic();
fadeOutElements([gameTitle, endlessButton, challengesButton, howToPlayButton].concat(mainMenuClouds), function () {
startGame('challenges');
});
};
challengesButton._update_migrated = function () {
challengesButton.y += challengesButton.floatSpeed * challengesButton.floatDirection;
if (challengesButton.y >= 1450 + challengesButton.floatRange || challengesButton.y <= 1450 - challengesButton.floatRange) {
challengesButton.floatDirection *= -1;
}
};
LK.on('tick', function () {
challengesButton._update_migrated();
});
// Create game title using gametitle asset
var gameTitle = self.attachAsset('gametitle', {
anchorX: 0.5,
anchorY: 0.5
});
gameTitle.x = 0;
gameTitle.y = 600;
// self.addChild(background); // Removed undefined background reference
// Create How to Play button using a new asset
var howToPlayButton = new Text2('how to play', {
size: 50,
fill: "#ffffff",
stroke: "#000000",
// Add border color
strokeThickness: 8,
// Add border thickness
anchorX: 0.5,
anchorY: 0.5,
align: 'center' // Center justify the text
});
howToPlayButton.x = -125;
howToPlayButton.y = 1700;
howToPlayButton.blinking = true;
howToPlayButton.blinkSpeed = 0.005;
howToPlayButton.blinkDirection = 1;
howToPlayButton.down = function () {
LK.getSound('button').play();
showHowToPlay();
};
howToPlayButton._update_migrated = function () {
if (howToPlayButton.blinking) {
howToPlayButton.alpha += howToPlayButton.blinkSpeed * howToPlayButton.blinkDirection;
if (howToPlayButton.alpha >= 1) {
howToPlayButton.alpha = 1;
howToPlayButton.blinkDirection = -1;
} else if (howToPlayButton.alpha <= 0.1) {
howToPlayButton.alpha = 0.1;
howToPlayButton.blinkDirection = 1;
}
}
};
LK.on('tick', function () {
howToPlayButton._update_migrated();
});
gameTitle.tiltDirection = 1;
gameTitle.tiltSpeed = 0.001;
gameTitle.maxTilt = 0.1;
gameTitle._update_migrated = function () {
gameTitle.rotation += gameTitle.tiltSpeed * gameTitle.tiltDirection;
if (gameTitle.rotation >= gameTitle.maxTilt || gameTitle.rotation <= -gameTitle.maxTilt) {
gameTitle.tiltDirection *= -1;
}
};
LK.on('tick', function () {
gameTitle._update_migrated();
});
// Add clouds to the main menu background
var mainMenuClouds = [];
for (var i = 0; i < 10; i++) {
var cloud = new MainMenuCloud();
cloud.x = Math.random() * 2048 - 2600;
var newY;
do {
newY = Math.random() * 2732;
} while (!isCloudPositionValid(newY, mainMenuClouds, 200)); // Ensure clouds are at least 200 pixels apart
cloud.y = newY;
mainMenuClouds.push(cloud);
self.addChild(cloud);
}
self.addChild(gameTitle);
self.addChild(endlessButton);
self.addChild(challengesButton);
self.addChild(howToPlayButton);
// Update clouds on the main menu background
LK.on('tick', function () {
for (var i = 0; i < mainMenuClouds.length; i++) {
mainMenuClouds[i]._update_migrated();
}
});
// Play game music after 2 seconds
LK.setTimeout(function () {
LK.playMusic('gamemusic');
}, 2000);
});
var MainMenuCloud = Container.expand(function () {
var self = Container.call(this);
var cloudTypes = ['cloud1', 'cloud2', 'cloud3'];
var cloudType = cloudTypes[Math.floor(Math.random() * cloudTypes.length)];
var cloudGraphics = self.attachAsset(cloudType, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3 // Make clouds even more transparent
});
self.speed = Math.random() * 0.5 + 0.25; // Random speed between 0.25 and 0.75
self.direction = Math.random() < 0.5 ? 1 : -1; // Random direction
self._update_migrated = function () {
self.x += self.speed * self.direction;
if (self.x > 2048 + cloudGraphics.width / 2) {
self.x = -cloudGraphics.width / 2;
} else if (self.x < -cloudGraphics.width / 2) {
self.x = 2048 + cloudGraphics.width / 2;
}
if (self.y > 2732 + cloudGraphics.height / 2) {
self.y = -cloudGraphics.height / 2;
}
};
});
var ObstacleParticleEffect = Container.expand(function (x, y) {
var self = Container.call(this);
self.x = x;
self.y = y;
var particles = [];
var angleIncrement = Math.PI * 2 / 30;
var speed = 20;
var dotColor = dot.children[0].tint; // Get the current color of the dot
for (var i = 0; i < 30; i++) {
var particle = self.attachAsset('obstacleParticle', {
anchorX: 0.5,
anchorY: 0.5,
tint: dotColor
});
particle.scaleX = particle.scaleY = 0.5;
particle.alpha = 1;
var angle = i * angleIncrement;
particle.vx = Math.cos(angle) * speed;
particle.vy = Math.sin(angle) * speed;
particles.push(particle);
}
self._update_migrated = function () {
for (var i = particles.length - 1; i >= 0; i--) {
particles[i].x += particles[i].vx;
particles[i].y += particles[i].vy;
particles[i].rotation += 0.1; // Rotate the particle
particles[i].alpha -= 0.0167;
if (particles[i].alpha <= 0) {
particles[i].destroy();
particles.splice(i, 1);
}
}
if (particles.length === 0) {
self.destroy();
particles = [];
}
};
game.addChild(self);
});
var ObstacleScorePopup = Container.expand(function (x, y) {
var self = Container.call(this);
self.x = x;
self.y = y;
var scoreText = new Text2('+10', {
size: 100,
fill: "#ffffff",
anchorX: 0.5,
anchorY: 0.5
});
scoreText.x = -scoreText.width / 2;
scoreText.y = -scoreText.height / 2;
self.addChild(scoreText);
self.alpha = 1;
var duration = 120;
self._update_migrated = function () {
duration--;
self.y -= 2;
self.alpha -= 1 / 120;
if (duration <= 0) {
self.destroy();
}
};
game.addChild(self);
});
var OrbitLine = Container.expand(function (starX, starY, radius) {
var self = Container.call(this);
self.starX = starX;
self.starY = starY;
self.radius = radius;
var segments = 50;
var angleIncrement = Math.PI * 2 / segments;
for (var i = 0; i < segments; i++) {
var angle = i * angleIncrement;
var dot = self.attachAsset('smallObstacle', {
x: starX + Math.cos(angle) * radius,
y: starY + Math.sin(angle) * radius,
anchorX: 0.5,
anchorY: 0.5,
tint: [0xffe066, 0xcc66ff, 0xff6666, 0x99ccff, 0xffa500][Math.floor(Math.random() * 5)]
});
if (i % 2 === 0) {
dot.alpha = 0;
}
}
self.moveDown = function (distance, dotY) {
var speedMultiplier = dotY < 1200 ? 3 : dotY < 1400 ? 2 : dotY < 2000 ? 1.3 : dotY < 2300 ? 1.2 : 1;
self.y += distance * speedMultiplier;
};
});
var ParticleEffect = Container.expand(function (x, y, color) {
var self = Container.call(this);
self.x = x;
self.y = y;
var particles = [];
for (var i = 0; i < 20; i++) {
var particle = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
tint: color
});
particle.scaleX = particle.scaleY = Math.random() * 0.5 + 0.5;
particle.alpha = 0.7;
particle.vx = (Math.random() - 0.5) * 10;
particle.vy = (Math.random() - 0.5) * 10;
particles.push(particle);
}
self._update_migrated = function () {
for (var i = particles.length - 1; i >= 0; i--) {
particles[i].x += particles[i].vx;
particles[i].y += particles[i].vy;
particles[i].alpha -= 0.02;
if (particles[i].alpha <= 0) {
particles[i].destroy();
particles.splice(i, 1);
}
}
if (particles.length === 0) {
self.destroy();
}
};
game.addChild(self);
});
var ScorePopup = Container.expand(function (x, y) {
var self = Container.call(this);
self.x = x;
self.y = y;
var scoreText = new Text2('+' + (10 * (starCount + 1)).toString(), {
size: 100,
fill: "#ffffff",
anchorX: 0.5,
anchorY: 0.5
});
scoreText.x = -scoreText.width / 2;
scoreText.y = -scoreText.height / 2;
self.addChild(scoreText);
self.alpha = 1;
var duration = 120;
self._update_migrated = function () {
duration--;
self.y -= 2;
self.alpha -= 1 / 120;
if (duration <= 0) {
self.destroy();
}
};
game.addChild(self);
});
var Star = Container.expand(function (starNumber) {
var self = Container.call(this);
self.starNumber = starNumber;
var starGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
tint: getRandomTint()
});
self.scaleDirection = 1;
self.scaleSpeed = 0.005;
self.minScale = 1;
self.maxScale = 1.2;
self.moveDown = function (distance, dotY) {
self.y += distance * getSpeedMultiplier(dotY);
if (self.y > 2732 - self.height / 2) {
self.y = -self.height / 2;
}
for (var i = 0; i < clouds.length; i++) {
clouds[i].y += distance * getSpeedMultiplier(dotY);
}
};
self.updateScale = function () {
if (self.scaleDirection === 1 && starGraphics.scale.x < self.maxScale) {
starGraphics.scale.x += self.scaleSpeed;
starGraphics.scale.y += self.scaleSpeed;
} else if (self.scaleDirection === -1 && starGraphics.scale.x > self.minScale) {
starGraphics.scale.x -= self.scaleSpeed;
starGraphics.scale.y -= self.scaleSpeed;
}
if (starGraphics.scale.x >= self.maxScale || starGraphics.scale.x <= self.minScale) {
self.scaleDirection *= -1;
}
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xD3D3D3 // Light grey color
});
/****
* Game Code
****/
function fadeOutElements(elements, callback) {
var duration = 60; // Duration of the fade-out effect in frames
var frame = 0;
var interval = LK.setInterval(function () {
frame++;
elements.forEach(function (element) {
element.alpha -= 1 / duration;
});
if (frame >= duration) {
LK.clearInterval(interval);
elements.forEach(function (element) {
element.destroy();
});
if (callback) {
callback();
}
}
}, 1000 / 60);
}
// Removed mainMenuBackground asset initialization
function createHandDestroyEffect() {
var effect = new HandDestroyEffect(hand.x, hand.y);
LK.on('tick', function () {
effect._update_migrated();
});
}
function destroyHand() {
if (hand) {
createHandDestroyEffect(hand.x, hand.y);
hand.destroy();
hand = null;
}
}
function isCloudPositionValid(newY, existingClouds, minDistance) {
for (var i = 0; i < existingClouds.length; i++) {
if (Math.abs(newY - existingClouds[i].y) < minDistance) {
return false;
}
}
return true;
}
var remainingBounces;
var clouds = [];
for (var i = 0; i < 5; i++) {
var cloud = new Cloud();
cloud.x = Math.random() * 2048;
var newY;
do {
newY = Math.random() * 2732;
} while (!isCloudPositionValid(newY, clouds, 200)); // Ensure clouds are at least 200 pixels apart
cloud.y = newY;
clouds.push(cloud);
game.addChildAt(cloud, 0); // Add clouds behind other elements
}
function showHowToPlay() {
var howToPlayScreen = new Container({
width: 2048,
height: 2732,
alpha: 0.5
});
var background = howToPlayScreen.attachAsset('mainMenuBackground', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9,
width: 2048,
height: 2732
});
background.x = 2048 / 4;
background.y = 2732 / 2;
var endlessModeText = new Text2('Endless:\n\n• Tap to bounce!\n• Collect stars to score points and change color!\n• Avoid different colored obstacles! \n•. Destroy same colored obstacles to clear the path and get extra points!', {
size: 50,
fill: "#ffffff",
stroke: "#000000",
// Add border color
strokeThickness: 8,
// Add border thickness
anchorX: 0.5,
anchorY: 0.5,
align: 'left',
wordWrap: true,
wordWrapWidth: 900
});
endlessModeText.x = 2048 / 4 - 900;
endlessModeText.y = 2732 / 2 - 900;
var challengesText = new Text2('Challenges:\n\n• Complete objectives by destroying obstacles! \n• Keep an eye on your remaining bounces! \n• Reach the higher level possible!', {
size: 50,
fill: "#ffffff",
stroke: "#000000",
// Add border color
strokeThickness: 8,
// Add border thickness
anchorX: 0.5,
anchorY: 0.5,
align: 'left',
wordWrap: true,
wordWrapWidth: 900
});
challengesText.x = 2048 / 4 - 900;
challengesText.y = 2732 / 2 - 300;
var backButton = new Text2('Back', {
size: 50,
fill: "#ffffff",
stroke: "#000000",
// Add border color
strokeThickness: 8,
// Add border thickness
anchorX: 0.5,
anchorY: 0.5
});
backButton.x = 2048 / 4;
backButton.y = 2732 - 200;
backButton.down = function () {
howToPlayScreen.destroy();
};
howToPlayScreen.addChild(background);
howToPlayScreen.addChild(endlessModeText);
howToPlayScreen.addChild(challengesText);
howToPlayScreen.addChild(backButton);
// Add event listener to close overlay when screen is touched
howToPlayScreen.down = function () {
howToPlayScreen.destroy();
};
LK.gui.top.addChild(howToPlayScreen);
}
function isValidStar(star) {
return star && star.children && star.children[0] && typeof star.children[0].tint !== 'undefined' && star.y !== null && typeof star.y !== 'undefined';
}
function resetGameToStartingPoint() {
// Destroy all existing stars, obstacles, particles from ObstacleParticleEffect, and the dot
stars.forEach(function (star) {
star.destroy();
});
stars = [];
obstacles.forEach(function (obstacle) {
if (obstacle instanceof ObstacleParticleEffect) {
obstacle.destroy();
}
obstacle.destroy();
});
obstacles = [];
if (dot) {
dot.destroy();
dot = null;
}
remainingBounces = challenges[currentChallengeIndex].remainingBounces;
console.log("Remaining bounces reset to initial value:", remainingBounces);
// Reset star count
starCount = 0;
// Add initial star
var star = game.addChildAt(new Star(), 1);
star.x = 2048 / 2;
star.y = 2732 / 2 - 500;
stars.push(star);
// Add initial dot
if (!dot) {
dot = game.addChild(new Dot());
dot.x = 2048 / 2;
dot.y = 2732 - dot.height / 2 - 200;
dotBouncing = true;
}
if (!hand) {
createHand();
}
handMoved = false;
// Add initial orbit line
var orbitLine = game.addChildAt(new OrbitLine(star.x, star.y, 300), 0);
obstacles.push(orbitLine);
// Add initial circular obstacle
var starX = 2048 / 2;
var starY = 2732 / 2 - 500;
var radius = 300;
var angleSpeed = 0.05;
var obstacle = new CircularObstacle(starX, starY, radius, angleSpeed);
game.addChildAt(obstacle, 2);
obstacles.push(obstacle);
// Check if the first star has at least one obstacle, if not, create it
if (obstacles.length === 0) {
var newObstacle = new CircularObstacle(starX, starY, radius, angleSpeed);
game.addChildAt(newObstacle, 1);
obstacles.push(newObstacle);
}
}
// Ensure HUD is still over the rest of the elements
game.addChild(hud);
var CONFIG = {
numColors: 2 // Default number of colors, can be set between 2 and 5
};
var gameMode = 'challenges'; // Default game mode
var mainMenu = new MainMenu();
LK.gui.top.addChild(mainMenu);
var scoreTxt;
var hud = new HUD();
hud.visible = false; // Hide HUD on game start
game.addChild(hud);
function getRandomTint() {
var colors = [0xffe066, 0xcc66ff, 0xff6666, 0x99ccff].slice(0, CONFIG.numColors);
return colors[Math.floor(Math.random() * Math.min(CONFIG.numColors, colors.length))];
}
function showChallengeCompletePopup(color) {
var successAssets = ['success', 'success2', 'success3'];
var randomSuccessAsset = successAssets[Math.floor(Math.random() * successAssets.length)];
var challengeCompletePopup = LK.getAsset(randomSuccessAsset, {
anchorX: 0.5,
anchorY: 0.5,
tint: color,
alpha: 0
});
challengeCompletePopup.x = 2048 / 2;
challengeCompletePopup.y = 2732 / 2;
game.addChild(challengeCompletePopup);
var animationDuration = 120;
var animationFrame = 0;
var animationInterval = LK.setInterval(function () {
if (animationFrame < animationDuration / 2) {
if (animationFrame === 0) {
challengeCompletePopup.alpha = 1;
}
challengeCompletePopup.scaleX = challengeCompletePopup.scaleY = 1 + 0.5 * (animationFrame / (animationDuration / 2));
} else {
challengeCompletePopup.alpha = 1 - (animationFrame - animationDuration / 2) / (animationDuration / 2);
challengeCompletePopup.scaleX = challengeCompletePopup.scaleY = 1.5 - 0.5 * (animationFrame - animationDuration / 2) / (animationDuration / 2);
}
animationFrame++;
if (animationFrame >= animationDuration) {
LK.clearInterval(animationInterval);
challengeCompletePopup.destroy();
}
}, 1000 / 60);
}
function getStarColor(starNumber) {
var colors = [0xffe066, 0xcc66ff, 0xff6666, 0x99ccff].slice(0, CONFIG.numColors);
return colors[starNumber % Math.min(CONFIG.numColors, colors.length)];
}
function getSpeedMultiplier(dotY) {
if (dotY < 1200) {
return 3;
}
if (dotY < 1400) {
return 2;
}
if (dotY < 2000) {
return 1.3;
}
return 1.2;
}
function handleDotDestruction() {
createDotParticleEffect(dot.x, dot.y);
LK.getSound('explosion').play();
dot.destroyed = true;
dot.destroy();
LK.setTimeout(function () {
remainingBounces = challenges[currentChallengeIndex].remainingBounces;
console.log("Remaining bounces reset due to dot destruction:", remainingBounces);
LK.stopMusic();
LK.showGameOver();
}, 1000);
}
function createBounceEffect(x, y, color) {
var effect = new BounceEffect(x, y + 80, color); // Adjust y position to start from a little more lower on the ball
LK.on('tick', function () {
// Ensure HUD is on top of everything
if (game.children.indexOf(hud) !== game.children.length - 1) {
game.addChild(hud);
}
effect._update_migrated();
});
}
var shrinkFrame = 0;
var shrinkDuration = 60;
function startGame(mode) {
gameMode = mode;
hud.visible = true; // Show HUD when a game mode is selected
if (!dot) {
dot = game.addChild(new Dot());
dot.x = 2048 / 2;
dot.y = 2732 - dot.height / 2 - 200;
dotBouncing = true;
}
if (!hand) {
hand = new Hand();
game.addChild(hand);
hand.x = dot.x;
hand.y = dot.y + dot.height / 2;
}
// Ensure obstacles are always on a higher layer than orbit lines
for (var i = 0; i < obstacles.length; i++) {
if (obstacles[i] instanceof CircularObstacle) {
var obstacleIndex = game.children.indexOf(obstacles[i]);
var orbitLineIndex = game.children.indexOf(orbitLine);
if (obstacleIndex < orbitLineIndex) {
game.setChildIndex(obstacles[i], orbitLineIndex + 1);
}
}
}
if (mode === 'endless') {
CONFIG.numColors = 5;
// Start endless mode
// Add your endless mode initialization code here
hud.removeChild(hud.children[0]); // Remove HUD background
hud.challengeLevelTxt.visible = false; // Hide level text in endless mode
hud.remainingBouncesIcon.visible = false; // Hide remaining bounces icon in endless mode
hud.remainingBouncesTxt.visible = false; // Hide remaining bounces text in endless mode
scoreTxt.x -= 100; // Move score text 100 pixels to the left
scoreTxt.size *= 2; // Double the size of the score text
scoreTxt.visible = true; // Show score text in endless mode
} else if (mode === 'challenges') {
CONFIG.numColors = 2;
// Start challenges mode
hud.challengeLevelTxt.visible = true; // Show level text in challenge mode
hud.remainingBouncesIcon.visible = true; // Show remaining bounces icon in challenge mode
hud.remainingBouncesTxt.visible = true; // Show remaining bounces text in challenge mode
scoreTxt.visible = false; // Hide score text in challenge mode
console.log("Remaining bounces reset for new game mode.");
startNextChallenge();
}
}
// Pregame screen removed
var challenges = [{
id: 1,
numColors: 2,
remainingBounces: 30,
obstacles: [1]
}, {
id: 2,
numColors: 2,
remainingBounces: 40,
obstacles: [1, 1]
}, {
id: 3,
numColors: 2,
remainingBounces: 50,
obstacles: [2, 2]
}, {
id: 4,
numColors: 3,
remainingBounces: 50,
obstacles: [1, 1, 1]
}, {
id: 5,
numColors: 3,
remainingBounces: 60,
obstacles: [3, 2, 1]
}, {
id: 6,
numColors: 3,
remainingBounces: 70,
obstacles: [2, 2, 2]
}, {
id: 7,
numColors: 3,
remainingBounces: 80,
obstacles: [3, 3, 3]
}, {
id: 8,
numColors: 4,
remainingBounces: 70,
obstacles: [1, 1, 1, 1]
}, {
id: 9,
numColors: 4,
remainingBounces: 80,
obstacles: [1, 2, 3, 4]
}, {
id: 10,
numColors: 4,
remainingBounces: 99,
obstacles: [5, 5, 5, 5]
}, {
id: 11,
numColors: 4,
remainingBounces: 99,
obstacles: [5, 5, 5, 5]
}, {
id: 12,
numColors: 4,
remainingBounces: 99,
obstacles: [5, 5, 5, 5]
}, {
id: 13,
numColors: 4,
remainingBounces: 99,
obstacles: [5, 5, 5, 5]
}, {
id: 14,
numColors: 4,
remainingBounces: 99,
obstacles: [5, 5, 5, 5]
}, {
id: 15,
numColors: 4,
remainingBounces: 99,
obstacles: [5, 5, 5, 5]
}];
var currentChallengeIndex = 0;
var currentChallenge = null;
function startNextChallenge() {
if (gameMode === 'endless') {
return;
}
if (currentChallengeIndex < challenges.length) {
console.log("Starting next challenge with index:", currentChallengeIndex);
// Clear previous challenge obstacles
if (currentChallenge) {
currentChallenge.forEach(function (challenge) {
hud.removeChild(challenge);
challenge.destroy();
});
currentChallenge = [];
hud.updateChallenges(currentChallenge);
}
// Clear the challenges container
hud.children.forEach(function (child) {
if (child instanceof Challenge) {
hud.removeChild(child);
child.destroy();
}
});
// Clear the challenges container
hud.children.forEach(function (child) {
if (child instanceof Challenge) {
hud.removeChild(child);
child.destroy();
}
});
CONFIG.numColors = challenges[currentChallengeIndex].numColors;
var challengeData = challenges[currentChallengeIndex];
var colors = [0xffe066, 0xcc66ff, 0xff6666, 0x99ccff, 0xffa500].slice(0, CONFIG.numColors);
currentChallenge = [];
challengeData.obstacles.forEach(function (amount, i) {
var challengeColor = colors[i % colors.length];
var challenge = new Challenge(challengeColor, amount, challengeData.remainingBounces);
currentChallenge.push(challenge);
game.addChildAt(challenge, 2);
});
bounceCount = 0;
var totalWidth = currentChallenge.reduce(function (acc, challenge) {
return acc + challenge.width + 20; // 20px gap
}, -20); // Subtract the last gap
hud.updateChallenges(currentChallenge);
hud.challengeLevelTxt.setText('LVL ' + currentChallengeIndex);
hud.updateScore(LK.getScore()); // Ensure score is updated in the HUD
remainingBounces = challengeData.remainingBounces;
hud.remainingBouncesTxt.setText(remainingBounces.toString()); // Reset remaining bounces text
console.log("Remaining bounces reset to:", remainingBounces);
// Ensure HUD is still over the rest of the elements
if (hud.y < 0) {
hud.y = 0;
}
if (hud.x < 0) {
hud.x = 0;
}
if (hud.x + hud.width > 2048) {
hud.x = 2048 - hud.width;
}
if (hud.y + hud.height > 2732) {
hud.y = 2732 - hud.height;
}
}
currentChallengeIndex++;
}
// startNextChallenge(); // Removed initial call to startNextChallenge
function createObstacleParticleEffect(x, y) {
var effect = new ObstacleParticleEffect(x, y);
LK.on('tick', function () {
effect._update_migrated();
});
}
function changeStarColor(star) {
var colors = [0xffe066, 0xcc66ff, 0xff6666, 0x99ccff].slice(0, CONFIG.numColors);
var currentColorIndex = colors.indexOf(star.children[0].tint);
var nextColorIndex = (currentColorIndex + 1) % Math.min(CONFIG.numColors, colors.length);
star.children[0].tint = colors[nextColorIndex];
}
function updateStarColors() {
for (var i = 0; i < stars.length; i++) {
changeStarColor(stars[i]);
}
}
LK.setInterval(updateStarColors, 2000);
var starCount = 0;
// Initialize the offscreen threshold for destroying obstacles
var offscreenThreshold = 2732 + 1000;
function createParticleEffect(x, y, color) {
var effect = new ParticleEffect(x, y, color);
LK.on('tick', function () {
effect._update_migrated();
});
}
function createDotParticleEffect(x, y) {
var effect = new DotParticleEffect(x, y);
LK.on('tick', function () {
effect._update_migrated();
});
}
var obstacles = [];
function updateObstacles() {
var obstacleCount = 5 + starCount;
while (obstacles.length < obstacleCount) {
var obstacle = game.addChildAt(new Obstacle(), game.children.length - 1); // Ensure obstacle is in front of clouds
obstacle.x = obstacle.direction === 1 ? -obstacle.width / 2 : 2048 + obstacle.width / 2;
obstacle.y = Math.random() * (2732 - obstacle.height) + obstacle.height / 2;
obstacles.push(obstacle);
}
// No longer move clouds when a star is destroyed
}
// Removed duplicate score text initialization and addition to the screen
game.on('down', function (x, y, obj) {
if (dot) {
dot.bounceUp();
}
});
var stars = [];
var star = game.addChildAt(new Star(), 1);
star.x = 2048 / 2;
star.y = 2732 / 2 - 500;
stars.push(star);
LK.setInterval(function () {
changeStarColor(star);
}, 1000); // Initialize star with a random color from the obstacles
// Add dotted orbit for the first star
var orbitLine = game.addChild(new OrbitLine(star.x, star.y, 300));
obstacles.push(orbitLine);
function spawnInitialObstacles() {
var starX = 2048 / 2;
var starY = 2732 / 2 - 500;
var radius = 300;
var angleSpeed = 0.05;
var obstacle = new CircularObstacle(starX, starY, radius, angleSpeed);
game.addChildAt(obstacle, game.children.length - 1); // Ensure obstacle is in front of clouds
obstacles.push(obstacle);
game.setChildIndex(star, game.children.length - 1); // Ensure star is in front of clouds
// No additional obstacles for the first star
}
spawnInitialObstacles();
game.addChild(hud);
LK.on('tick', function () {
if (dot) {
dot._update_migrated();
}
for (var i = 0; i < obstacles.length; i++) {
if (obstacles[i] instanceof CircularObstacle) {
obstacles[i].updatePosition();
} else {
if (typeof obstacles[i]._move_migrated === 'function') {
obstacles[i]._move_migrated();
}
}
if (dot && dot.y < 2300 && dot.movedDistance < 0) {
obstacles[i].moveDown(-dot.movedDistance, dot.y);
}
if (dot && dot.intersects && obstacles[i] && dot.intersects(obstacles[i]) && !(obstacles[i] instanceof OrbitLine) && dot !== null && obstacles[i] !== null && typeof dot.intersects === 'function') {
if (dot.children[0].tint === obstacles[i].children[0].tint) {
createObstacleParticleEffect(obstacles[i].x, obstacles[i].y);
if (gameMode === 'endless') {
if (gameMode === 'endless') {
LK.setScore(LK.getScore() + 10);
} else if (gameMode === 'challenges') {
// Do not display points addition in challenge mode
}
}
hud.updateScore(LK.getScore());
if (gameMode === 'endless') {
var obstacleScorePopup = new ObstacleScorePopup(obstacles[i].x, obstacles[i].y);
LK.on('tick', function () {
obstacleScorePopup._update_migrated();
});
}
LK.getSound('obstacle').play();
// Update challenge progress before destroying the obstacle
if (currentChallenge) {
for (var j = 0; j < currentChallenge.length; j++) {
if (obstacles[i].children[0].tint === currentChallenge[j].color) {
currentChallenge[j].updateProgress();
if (currentChallenge[j].completed) {
currentChallenge.splice(j, 1);
if (currentChallenge.length === 0) {
startNextChallenge();
}
}
break;
}
}
}
if (obstacles[i]) {
obstacles[i].destroy();
}
obstacles.splice(i, 1);
} else {
if (!dot.destroyed) {
createDotParticleEffect(dot.x, dot.y);
LK.getSound('explosion').play();
dot.destroyed = true;
}
dot.destroy();
LK.setTimeout(function () {
LK.showGameOver();
}, 1500);
}
} else if (obstacles[i] && obstacles[i].y > offscreenThreshold) {
if (obstacles[i] && typeof obstacles[i].destroy === 'function') {
obstacles[i].destroy();
}
obstacles.splice(i, 1);
}
}
for (var j = stars.length - 1; j >= 0; j--) {
if (!dot || !stars[j]) {
continue;
}
stars[j].updateScale();
if (dot && dot.intersects && stars[j] && isValidStar(stars[j]) && dot.intersects(stars[j]) && dot.y != null && stars[j].y != null && typeof dot.intersects === 'function' && dot.children && dot.children[0] && dot.children[0].y != null && stars[j].children && stars[j].children[0]) {
destroyHand();
dot.inheritStarColor(stars[j]);
if (gameMode === 'endless') {
LK.setScore(LK.getScore() + 10 * (starCount + 1));
} else if (gameMode === 'challenges') {
// Do not display points addition in challenge mode
}
hud.updateScore(LK.getScore());
var oldStarY = stars[j].y;
createParticleEffect(stars[j].x, stars[j].y, stars[j].children[0].tint);
LK.getSound('star').play();
if (gameMode === 'endless') {
var scorePopup = new ScorePopup(stars[j].x, stars[j].y);
LK.on('tick', function () {
scorePopup._update_migrated();
});
}
stars[j].destroy();
stars.splice(j, 1);
starCount += 1;
var newStar = game.addChildAt(new Star(), 1);
game.setChildIndex(newStar, game.children.length - 1); // Ensure new star is in front of clouds
newStar.x = 2048 / 2;
var additionalYOffset = starCount > 1 ? (starCount - 1) * 200 : 0;
newStar.y = oldStarY - 2000 - additionalYOffset;
// Create new clouds if needed when a star is destroyed
while (clouds.length < 5) {
var cloud = new Cloud();
cloud.x = Math.random() * 2048;
var newY;
do {
newY = Math.random() * 2732;
} while (!isCloudPositionValid(newY, clouds, 200)); // Ensure clouds are at least 200 pixels apart
cloud.y = newY;
clouds.push(cloud);
game.addChildAt(cloud, 0); // Add clouds behind other elements
}
stars.push(newStar);
// Ensure new star also has the color change function
changeStarColor(newStar);
if (!handMoved && hand) {
var handMoveDistance = 0;
var handMoveInterval = LK.setInterval(function () {
handMoveDistance += 1;
hand._update_migrated(handMoveDistance);
if (handMoveDistance >= 1000) {
LK.clearInterval(handMoveInterval);
}
}, 10);
handMoved = true;
}
// Increase the offscreen threshold for destroying obstacles
offscreenThreshold += 300;
// Add a cumulative number of CircularObstacles at random positions around the new star
var cumulativeObstacles = 1 + starCount;
for (var k = 0; k < cumulativeObstacles; k++) {
var randomAngle = Math.random() * Math.PI * 2; // Random angle in radians
var radiusOffset = k * 100;
var circularObstacle = game.addChildAt(new CircularObstacle(newStar.x, newStar.y, 300 + radiusOffset, 0.05 * (k % 2 === 0 ? 1 : -1), randomAngle), 1);
obstacles.push(circularObstacle);
}
// Add orbit line before creating all obstacles
var orbitLine = new OrbitLine(newStar.x, newStar.y, 300 + radiusOffset);
game.addChildAt(orbitLine, 1);
obstacles.push(orbitLine);
} else if (dot.y < 2300 && dot.movedDistance < 0) {
stars[j].moveDown(-dot.movedDistance, dot.y);
}
}
for (var i = 0; i < clouds.length; i++) {
clouds[i]._update_migrated();
}
});
var dot = null;
var dotBouncing = false;
var hand;
var handMoved = false;
function createHand() {
hand = new Hand();
game.addChild(hand);
hand.x = dot.x;
hand.y = dot.y + dot.height / 2;
}
Cartoon, white star. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Cartoon. white circle. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
cartoon white dot with eyes (just black dots).. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
cartoon white ring. simple.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
cartoon white cloud.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.