/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Candy = Container.expand(function (type) { var self = Container.call(this); self.candyType = type || 1; self.gridX = 0; self.gridY = 0; self.isAnimating = false; self.isMatched = false; self.idleAnimationActive = false; self.bobOffset = Math.random() * Math.PI * 2; // Random starting phase for bobbing self.sparkleTimer = Math.random() * 120; // Random timing for sparkle effect var candyGraphics = self.attachAsset('candy' + self.candyType, { anchorX: 0.5, anchorY: 0.5 }); self.setGridPosition = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.x = GRID_START_X + gridX * CELL_SIZE + CELL_SIZE / 2; self.y = GRID_START_Y + gridY * CELL_SIZE + CELL_SIZE / 2; }; self.animateToPosition = function (targetX, targetY, callback) { self.isAnimating = true; self.stopIdleAnimation(); // Stop idle animation during move animation tween(self, { x: targetX, y: targetY }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { self.isAnimating = false; if (callback) callback(); // Restart idle animation after move completes LK.setTimeout(function () { if (!self.isMatched) { self.startIdleAnimation(); } }, 200); } }); }; self.animateFall = function (newGridY, callback) { var targetY = GRID_START_Y + newGridY * CELL_SIZE + CELL_SIZE / 2; self.gridY = newGridY; self.stopIdleAnimation(); // Stop idle animation during fall self.animateToPosition(self.x, targetY, function () { if (callback) callback(); // Restart idle animation after fall completes LK.setTimeout(function () { if (!self.isMatched) { self.startIdleAnimation(); } }, 300); }); }; self.startIdleAnimation = function () { if (self.idleAnimationActive || self.isAnimating || self.isMatched) return; self.idleAnimationActive = true; // Gentle bobbing animation function bobAnimation() { if (!self.idleAnimationActive || self.isAnimating || self.isMatched) return; tween(self, { y: self.y - 8 }, { duration: 1500 + Math.random() * 1000, easing: tween.easeInOut, onFinish: function onFinish() { if (!self.idleAnimationActive || self.isAnimating || self.isMatched) return; tween(self, { y: self.y + 8 }, { duration: 1500 + Math.random() * 1000, easing: tween.easeInOut, onFinish: function onFinish() { if (self.idleAnimationActive && !self.isAnimating && !self.isMatched) { bobAnimation(); } } }); } }); } // Start bobbing with a random delay LK.setTimeout(function () { if (self.idleAnimationActive && !self.isAnimating && !self.isMatched) { bobAnimation(); } }, Math.random() * 3000); }; self.stopIdleAnimation = function () { self.idleAnimationActive = false; tween.stop(self, { y: true }); // Stop any y-position tweens }; self.sparkle = function () { if (self.isAnimating || self.isMatched) return; // Create sparkle effect with scale and alpha animation tween(candyGraphics, { scaleX: 1.15, scaleY: 1.15, alpha: 1.2 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(candyGraphics, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 300, easing: tween.easeIn }); } }); }; self.markForRemoval = function () { self.isMatched = true; self.stopIdleAnimation(); // Stop idle animations when marked for removal tween(self, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 200, easing: tween.easeIn }); }; return self; }); var ComboText = Container.expand(function (message, x, y, color) { var self = Container.call(this); self.x = x; self.y = y; var comboTextDisplay = new Text2(message, { size: 120, fill: color || 0xFFFFFF }); comboTextDisplay.anchor.set(0.5, 0.5); self.addChild(comboTextDisplay); // Initial state self.alpha = 0; self.scaleX = 0.5; self.scaleY = 0.5; // Animate in tween(self, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { // Hold for a moment LK.setTimeout(function () { // Animate out tween(self, { alpha: 0, scaleX: 1.5, scaleY: 1.5, y: self.y - 100 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { self.destroy(); var index = comboTexts.indexOf(self); if (index > -1) { comboTexts.splice(index, 1); } } }); }, 800); } }); return self; }); var FloatingParticle = Container.expand(function (color, size) { var self = Container.call(this); var particleGraphics = self.attachAsset('particle', { anchorX: 0.5, anchorY: 0.5 }); particleGraphics.tint = color; particleGraphics.scaleX = size; particleGraphics.scaleY = size; self.speed = Math.random() * 2 + 1; self.direction = Math.random() * Math.PI * 2; self.bobOffset = Math.random() * Math.PI * 2; self.bobSpeed = Math.random() * 0.02 + 0.01; self.update = function () { self.x += Math.cos(self.direction) * self.speed; self.y += Math.sin(self.direction) * self.speed + Math.sin(LK.ticks * self.bobSpeed + self.bobOffset) * 0.5; // Wrap around screen if (self.x < -50) self.x = 2098; if (self.x > 2098) self.x = -50; if (self.y < -50) self.y = 2782; if (self.y > 2782) self.y = -50; // Gentle rotation self.rotation += 0.01; }; return self; }); var HowToPlayScreen = Container.expand(function () { var self = Container.call(this); // Background var background = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); background.x = 2048 / 2; background.y = 2732 / 2; background.scaleX = 12; background.scaleY = 16; background.alpha = 0.9; background.tint = 0x000000; self.addChild(background); // Title var titleText = new Text2('HOW TO PLAY', { size: 120, fill: 0xFF69B4 }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 400; self.addChild(titleText); // Instructions var instructions = ['1. Swap adjacent candies to create matches', '2. Match 3-6 connected candies of same type', '3. Candies can connect horizontally & vertically', '4. Scoring: 3 blocks=50, 4=150, 5=200, 6=300', '5. Create combos for bonus points!']; for (var i = 0; i < instructions.length; i++) { var instructionText = new Text2(instructions[i], { size: 55, fill: 0xFFFFFF }); instructionText.anchor.set(0.5, 0.5); instructionText.x = 2048 / 2; instructionText.y = 700 + i * 140; self.addChild(instructionText); } // Back button var backButton = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); backButton.x = 2048 / 2; backButton.y = 2200; backButton.scaleX = 1.5; backButton.scaleY = 0.6; backButton.tint = 0xEB4D4B; self.addChild(backButton); var backButtonText = new Text2('BACK', { size: 80, fill: 0xFFFFFF }); backButtonText.anchor.set(0.5, 0.5); backButtonText.x = backButton.x; backButtonText.y = backButton.y; self.addChild(backButtonText); backButton.down = function (x, y, obj) { // Button press animation tween(backButton, { scaleX: 1.3, scaleY: 0.5 }, { duration: 100, onFinish: function onFinish() { tween(backButton, { scaleX: 1.5, scaleY: 0.6 }, { duration: 100 }); } }); // Go back to main menu if (typeof showMainMenu === 'function') { showMainMenu(); } }; return self; }); var MainMenu = Container.expand(function () { var self = Container.call(this); // Create gradient background overlay var gradientOverlay = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); gradientOverlay.x = 2048 / 2; gradientOverlay.y = 2732 / 2; gradientOverlay.scaleX = 12; gradientOverlay.scaleY = 16; gradientOverlay.alpha = 0.1; gradientOverlay.tint = 0x000000; self.addChild(gradientOverlay); // Add menu decorations var decorations = new MenuDecoration(); self.addChild(decorations); // Create floating background particles var particles = []; for (var i = 0; i < 20; i++) { var colors = [0xFF69B4, 0x4ECDC4, 0xF9CA24, 0xEB4D4B, 0x45B7D1, 0xF0932B]; var color = colors[Math.floor(Math.random() * colors.length)]; var size = Math.random() * 0.8 + 0.3; var particle = new FloatingParticle(color, size); particle.x = Math.random() * 2048; particle.y = Math.random() * 2732; particle.alpha = 0.6; particles.push(particle); self.addChild(particle); } // Game title with enhanced styling var titleText = new Text2('🍭 CANDY MATCH 🍭', { size: 200, fill: 0xFF69B4 }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 500; self.addChild(titleText); // Add title shadow effect var titleShadow = new Text2('🍭 CANDY MATCH 🍭', { size: 200, fill: 0x000000 }); titleShadow.anchor.set(0.5, 0.5); titleShadow.x = 2048 / 2 + 5; titleShadow.y = 505; titleShadow.alpha = 0.3; self.addChildAt(titleShadow, self.getChildIndex(titleText)); // Subtitle var subtitleText = new Text2('✨ Match candies and create sweet combos! ✨', { size: 60, fill: 0xFFFFFF }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 2048 / 2; subtitleText.y = 650; subtitleText.alpha = 0.8; self.addChild(subtitleText); // Enhanced start button with glow effect var startButtonGlow = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); startButtonGlow.x = 2048 / 2; startButtonGlow.y = 1200; startButtonGlow.scaleX = 3.4; startButtonGlow.scaleY = 1.4; startButtonGlow.tint = 0x4ECDC4; startButtonGlow.alpha = 0.3; self.addChild(startButtonGlow); var startButton = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); startButton.x = 2048 / 2; startButton.y = 1200; startButton.scaleX = 3.2; startButton.scaleY = 1.3; startButton.tint = 0x4ECDC4; self.addChild(startButton); var startButtonText = new Text2('🚀 START GAME', { size: 90, fill: 0xFFFFFF }); startButtonText.anchor.set(0.5, 0.5); startButtonText.x = startButton.x; startButtonText.y = startButton.y; self.addChild(startButtonText); // Enhanced how to play button with glow effect var howToPlayButtonGlow = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); howToPlayButtonGlow.x = 2048 / 2; howToPlayButtonGlow.y = 1500; howToPlayButtonGlow.scaleX = 3.2; howToPlayButtonGlow.scaleY = 1.3; howToPlayButtonGlow.tint = 0xF9CA24; howToPlayButtonGlow.alpha = 0.3; self.addChild(howToPlayButtonGlow); var howToPlayButton = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); howToPlayButton.x = 2048 / 2; howToPlayButton.y = 1500; howToPlayButton.scaleX = 3.0; howToPlayButton.scaleY = 1.2; howToPlayButton.tint = 0xF9CA24; self.addChild(howToPlayButton); var howToPlayButtonText = new Text2('❓ HOW TO PLAY', { size: 90, fill: 0xFFFFFF }); howToPlayButtonText.anchor.set(0.5, 0.5); howToPlayButtonText.x = howToPlayButton.x; howToPlayButtonText.y = howToPlayButton.y; self.addChild(howToPlayButtonText); // Sound control buttons var soundButtonGlow = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); soundButtonGlow.x = 2048 / 2; soundButtonGlow.y = 1800; soundButtonGlow.scaleX = 3.0; soundButtonGlow.scaleY = 1.2; soundButtonGlow.tint = 0xEB4D4B; soundButtonGlow.alpha = 0.3; self.addChild(soundButtonGlow); var soundButton = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); soundButton.x = 2048 / 2; soundButton.y = 1800; soundButton.scaleX = 2.8; soundButton.scaleY = 1.1; soundButton.tint = 0xEB4D4B; self.addChild(soundButton); // Get current sound state from storage var soundEnabled = storage.soundEnabled; if (soundEnabled === null || soundEnabled === undefined) { soundEnabled = true; storage.soundEnabled = soundEnabled; } var soundButtonText = new Text2(soundEnabled ? '🔊 SOUND ON' : '🔇 SOUND OFF', { size: 90, fill: 0xFFFFFF }); soundButtonText.anchor.set(0.5, 0.5); soundButtonText.x = soundButton.x; soundButtonText.y = soundButton.y; self.addChild(soundButtonText); // Apply current sound settings if (!soundEnabled) { LK.stopMusic(); } // Animate title with rainbow effect self.animateTitle = function () { // Scale animation tween(titleText, { scaleX: 1.15, scaleY: 1.15 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { tween(titleText, { scaleX: 1, scaleY: 1 }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { self.animateTitle(); } }); } }); // Color cycle animation var colors = [0xFF69B4, 0x4ECDC4, 0xF9CA24, 0xEB4D4B, 0x45B7D1]; var currentColorIndex = 0; function cycleColors() { currentColorIndex = (currentColorIndex + 1) % colors.length; tween(titleText, { tint: colors[currentColorIndex] }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { LK.setTimeout(cycleColors, 500); } }); } cycleColors(); }; // Animate subtitle function animateSubtitle() { tween(subtitleText, { alpha: 1, y: subtitleText.y - 10 }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { tween(subtitleText, { alpha: 0.6, y: 650 }, { duration: 1500, easing: tween.easeInOut, onFinish: animateSubtitle }); } }); } animateSubtitle(); // Animate button glows function animateGlows() { tween(startButtonGlow, { alpha: 0.6, scaleX: 3.6, scaleY: 1.5 }, { duration: 1200, easing: tween.easeInOut, onFinish: function onFinish() { tween(startButtonGlow, { alpha: 0.3, scaleX: 3.4, scaleY: 1.4 }, { duration: 1200, easing: tween.easeInOut }); } }); tween(howToPlayButtonGlow, { alpha: 0.6, scaleX: 3.4, scaleY: 1.4 }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { tween(howToPlayButtonGlow, { alpha: 0.3, scaleX: 3.2, scaleY: 1.3 }, { duration: 1500, easing: tween.easeInOut, onFinish: animateGlows }); } }); } animateGlows(); // Update particles self.update = function () { for (var i = 0; i < particles.length; i++) { particles[i].update(); } }; // Enhanced button click handlers startButton.down = function (x, y, obj) { // Button press animation with enhanced effects tween(startButton, { scaleX: 2.8, scaleY: 1.0 }, { duration: 80, onFinish: function onFinish() { tween(startButton, { scaleX: 3.4, scaleY: 1.4 }, { duration: 80, onFinish: function onFinish() { tween(startButton, { scaleX: 3.2, scaleY: 1.3 }, { duration: 80 }); } }); } }); // Animate button glow on press tween(startButtonGlow, { alpha: 0.8, scaleX: 3.8, scaleY: 1.7 }, { duration: 150, onFinish: function onFinish() { tween(startButtonGlow, { alpha: 0.3, scaleX: 3.4, scaleY: 1.4 }, { duration: 200 }); } }); // Start the game startGame(); }; howToPlayButton.down = function (x, y, obj) { // Button press animation with enhanced effects tween(howToPlayButton, { scaleX: 2.6, scaleY: 0.9 }, { duration: 80, onFinish: function onFinish() { tween(howToPlayButton, { scaleX: 3.2, scaleY: 1.3 }, { duration: 80, onFinish: function onFinish() { tween(howToPlayButton, { scaleX: 3.0, scaleY: 1.2 }, { duration: 80 }); } }); } }); // Animate button glow on press tween(howToPlayButtonGlow, { alpha: 0.8, scaleX: 3.6, scaleY: 1.6 }, { duration: 150, onFinish: function onFinish() { tween(howToPlayButtonGlow, { alpha: 0.3, scaleX: 3.2, scaleY: 1.3 }, { duration: 200 }); } }); // Show how to play if (typeof showHowToPlay === 'function') { showHowToPlay(); } }; soundButton.down = function (x, y, obj) { // Button press animation with enhanced effects tween(soundButton, { scaleX: 2.4, scaleY: 0.9 }, { duration: 80, onFinish: function onFinish() { tween(soundButton, { scaleX: 3.0, scaleY: 1.2 }, { duration: 80, onFinish: function onFinish() { tween(soundButton, { scaleX: 2.8, scaleY: 1.1 }, { duration: 80 }); } }); } }); // Animate button glow on press tween(soundButtonGlow, { alpha: 0.8, scaleX: 3.4, scaleY: 1.5 }, { duration: 150, onFinish: function onFinish() { tween(soundButtonGlow, { alpha: 0.3, scaleX: 3.0, scaleY: 1.2 }, { duration: 200 }); } }); // Toggle sound soundEnabled = !soundEnabled; storage.soundEnabled = soundEnabled; soundButtonText.setText(soundEnabled ? '🔊 SOUND ON' : '🔇 SOUND OFF'); // Apply sound settings if (soundEnabled) { LK.playMusic('rahat'); } else { LK.stopMusic(); } }; return self; }); var MenuDecoration = Container.expand(function () { var self = Container.call(this); // Create candy decorations around the screen var decorationCount = 12; var _loop = function _loop() { candyType = Math.floor(Math.random() * 6) + 1; decoration = LK.getAsset('candy' + candyType, { anchorX: 0.5, anchorY: 0.5 }); angle = i / decorationCount * Math.PI * 2; radius = 800 + Math.random() * 200; decoration.x = 2048 / 2 + Math.cos(angle) * radius; decoration.y = 2732 / 2 + Math.sin(angle) * radius; decoration.alpha = 0.3; decoration.scaleX = 0.8 + Math.random() * 0.4; decoration.scaleY = decoration.scaleX; self.addChild(decoration); // Animate decorations animDuration = 3000 + Math.random() * 2000; targetScale = decoration.scaleX + 0.2; function animateDecoration(dec) { tween(dec, { rotation: dec.rotation + Math.PI * 2, scaleX: targetScale, scaleY: targetScale }, { duration: animDuration, easing: tween.easeInOut, onFinish: function onFinish() { targetScale = 0.8 + Math.random() * 0.4; animDuration = 3000 + Math.random() * 2000; animateDecoration(dec); } }); } animateDecoration(decoration); }, candyType, decoration, angle, radius, animDuration, targetScale; for (var i = 0; i < decorationCount; i++) { _loop(); } return self; }); var Particle = Container.expand(function (color, startX, startY) { var self = Container.call(this); self.x = startX; self.y = startY; self.velocityX = (Math.random() - 0.5) * 400; self.velocityY = (Math.random() - 0.5) * 400; self.gravity = 300; self.life = 1.0; self.maxLife = 1.0; var particleGraphics = self.attachAsset('particle', { anchorX: 0.5, anchorY: 0.5 }); particleGraphics.tint = color; particleGraphics.scaleX = Math.random() * 0.8 + 0.4; particleGraphics.scaleY = particleGraphics.scaleX; self.update = function () { self.x += self.velocityX * (1 / 60); self.y += self.velocityY * (1 / 60); self.velocityY += self.gravity * (1 / 60); self.life -= 1 / 60 * 2; var alpha = self.life / self.maxLife; self.alpha = alpha; self.scaleX = alpha * particleGraphics.scaleX; self.scaleY = alpha * particleGraphics.scaleY; if (self.life <= 0) { self.destroy(); var index = particles.indexOf(self); if (index > -1) { particles.splice(index, 1); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xff69b4 }); /**** * Game Code ****/ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } var GRID_SIZE = 8; var CELL_SIZE = 200; var GRID_START_X = (2048 - GRID_SIZE * CELL_SIZE) / 2; var GRID_START_Y = 400; var gameGrid = []; var candyTypes = [1, 2, 3, 4, 5, 6]; var selectedCandy = null; var isProcessing = false; var movesLeft = 999999; var score = 0; var animatingCandies = 0; var particles = []; var comboTexts = []; var currentCombo = 0; // Power-up variables var rowCleanerButton = null; var colorChangerButton = null; var clearAllButton = null; var hintButton = null; var rowCleanerCost = 2000; var colorChangerCost = 500; var clearAllCost = 7000; var hintCost = 4000; var selectedPowerUp = null; // 'rowCleaner', 'colorChanger', or 'clearAll' var hintArrows = []; // Array to store hint arrow elements // Game state variables var gameState = 'menu'; // 'menu', 'game', 'howtoplay' var mainMenu = null; var howToPlayScreen = null; var gameElements = []; // Sound control variables var soundEnabled = true; // Initialize grid array for (var x = 0; x < GRID_SIZE; x++) { gameGrid[x] = []; for (var y = 0; y < GRID_SIZE; y++) { gameGrid[x][y] = null; } } // Menu control functions function startGame() { gameState = 'game'; hideAllScreens(); initializeGameElements(); } function showMainMenu() { gameState = 'menu'; // Clear game grid and destroy candies for (var x = 0; x < GRID_SIZE; x++) { for (var y = 0; y < GRID_SIZE; y++) { if (gameGrid[x][y]) { gameGrid[x][y].destroy(); gameGrid[x][y] = null; } } } // Clear particles for (var i = particles.length - 1; i >= 0; i--) { particles[i].destroy(); } particles = []; // Clear combo texts for (var i = comboTexts.length - 1; i >= 0; i--) { comboTexts[i].destroy(); } comboTexts = []; // Reset game state selectedCandy = null; isProcessing = false; animatingCandies = 0; currentCombo = 0; hideAllScreens(); if (!mainMenu) { mainMenu = new MainMenu(); game.addChild(mainMenu); } else { // Recursively re-enable all menu interactions var _enableMenuInteractions = function enableMenuInteractions(container) { container.interactive = true; if (container.children) { for (var i = 0; i < container.children.length; i++) { var child = container.children[i]; child.interactive = true; if (child.children && child.children.length > 0) { _enableMenuInteractions(child); } } } }; mainMenu.alpha = 1; mainMenu.visible = true; mainMenu.interactive = true; _enableMenuInteractions(mainMenu); } mainMenu.animateTitle(); } function showHowToPlay() { gameState = 'howtoplay'; hideAllScreens(); // Completely hide main menu to prevent interactions if (mainMenu) { // Recursively disable all child interactions var _disableMenuInteractions = function disableMenuInteractions(container) { container.interactive = false; if (container.children) { for (var i = 0; i < container.children.length; i++) { var child = container.children[i]; child.interactive = false; if (child.down) { child.down = null; } if (child.children && child.children.length > 0) { _disableMenuInteractions(child); } } } }; mainMenu.alpha = 0; mainMenu.visible = false; mainMenu.interactive = false; _disableMenuInteractions(mainMenu); } if (!howToPlayScreen) { howToPlayScreen = new HowToPlayScreen(); game.addChild(howToPlayScreen); // Ensure how-to-play screen is on top game.setChildIndex(howToPlayScreen, game.children.length - 1); } else { howToPlayScreen.alpha = 1; howToPlayScreen.visible = true; // Bring to front when showing game.setChildIndex(howToPlayScreen, game.children.length - 1); } } function hideAllScreens() { if (mainMenu) { mainMenu.alpha = 0; mainMenu.visible = false; } if (howToPlayScreen) { howToPlayScreen.alpha = 0; howToPlayScreen.visible = false; } // Hide game elements (except persistent ones like scoreText and backgroundImage) for (var i = 0; i < gameElements.length; i++) { if (gameElements[i] !== scoreText && gameElements[i] !== backgroundImage) { gameElements[i].alpha = 0; } } } function initializeGameElements() { // Clear existing game elements first for (var i = gameElements.length - 1; i >= 0; i--) { if (gameElements[i] !== scoreText && gameElements[i] !== backgroundImage) { gameElements[i].destroy(); gameElements.splice(i, 1); } } // Show persistent game elements for (var i = 0; i < gameElements.length; i++) { gameElements[i].alpha = 1; } // Grid background removed - candies display directly on background image // Add 7000 points to initial score score += 7000; scoreText.setText('Score: ' + score); // Create power-up buttons createPowerUpButtons(); // Clear hint arrows clearHintArrows(); // Reset game state score = 0; currentCombo = 0; selectedCandy = null; isProcessing = false; scoreText.setText('Score: 0'); // Clear existing candies and initialize fresh grid for (var x = 0; x < GRID_SIZE; x++) { for (var y = 0; y < GRID_SIZE; y++) { if (gameGrid[x][y]) { gameGrid[x][y].destroy(); gameGrid[x][y] = null; } } } // Initialize the game grid initializeGrid(); } // UI Elements var scoreText = new Text2('Score: 0', { size: 80, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); gameElements.push(scoreText); // Create background image var backgroundImage = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5 }); backgroundImage.x = 2048 / 2; backgroundImage.y = 2732 / 2; backgroundImage.scaleX = 2048 / backgroundImage.width; backgroundImage.scaleY = 2732 / backgroundImage.height; game.addChild(backgroundImage); gameElements.push(backgroundImage); // Grid cells will be created when game starts function getRandomCandyType() { return candyTypes[Math.floor(Math.random() * candyTypes.length)]; } function createCandy(x, y, type) { if (!type) type = getRandomCandyType(); var candy = new Candy(type); candy.setGridPosition(x, y); gameGrid[x][y] = candy; game.addChild(candy); // Start idle animations after a short delay to let positioning settle LK.setTimeout(function () { if (candy && !candy.isMatched) { candy.startIdleAnimation(); } }, 500); return candy; } function initializeGrid() { for (var x = 0; x < GRID_SIZE; x++) { for (var y = 0; y < GRID_SIZE; y++) { var type; var attempts = 0; do { type = getRandomCandyType(); attempts++; } while (attempts < 10 && wouldCreateMatch(x, y, type)); createCandy(x, y, type); } } } function wouldCreateMatch(x, y, type) { var horizontalCount = 1; var verticalCount = 1; // Check horizontal for (var i = x - 1; i >= 0 && gameGrid[i][y] && gameGrid[i][y].candyType === type; i--) { horizontalCount++; } for (var i = x + 1; i < GRID_SIZE && gameGrid[i][y] && gameGrid[i][y].candyType === type; i++) { horizontalCount++; } // Check vertical for (var i = y - 1; i >= 0 && gameGrid[x][i] && gameGrid[x][i].candyType === type; i--) { verticalCount++; } for (var i = y + 1; i < GRID_SIZE && gameGrid[x][i] && gameGrid[x][i].candyType === type; i++) { verticalCount++; } return horizontalCount >= 3 || verticalCount >= 3; } function getCandyAt(worldX, worldY) { var gridX = Math.floor((worldX - GRID_START_X) / CELL_SIZE); var gridY = Math.floor((worldY - GRID_START_Y) / CELL_SIZE); if (gridX >= 0 && gridX < GRID_SIZE && gridY >= 0 && gridY < GRID_SIZE) { return gameGrid[gridX][gridY]; } return null; } function areAdjacent(candy1, candy2) { var dx = Math.abs(candy1.gridX - candy2.gridX); var dy = Math.abs(candy1.gridY - candy2.gridY); return dx === 1 && dy === 0 || dx === 0 && dy === 1; } function swapCandies(candy1, candy2) { var tempX = candy1.gridX; var tempY = candy1.gridY; var tempPosX = candy1.x; var tempPosY = candy1.y; gameGrid[candy1.gridX][candy1.gridY] = candy2; gameGrid[candy2.gridX][candy2.gridY] = candy1; candy1.gridX = candy2.gridX; candy1.gridY = candy2.gridY; candy2.gridX = tempX; candy2.gridY = tempY; animatingCandies += 2; // Play boing sound when candies are swapped LK.getSound('boing').play(); candy1.animateToPosition(candy2.x, candy2.y, function () { animatingCandies--; }); candy2.animateToPosition(tempPosX, tempPosY, function () { animatingCandies--; }); } function findMatches() { var allMatches = []; var visited = []; // Initialize visited array for (var x = 0; x < GRID_SIZE; x++) { visited[x] = []; for (var y = 0; y < GRID_SIZE; y++) { visited[x][y] = false; } } // Flood fill function to find all connected candies of same type (max 6 blocks) function floodFill(startX, startY, candyType, connectedGroup) { // Check bounds and if already visited if (startX < 0 || startX >= GRID_SIZE || startY < 0 || startY >= GRID_SIZE) { return; } if (visited[startX][startY]) { return; } var candy = gameGrid[startX][startY]; if (!candy || candy.candyType !== candyType) { return; } // Limit group size to maximum 6 blocks if (connectedGroup.length >= 6) { return; } // Mark as visited and add to group visited[startX][startY] = true; connectedGroup.push(candy); // Check all 4 adjacent directions (up, down, left, right) only if we haven't reached the limit if (connectedGroup.length < 6) { floodFill(startX - 1, startY, candyType, connectedGroup); // left floodFill(startX + 1, startY, candyType, connectedGroup); // right floodFill(startX, startY - 1, candyType, connectedGroup); // up floodFill(startX, startY + 1, candyType, connectedGroup); // down } } // Check each cell for connected groups for (var x = 0; x < GRID_SIZE; x++) { for (var y = 0; y < GRID_SIZE; y++) { if (!visited[x][y] && gameGrid[x][y]) { var connectedGroup = []; var candyType = gameGrid[x][y].candyType; // Find all connected candies of the same type floodFill(x, y, candyType, connectedGroup); // If we found 3 or more connected candies, add this group to allMatches if (connectedGroup.length >= 3) { allMatches.push(connectedGroup); } } } } return allMatches; } function removeMatches(matchGroups) { if (matchGroups.length === 0) return; LK.getSound('match').play(); // Flatten all matches for candy removal and particle effects var allMatches = []; for (var g = 0; g < matchGroups.length; g++) { for (var c = 0; c < matchGroups[g].length; c++) { allMatches.push(matchGroups[g][c]); } } for (var i = 0; i < allMatches.length; i++) { var candy = allMatches[i]; // Create particle explosion for each candy var candyColors = [0xff6b6b, 0x4ecdc4, 0x45b7d1, 0xf9ca24, 0xf0932b, 0xeb4d4b]; var particleColor = candyColors[candy.candyType - 1] || 0xffffff; // Create 8-12 particles per candy var particleCount = Math.floor(Math.random() * 5) + 8; for (var p = 0; p < particleCount; p++) { var particle = new Particle(particleColor, candy.x, candy.y); particles.push(particle); game.addChild(particle); } candy.markForRemoval(); gameGrid[candy.gridX][candy.gridY] = null; } // Update score based on each group's size with new scoring system var oldScore = score; var largestGroupSize = 0; for (var g = 0; g < matchGroups.length; g++) { var groupSize = Math.min(matchGroups[g].length, 6); // Cap at 6 blocks maximum if (groupSize > largestGroupSize) { largestGroupSize = groupSize; } if (groupSize === 3) { score += 50; } else if (groupSize === 4) { score += 150; } else if (groupSize === 5) { score += 200; } else if (groupSize >= 6) { score += 300; } } // Check for score milestones and celebrate var milestones = [1000, 5000, 10000, 25000, 50000]; for (var m = 0; m < milestones.length; m++) { if (oldScore < milestones[m] && score >= milestones[m]) { // Milestone reached! Create celebration effect var milestoneText = new Text2('MILESTONE!\n' + milestones[m] + ' POINTS!', { size: 80, fill: 0xFF69B4 }); milestoneText.anchor.set(0.5, 0.5); milestoneText.x = 2048 / 2; milestoneText.y = 400; milestoneText.alpha = 0; milestoneText.scaleX = 0.5; milestoneText.scaleY = 0.5; game.addChild(milestoneText); // Animate milestone text tween(milestoneText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { LK.setTimeout(function () { tween(milestoneText, { alpha: 0, scaleX: 1.5, scaleY: 1.5, y: milestoneText.y - 100 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { milestoneText.destroy(); } }); }, 1500); } }); // Screen flash for milestone LK.effects.flashScreen(0xFF69B4, 800); break; } } // Create floating score text for each match group var scoreIncrease = score - oldScore; var floatingScoreText = new Text2('+' + scoreIncrease, { size: 100, fill: 0xF9CA24 }); floatingScoreText.anchor.set(0.5, 0.5); // Position above the grid floatingScoreText.x = 2048 / 2; floatingScoreText.y = GRID_START_Y - 100; floatingScoreText.alpha = 0; // Set initial rotation to be horizontal floatingScoreText.rotation = 0; game.addChild(floatingScoreText); // Animate floating score - first appear, then move towards score display tween(floatingScoreText, { alpha: 1, scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { // Convert score text position to game coordinates var scoreWorldPos = game.toLocal(LK.gui.top.toGlobal({ x: scoreText.x, y: scoreText.y })); tween(floatingScoreText, { alpha: 0, x: scoreWorldPos.x, y: scoreWorldPos.y, scaleX: 0.8, scaleY: 0.8 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { floatingScoreText.destroy(); } }); } }); // Animate main score counter with pulsing effect tween(scoreText, { scaleX: 1.3, scaleY: 1.3, tint: 0xF9CA24 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(scoreText, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 300, easing: tween.easeOut }); } }); // Animate score increase with smooth counting var tempScore = oldScore; var scoreAnimationTimer = LK.setInterval(function () { tempScore += scoreIncrease / 30; // 30 steps over 500ms if (tempScore >= score) { tempScore = score; LK.clearInterval(scoreAnimationTimer); } scoreText.setText('Score: ' + Math.floor(tempScore)); }, 16); // ~60fps // Increment combo counter currentCombo++; // Play celebration sound for large matches if (largestGroupSize >= 5) { // Celebration sound removed } // Show combo text based on largest match size and combo count var comboMessage = ""; var comboColor = 0xFFFFFF; if (largestGroupSize >= 5) { comboMessage = "Fantastic!"; comboColor = 0xFF6B6B; // Screen shake for 5+ matches var shakeIntensity = 15; var originalX = game.x; var originalY = game.y; tween(game, { x: originalX + shakeIntensity, y: originalY + shakeIntensity * 0.5 }, { duration: 50, onFinish: function onFinish() { tween(game, { x: originalX - shakeIntensity, y: originalY - shakeIntensity * 0.5 }, { duration: 50, onFinish: function onFinish() { tween(game, { x: originalX + shakeIntensity * 0.5, y: originalY + shakeIntensity }, { duration: 50, onFinish: function onFinish() { tween(game, { x: originalX, y: originalY }, { duration: 50 }); } }); } }); } }); } else if (largestGroupSize >= 4) { comboMessage = "Awesome!"; comboColor = 0x4ECDC4; // Screen shake for 4+ matches var shakeIntensity = 10; var originalX = game.x; var originalY = game.y; tween(game, { x: originalX + shakeIntensity, y: originalY }, { duration: 75, onFinish: function onFinish() { tween(game, { x: originalX - shakeIntensity, y: originalY }, { duration: 75, onFinish: function onFinish() { tween(game, { x: originalX, y: originalY }, { duration: 75 }); } }); } }); } else if (currentCombo >= 3) { comboMessage = "Great Combo!"; comboColor = 0xF9CA24; // Light screen shake for combo var shakeIntensity = 5; var originalX = game.x; var originalY = game.y; tween(game, { x: originalX + shakeIntensity }, { duration: 100, onFinish: function onFinish() { tween(game, { x: originalX - shakeIntensity }, { duration: 100, onFinish: function onFinish() { tween(game, { x: originalX }, { duration: 100 }); } }); } }); } else if (currentCombo >= 2) { comboMessage = "Great!"; comboColor = 0x45B7D1; } if (comboMessage !== "") { var comboX = 2048 / 2; var comboY = GRID_START_Y + GRID_SIZE * CELL_SIZE / 2; var comboText = new ComboText(comboMessage, comboX, comboY, comboColor); comboTexts.push(comboText); game.addChild(comboText); } // Remove candies after animation LK.setTimeout(function () { for (var i = 0; i < allMatches.length; i++) { allMatches[i].destroy(); } applyGravity(); }, 250); } function applyGravity() { var needsGravity = false; // Apply gravity physics - make candies fall to fill empty spaces for (var x = 0; x < GRID_SIZE; x++) { // Collect all candies in this column that are not null var candiesInColumn = []; for (var y = 0; y < GRID_SIZE; y++) { if (gameGrid[x][y] !== null) { candiesInColumn.push({ candy: gameGrid[x][y], originalY: y }); } gameGrid[x][y] = null; // Clear the column } // Place candies back starting from bottom var newY = GRID_SIZE - 1; for (var i = candiesInColumn.length - 1; i >= 0; i--) { var candyData = candiesInColumn[i]; var candy = candyData.candy; var originalY = candyData.originalY; gameGrid[x][newY] = candy; // Immediately update grid position to prevent overlaps candy.gridX = x; candy.gridY = newY; // Check if candy needs to fall if (newY !== originalY) { var targetY = GRID_START_Y + newY * CELL_SIZE + CELL_SIZE / 2; candy.isAnimating = true; animatingCandies++; tween(candy, { y: targetY }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { candy.isAnimating = false; animatingCandies--; } }); needsGravity = true; } else { // Ensure position is correct even if not animating candy.x = GRID_START_X + x * CELL_SIZE + CELL_SIZE / 2; candy.y = GRID_START_Y + newY * CELL_SIZE + CELL_SIZE / 2; } newY--; } // Fill remaining empty spaces at top with new candies for (var y = 0; y < GRID_SIZE; y++) { if (gameGrid[x][y] === null) { var newCandy = createCandy(x, y, getRandomCandyType()); newCandy.y = GRID_START_Y - CELL_SIZE + CELL_SIZE / 2; newCandy.isAnimating = true; animatingCandies++; var targetY = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2; tween(newCandy, { y: targetY }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { newCandy.isAnimating = false; animatingCandies--; } }); needsGravity = true; } } } if (needsGravity) { LK.getSound('cascade').play(); LK.setTimeout(function () { checkForNewMatches(); }, 400); } } function checkForNewMatches() { if (animatingCandies > 0) { LK.setTimeout(checkForNewMatches, 100); return; } var matchGroups = findMatches(); if (matchGroups.length > 0) { removeMatches(matchGroups); } else { isProcessing = false; currentCombo = 0; // Reset combo counter when no more matches } } function findBestMove() { var bestMove = null; var bestScore = 0; // Check all possible moves for (var x1 = 0; x1 < GRID_SIZE; x1++) { for (var y1 = 0; y1 < GRID_SIZE; y1++) { var candy1 = gameGrid[x1][y1]; if (!candy1) continue; // Check adjacent positions var adjacentPositions = [{ x: x1 - 1, y: y1 }, // left { x: x1 + 1, y: y1 }, // right { x: x1, y: y1 - 1 }, // up { x: x1, y: y1 + 1 } // down ]; for (var i = 0; i < adjacentPositions.length; i++) { var pos = adjacentPositions[i]; if (pos.x < 0 || pos.x >= GRID_SIZE || pos.y < 0 || pos.y >= GRID_SIZE) continue; var candy2 = gameGrid[pos.x][pos.y]; if (!candy2) continue; // Temporarily swap to check for matches var tempX1 = candy1.gridX, tempY1 = candy1.gridY; var tempX2 = candy2.gridX, tempY2 = candy2.gridY; gameGrid[tempX1][tempY1] = candy2; gameGrid[tempX2][tempY2] = candy1; candy1.gridX = tempX2; candy1.gridY = tempY2; candy2.gridX = tempX1; candy2.gridY = tempY1; var matchGroups = findMatches(); var moveScore = 0; for (var g = 0; g < matchGroups.length; g++) { var groupSize = Math.min(matchGroups[g].length, 6); if (groupSize === 3) moveScore += 50;else if (groupSize === 4) moveScore += 150;else if (groupSize === 5) moveScore += 200;else if (groupSize >= 6) moveScore += 300; } // Revert the swap gameGrid[tempX1][tempY1] = candy1; gameGrid[tempX2][tempY2] = candy2; candy1.gridX = tempX1; candy1.gridY = tempY1; candy2.gridX = tempX2; candy2.gridY = tempY2; if (moveScore > bestScore) { bestScore = moveScore; bestMove = { candy1: candy1, candy2: candy2, score: moveScore }; } } } } return bestMove; } function showHintArrow(candy1, candy2) { // Clear existing hint arrows clearHintArrows(); // Create arrow from candy1 to candy2 var arrow = new Container(); var arrowBody = LK.getAsset('gridCell', { anchorX: 0, anchorY: 0.5 }); arrowBody.scaleX = 0.8; arrowBody.scaleY = 0.1; arrowBody.tint = 0xFFFF00; arrow.addChild(arrowBody); var arrowHead = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); arrowHead.scaleX = 0.15; arrowHead.scaleY = 0.15; arrowHead.tint = 0xFFFF00; arrowHead.rotation = Math.PI / 4; // 45 degrees arrow.addChild(arrowHead); // Position arrow between the two candies var midX = (candy1.x + candy2.x) / 2; var midY = (candy1.y + candy2.y) / 2; arrow.x = midX; arrow.y = midY; // Calculate angle from candy1 to candy2 var dx = candy2.x - candy1.x; var dy = candy2.y - candy1.y; var angle = Math.atan2(dy, dx); arrow.rotation = angle; // Position arrow body and head arrowBody.x = -80; arrowHead.x = 80; // Add pulsing animation arrow.alpha = 0; game.addChild(arrow); hintArrows.push(arrow); tween(arrow, { alpha: 1 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Pulse animation function pulseArrow() { tween(arrow, { scaleX: 1.3, scaleY: 1.3 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(arrow, { scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { if (hintArrows.indexOf(arrow) !== -1) { pulseArrow(); } } }); } }); } pulseArrow(); } }); // Auto-hide hint after 5 seconds LK.setTimeout(function () { clearHintArrows(); }, 5000); } function clearHintArrows() { for (var i = hintArrows.length - 1; i >= 0; i--) { hintArrows[i].destroy(); } hintArrows = []; } function checkGameState() { // Endless game - no win/lose conditions } function processMove(candy1, candy2) { if (isProcessing || !candy1 || !candy2 || candy1 === candy2) return false; if (!areAdjacent(candy1, candy2)) return false; isProcessing = true; // Endless game - no move limit // Temporarily swap to check for matches var tempX1 = candy1.gridX, tempY1 = candy1.gridY; var tempX2 = candy2.gridX, tempY2 = candy2.gridY; gameGrid[tempX1][tempY1] = candy2; gameGrid[tempX2][tempY2] = candy1; candy1.gridX = tempX2; candy1.gridY = tempY2; candy2.gridX = tempX1; candy2.gridY = tempY1; var matchGroups = findMatches(); if (matchGroups.length > 0) { // Valid move - perform the swap animation swapCandies(candy2, candy1); // Swap back positions for animation LK.setTimeout(function () { removeMatches(matchGroups); }, 350); } else { // Invalid move - revert gameGrid[tempX1][tempY1] = candy1; gameGrid[tempX2][tempY2] = candy2; candy1.gridX = tempX1; candy1.gridY = tempY1; candy2.gridX = tempX2; candy2.gridY = tempY2; // Animate back to original positions swapCandies(candy1, candy2); LK.setTimeout(function () { isProcessing = false; }, 350); // Endless game - no move limit } return true; } game.down = function (x, y, obj) { if (gameState !== 'game') return; if (isProcessing) return; // Check if a power-up is selected if (selectedPowerUp) { var candy = getCandyAt(x, y); if (!candy) { selectedPowerUp = null; return; } if (selectedPowerUp === 'rowCleaner' && score >= rowCleanerCost) { // Clear entire row score -= rowCleanerCost; scoreText.setText('Score: ' + score); var row = candy.gridY; var clearedCandies = []; for (var x = 0; x < GRID_SIZE; x++) { if (gameGrid[x][row]) { clearedCandies.push(gameGrid[x][row]); gameGrid[x][row] = null; } } // Animate cleared candies for (var i = 0; i < clearedCandies.length; i++) { clearedCandies[i].markForRemoval(); } LK.setTimeout(function () { for (var i = 0; i < clearedCandies.length; i++) { clearedCandies[i].destroy(); } applyGravity(); }, 250); selectedPowerUp = null; return; } if (selectedPowerUp === 'colorChanger' && score >= colorChangerCost) { // Change candy color to random type score -= colorChangerCost; scoreText.setText('Score: ' + score); var newType = getRandomCandyType(); var oldCandy = candy; var x = oldCandy.gridX; var y = oldCandy.gridY; // Remove old candy oldCandy.destroy(); // Create new candy with different type var newCandy = createCandy(x, y, newType); // Flash effect tween(newCandy, { alpha: 0.3 }, { duration: 100, onFinish: function onFinish() { tween(newCandy, { alpha: 1 }, { duration: 100 }); } }); selectedPowerUp = null; return; } if (selectedPowerUp === 'clearAll' && score >= clearAllCost) { // Clear all candies from the grid score -= clearAllCost; score += 5000; // Bonus points scoreText.setText('Score: ' + score); var allCandies = []; for (var x = 0; x < GRID_SIZE; x++) { for (var y = 0; y < GRID_SIZE; y++) { if (gameGrid[x][y]) { allCandies.push(gameGrid[x][y]); gameGrid[x][y] = null; } } } // Animate all candies removal for (var i = 0; i < allCandies.length; i++) { allCandies[i].markForRemoval(); } // Create spectacular particle effects for (var i = 0; i < allCandies.length; i++) { var candy = allCandies[i]; var candyColors = [0xff6b6b, 0x4ecdc4, 0x45b7d1, 0xf9ca24, 0xf0932b, 0xeb4d4b]; var particleColor = candyColors[candy.candyType - 1] || 0xffffff; // Create more particles for spectacular effect var particleCount = Math.floor(Math.random() * 8) + 12; for (var p = 0; p < particleCount; p++) { var particle = new Particle(particleColor, candy.x, candy.y); particles.push(particle); game.addChild(particle); } } // Screen flash effect LK.effects.flashScreen(0xFFFFFF, 500); // Remove candies and refill grid LK.setTimeout(function () { for (var i = 0; i < allCandies.length; i++) { allCandies[i].destroy(); } applyGravity(); }, 250); selectedPowerUp = null; return; } selectedPowerUp = null; return; } var candy = getCandyAt(x, y); if (!candy) return; if (selectedCandy) { if (selectedCandy === candy) { // Deselect same candy tween(selectedCandy, { scaleX: 1, scaleY: 1 }, { duration: 150 }); selectedCandy = null; } else if (areAdjacent(selectedCandy, candy)) { // Try to make move if candies are adjacent var success = processMove(selectedCandy, candy); if (success) { tween(selectedCandy, { scaleX: 1, scaleY: 1 }, { duration: 150 }); selectedCandy = null; } } else { // Deselect current candy and select new candy tween(selectedCandy, { scaleX: 1, scaleY: 1 }, { duration: 150 }); selectedCandy = candy; tween(candy, { scaleX: 1.2, scaleY: 1.2 }, { duration: 150 }); } } else { // Select candy selectedCandy = candy; tween(candy, { scaleX: 1.2, scaleY: 1.2 }, { duration: 150 }); } }; // Create menu button (hamburger style with candy theme) var menuButton = null; function createPowerUpButtons() { // Calculate position below coffee cup var coffeeY = GRID_START_Y + GRID_SIZE * CELL_SIZE + 150; var powerUpStartY = coffeeY + 200; // Row Cleaner Button rowCleanerButton = new Container(); var rowCleanerBg = LK.getAsset('powerupButton', { anchorX: 0.5, anchorY: 0.5 }); rowCleanerBg.x = 0; rowCleanerBg.y = 0; rowCleanerBg.tint = 0xFF6B6B; rowCleanerButton.addChild(rowCleanerBg); var rowCleanerIcon = LK.getAsset('rowCleaner', { anchorX: 0.5, anchorY: 0.5 }); rowCleanerIcon.x = 0; rowCleanerIcon.y = -30; rowCleanerButton.addChild(rowCleanerIcon); // Progress bar background for row cleaner var rowCleanerProgressBg = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); rowCleanerProgressBg.x = 0; rowCleanerProgressBg.y = 50; rowCleanerProgressBg.scaleX = 0.6; rowCleanerProgressBg.scaleY = 0.15; rowCleanerProgressBg.tint = 0x000000; rowCleanerProgressBg.alpha = 0.3; rowCleanerButton.addChild(rowCleanerProgressBg); // Progress bar fill for row cleaner var rowCleanerProgressFill = LK.getAsset('gridCell', { anchorX: 0, anchorY: 0.5 }); rowCleanerProgressFill.x = -60; rowCleanerProgressFill.y = 50; rowCleanerProgressFill.scaleX = 0; rowCleanerProgressFill.scaleY = 0.15; rowCleanerProgressFill.tint = 0x00FF00; rowCleanerButton.addChild(rowCleanerProgressFill); rowCleanerButton.progressFill = rowCleanerProgressFill; var rowCleanerText = new Text2('2000', { size: 40, fill: 0xFFFFFF }); rowCleanerText.anchor.set(0.5, 0.5); rowCleanerText.x = 0; rowCleanerText.y = 10; rowCleanerButton.addChild(rowCleanerText); var rowCleanerDesc = new Text2('Clear Row', { size: 30, fill: 0xFFFFFF }); rowCleanerDesc.anchor.set(0.5, 0.5); rowCleanerDesc.x = 0; rowCleanerDesc.y = 40; rowCleanerButton.addChild(rowCleanerDesc); rowCleanerButton.x = 2048 / 2 - 200; rowCleanerButton.y = powerUpStartY; // Color Changer Button colorChangerButton = new Container(); var colorChangerBg = LK.getAsset('powerupButton', { anchorX: 0.5, anchorY: 0.5 }); colorChangerBg.x = 0; colorChangerBg.y = 0; colorChangerBg.tint = 0xF9CA24; colorChangerButton.addChild(colorChangerBg); var colorChangerIcon = LK.getAsset('colorChanger', { anchorX: 0.5, anchorY: 0.5 }); colorChangerIcon.x = 0; colorChangerIcon.y = -30; colorChangerButton.addChild(colorChangerIcon); // Progress bar background for color changer var colorChangerProgressBg = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); colorChangerProgressBg.x = 0; colorChangerProgressBg.y = 50; colorChangerProgressBg.scaleX = 0.6; colorChangerProgressBg.scaleY = 0.15; colorChangerProgressBg.tint = 0x000000; colorChangerProgressBg.alpha = 0.3; colorChangerButton.addChild(colorChangerProgressBg); // Progress bar fill for color changer var colorChangerProgressFill = LK.getAsset('gridCell', { anchorX: 0, anchorY: 0.5 }); colorChangerProgressFill.x = -60; colorChangerProgressFill.y = 50; colorChangerProgressFill.scaleX = 0; colorChangerProgressFill.scaleY = 0.15; colorChangerProgressFill.tint = 0x00FF00; colorChangerButton.addChild(colorChangerProgressFill); colorChangerButton.progressFill = colorChangerProgressFill; var colorChangerText = new Text2('500', { size: 40, fill: 0xFFFFFF }); colorChangerText.anchor.set(0.5, 0.5); colorChangerText.x = 0; colorChangerText.y = 10; colorChangerButton.addChild(colorChangerText); var colorChangerDesc = new Text2('Change Color', { size: 30, fill: 0xFFFFFF }); colorChangerDesc.anchor.set(0.5, 0.5); colorChangerDesc.x = 0; colorChangerDesc.y = 40; colorChangerButton.addChild(colorChangerDesc); colorChangerButton.x = 2048 / 2; colorChangerButton.y = powerUpStartY; // Clear All Button clearAllButton = new Container(); var clearAllBg = LK.getAsset('powerupButton', { anchorX: 0.5, anchorY: 0.5 }); clearAllBg.x = 0; clearAllBg.y = 0; clearAllBg.tint = 0x9B59B6; clearAllButton.addChild(clearAllBg); var clearAllIcon = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); clearAllIcon.scaleX = 0.4; clearAllIcon.scaleY = 0.4; clearAllIcon.x = 0; clearAllIcon.y = -30; clearAllButton.addChild(clearAllIcon); // Progress bar background for clear all var clearAllProgressBg = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); clearAllProgressBg.x = 0; clearAllProgressBg.y = 50; clearAllProgressBg.scaleX = 0.6; clearAllProgressBg.scaleY = 0.15; clearAllProgressBg.tint = 0x000000; clearAllProgressBg.alpha = 0.3; clearAllButton.addChild(clearAllProgressBg); // Progress bar fill for clear all var clearAllProgressFill = LK.getAsset('gridCell', { anchorX: 0, anchorY: 0.5 }); clearAllProgressFill.x = -60; clearAllProgressFill.y = 50; clearAllProgressFill.scaleX = 0; clearAllProgressFill.scaleY = 0.15; clearAllProgressFill.tint = 0x00FF00; clearAllButton.addChild(clearAllProgressFill); clearAllButton.progressFill = clearAllProgressFill; var clearAllText = new Text2('7000', { size: 40, fill: 0xFFFFFF }); clearAllText.anchor.set(0.5, 0.5); clearAllText.x = 0; clearAllText.y = 10; clearAllButton.addChild(clearAllText); var clearAllDesc = new Text2('Clear All', { size: 30, fill: 0xFFFFFF }); clearAllDesc.anchor.set(0.5, 0.5); clearAllDesc.x = 0; clearAllDesc.y = 40; clearAllButton.addChild(clearAllDesc); clearAllButton.x = 2048 / 2 + 200; clearAllButton.y = powerUpStartY; // Add click handlers // Hint Button var hintButton = new Container(); var hintBg = LK.getAsset('powerupButton', { anchorX: 0.5, anchorY: 0.5 }); hintBg.x = 0; hintBg.y = 0; hintBg.tint = 0x45B7D1; hintButton.addChild(hintBg); var hintIcon = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); hintIcon.x = 0; hintIcon.y = -30; hintIcon.scaleX = 0.25; hintIcon.scaleY = 0.25; hintIcon.tint = 0xFFFFFF; hintButton.addChild(hintIcon); // Progress bar background for hint var hintProgressBg = LK.getAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); hintProgressBg.x = 0; hintProgressBg.y = 50; hintProgressBg.scaleX = 0.6; hintProgressBg.scaleY = 0.15; hintProgressBg.tint = 0x000000; hintProgressBg.alpha = 0.3; hintButton.addChild(hintProgressBg); // Progress bar fill for hint var hintProgressFill = LK.getAsset('gridCell', { anchorX: 0, anchorY: 0.5 }); hintProgressFill.x = -60; hintProgressFill.y = 50; hintProgressFill.scaleX = 0; hintProgressFill.scaleY = 0.15; hintProgressFill.tint = 0x00FF00; hintButton.addChild(hintProgressFill); hintButton.progressFill = hintProgressFill; var hintText = new Text2('4000', { size: 40, fill: 0xFFFFFF }); hintText.anchor.set(0.5, 0.5); hintText.x = 0; hintText.y = 10; hintButton.addChild(hintText); var hintDesc = new Text2('Hint', { size: 30, fill: 0xFFFFFF }); hintDesc.anchor.set(0.5, 0.5); hintDesc.x = 0; hintDesc.y = 40; hintButton.addChild(hintDesc); hintButton.x = 2048 / 2 - 400; hintButton.y = powerUpStartY; rowCleanerButton.down = function (x, y, obj) { if (score >= rowCleanerCost) { selectedPowerUp = 'rowCleaner'; // Visual feedback tween(rowCleanerBg, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, onFinish: function onFinish() { tween(rowCleanerBg, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); } }; colorChangerButton.down = function (x, y, obj) { if (score >= colorChangerCost) { selectedPowerUp = 'colorChanger'; // Visual feedback tween(colorChangerBg, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, onFinish: function onFinish() { tween(colorChangerBg, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); } }; // Add hint button click handler hintButton.down = function (x, y, obj) { if (score >= 4000) { score -= 4000; scoreText.setText('Score: ' + score); // Find best move var bestMove = findBestMove(); if (bestMove) { showHintArrow(bestMove.candy1, bestMove.candy2); } // Visual feedback tween(hintBg, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, onFinish: function onFinish() { tween(hintBg, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); } }; // Add clear all button click handler clearAllButton.down = function (x, y, obj) { if (score >= clearAllCost) { // Execute clear all immediately instead of setting selectedPowerUp score -= clearAllCost; score += 5000; // Bonus points scoreText.setText('Score: ' + score); var allCandies = []; for (var x = 0; x < GRID_SIZE; x++) { for (var y = 0; y < GRID_SIZE; y++) { if (gameGrid[x][y]) { allCandies.push(gameGrid[x][y]); gameGrid[x][y] = null; } } } // Animate all candies removal for (var i = 0; i < allCandies.length; i++) { allCandies[i].markForRemoval(); } // Create spectacular particle effects for (var i = 0; i < allCandies.length; i++) { var candy = allCandies[i]; var candyColors = [0xff6b6b, 0x4ecdc4, 0x45b7d1, 0xf9ca24, 0xf0932b, 0xeb4d4b]; var particleColor = candyColors[candy.candyType - 1] || 0xffffff; // Create more particles for spectacular effect var particleCount = Math.floor(Math.random() * 8) + 12; for (var p = 0; p < particleCount; p++) { var particle = new Particle(particleColor, candy.x, candy.y); particles.push(particle); game.addChild(particle); } } // Screen flash effect LK.effects.flashScreen(0xFFFFFF, 500); // Remove candies and refill grid LK.setTimeout(function () { for (var i = 0; i < allCandies.length; i++) { allCandies[i].destroy(); } applyGravity(); }, 250); // Visual feedback tween(clearAllBg, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, onFinish: function onFinish() { tween(clearAllBg, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); } }; game.addChild(hintButton); game.addChild(rowCleanerButton); game.addChild(colorChangerButton); game.addChild(clearAllButton); gameElements.push(hintButton); gameElements.push(rowCleanerButton); gameElements.push(colorChangerButton); gameElements.push(clearAllButton); } // Menu button functionality removed // Coffee cup will be created when game starts // Initialize sound settings from storage try { var storedSoundSetting = storage.soundEnabled; if (storedSoundSetting === null || storedSoundSetting === undefined) { soundEnabled = true; storage.soundEnabled = soundEnabled; } else { soundEnabled = storedSoundSetting; } } catch (e) { // Fallback if storage is not available soundEnabled = true; } // Start background music if sound is enabled if (soundEnabled) { LK.playMusic('rahat'); } // Show main menu instead of initializing game immediately showMainMenu(); game.update = function () { // Update menu elements when in menu state if (gameState === 'menu' && mainMenu) { mainMenu.update(); } // Update particles during game for (var i = particles.length - 1; i >= 0; i--) { particles[i].update(); } // Combo texts are automatically managed by their own animations // No manual update needed as they self-destruct // Background is now static image - no animation needed // Update power-up button states and progress bars based on score if (gameState === 'game' && hintButton && rowCleanerButton && colorChangerButton && clearAllButton) { // Update hint button and progress bar var hintProgress = Math.min(score / hintCost, 1); if (hintButton.progressFill) { tween(hintButton.progressFill, { scaleX: hintProgress * 0.6 }, { duration: 200, easing: tween.easeOut }); // Change color based on availability var fillColor = score >= hintCost ? 0x00FF00 : 0xFFAA00; tween(hintButton.progressFill, { tint: fillColor }, { duration: 200 }); } if (score >= hintCost) { hintButton.alpha = 1; } else { hintButton.alpha = 0.8; } // Update row cleaner button and progress bar var rowCleanerProgress = Math.min(score / rowCleanerCost, 1); if (rowCleanerButton.progressFill) { tween(rowCleanerButton.progressFill, { scaleX: rowCleanerProgress * 0.6 }, { duration: 200, easing: tween.easeOut }); // Change color based on availability var fillColor = score >= rowCleanerCost ? 0x00FF00 : 0xFFAA00; tween(rowCleanerButton.progressFill, { tint: fillColor }, { duration: 200 }); } if (score >= rowCleanerCost) { rowCleanerButton.alpha = 1; } else { rowCleanerButton.alpha = 0.8; } // Update color changer button and progress bar var colorChangerProgress = Math.min(score / colorChangerCost, 1); if (colorChangerButton.progressFill) { tween(colorChangerButton.progressFill, { scaleX: colorChangerProgress * 0.6 }, { duration: 200, easing: tween.easeOut }); // Change color based on availability var fillColor = score >= colorChangerCost ? 0x00FF00 : 0xFFAA00; tween(colorChangerButton.progressFill, { tint: fillColor }, { duration: 200 }); } if (score >= colorChangerCost) { colorChangerButton.alpha = 1; } else { colorChangerButton.alpha = 0.8; } // Update clear all button and progress bar var clearAllProgress = Math.min(score / clearAllCost, 1); if (clearAllButton.progressFill) { tween(clearAllButton.progressFill, { scaleX: clearAllProgress * 0.6 }, { duration: 200, easing: tween.easeOut }); // Change color based on availability var fillColor = score >= clearAllCost ? 0x00FF00 : 0xFFAA00; tween(clearAllButton.progressFill, { tint: fillColor }, { duration: 200 }); } if (score >= clearAllCost) { clearAllButton.alpha = 1; } else { clearAllButton.alpha = 0.8; } } // Only run game physics during game state if (gameState === 'game') { // Add sparkle effects to random candies if (LK.ticks % 180 === 0) { // Every 3 seconds at 60fps // Pick a random candy to sparkle var validCandies = []; for (var x = 0; x < GRID_SIZE; x++) { for (var y = 0; y < GRID_SIZE; y++) { if (gameGrid[x][y] && !gameGrid[x][y].isAnimating && !gameGrid[x][y].isMatched) { validCandies.push(gameGrid[x][y]); } } } if (validCandies.length > 0) { var randomCandy = validCandies[Math.floor(Math.random() * validCandies.length)]; randomCandy.sparkle(); } } // Continuously check for physics updates when not processing moves if (!isProcessing && animatingCandies === 0) { // Check if any candies need to fall due to physics var needsPhysicsUpdate = false; for (var x = 0; x < GRID_SIZE && !needsPhysicsUpdate; x++) { // Check entire column from bottom to top for any candy that should fall for (var y = GRID_SIZE - 1; y >= 0; y--) { if (gameGrid[x][y] === null) { // Found empty space, check if there's a candy above it for (var checkY = y - 1; checkY >= 0; checkY--) { if (gameGrid[x][checkY] !== null) { needsPhysicsUpdate = true; break; } } if (needsPhysicsUpdate) break; } } } if (needsPhysicsUpdate) { applyGravity(); } } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Candy = Container.expand(function (type) {
var self = Container.call(this);
self.candyType = type || 1;
self.gridX = 0;
self.gridY = 0;
self.isAnimating = false;
self.isMatched = false;
self.idleAnimationActive = false;
self.bobOffset = Math.random() * Math.PI * 2; // Random starting phase for bobbing
self.sparkleTimer = Math.random() * 120; // Random timing for sparkle effect
var candyGraphics = self.attachAsset('candy' + self.candyType, {
anchorX: 0.5,
anchorY: 0.5
});
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = GRID_START_X + gridX * CELL_SIZE + CELL_SIZE / 2;
self.y = GRID_START_Y + gridY * CELL_SIZE + CELL_SIZE / 2;
};
self.animateToPosition = function (targetX, targetY, callback) {
self.isAnimating = true;
self.stopIdleAnimation(); // Stop idle animation during move animation
tween(self, {
x: targetX,
y: targetY
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isAnimating = false;
if (callback) callback();
// Restart idle animation after move completes
LK.setTimeout(function () {
if (!self.isMatched) {
self.startIdleAnimation();
}
}, 200);
}
});
};
self.animateFall = function (newGridY, callback) {
var targetY = GRID_START_Y + newGridY * CELL_SIZE + CELL_SIZE / 2;
self.gridY = newGridY;
self.stopIdleAnimation(); // Stop idle animation during fall
self.animateToPosition(self.x, targetY, function () {
if (callback) callback();
// Restart idle animation after fall completes
LK.setTimeout(function () {
if (!self.isMatched) {
self.startIdleAnimation();
}
}, 300);
});
};
self.startIdleAnimation = function () {
if (self.idleAnimationActive || self.isAnimating || self.isMatched) return;
self.idleAnimationActive = true;
// Gentle bobbing animation
function bobAnimation() {
if (!self.idleAnimationActive || self.isAnimating || self.isMatched) return;
tween(self, {
y: self.y - 8
}, {
duration: 1500 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (!self.idleAnimationActive || self.isAnimating || self.isMatched) return;
tween(self, {
y: self.y + 8
}, {
duration: 1500 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.idleAnimationActive && !self.isAnimating && !self.isMatched) {
bobAnimation();
}
}
});
}
});
}
// Start bobbing with a random delay
LK.setTimeout(function () {
if (self.idleAnimationActive && !self.isAnimating && !self.isMatched) {
bobAnimation();
}
}, Math.random() * 3000);
};
self.stopIdleAnimation = function () {
self.idleAnimationActive = false;
tween.stop(self, {
y: true
}); // Stop any y-position tweens
};
self.sparkle = function () {
if (self.isAnimating || self.isMatched) return;
// Create sparkle effect with scale and alpha animation
tween(candyGraphics, {
scaleX: 1.15,
scaleY: 1.15,
alpha: 1.2
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(candyGraphics, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 300,
easing: tween.easeIn
});
}
});
};
self.markForRemoval = function () {
self.isMatched = true;
self.stopIdleAnimation(); // Stop idle animations when marked for removal
tween(self, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 200,
easing: tween.easeIn
});
};
return self;
});
var ComboText = Container.expand(function (message, x, y, color) {
var self = Container.call(this);
self.x = x;
self.y = y;
var comboTextDisplay = new Text2(message, {
size: 120,
fill: color || 0xFFFFFF
});
comboTextDisplay.anchor.set(0.5, 0.5);
self.addChild(comboTextDisplay);
// Initial state
self.alpha = 0;
self.scaleX = 0.5;
self.scaleY = 0.5;
// Animate in
tween(self, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Hold for a moment
LK.setTimeout(function () {
// Animate out
tween(self, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5,
y: self.y - 100
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
self.destroy();
var index = comboTexts.indexOf(self);
if (index > -1) {
comboTexts.splice(index, 1);
}
}
});
}, 800);
}
});
return self;
});
var FloatingParticle = Container.expand(function (color, size) {
var self = Container.call(this);
var particleGraphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
particleGraphics.tint = color;
particleGraphics.scaleX = size;
particleGraphics.scaleY = size;
self.speed = Math.random() * 2 + 1;
self.direction = Math.random() * Math.PI * 2;
self.bobOffset = Math.random() * Math.PI * 2;
self.bobSpeed = Math.random() * 0.02 + 0.01;
self.update = function () {
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed + Math.sin(LK.ticks * self.bobSpeed + self.bobOffset) * 0.5;
// Wrap around screen
if (self.x < -50) self.x = 2098;
if (self.x > 2098) self.x = -50;
if (self.y < -50) self.y = 2782;
if (self.y > 2782) self.y = -50;
// Gentle rotation
self.rotation += 0.01;
};
return self;
});
var HowToPlayScreen = Container.expand(function () {
var self = Container.call(this);
// Background
var background = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
background.x = 2048 / 2;
background.y = 2732 / 2;
background.scaleX = 12;
background.scaleY = 16;
background.alpha = 0.9;
background.tint = 0x000000;
self.addChild(background);
// Title
var titleText = new Text2('HOW TO PLAY', {
size: 120,
fill: 0xFF69B4
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 400;
self.addChild(titleText);
// Instructions
var instructions = ['1. Swap adjacent candies to create matches', '2. Match 3-6 connected candies of same type', '3. Candies can connect horizontally & vertically', '4. Scoring: 3 blocks=50, 4=150, 5=200, 6=300', '5. Create combos for bonus points!'];
for (var i = 0; i < instructions.length; i++) {
var instructionText = new Text2(instructions[i], {
size: 55,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 2048 / 2;
instructionText.y = 700 + i * 140;
self.addChild(instructionText);
}
// Back button
var backButton = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
backButton.x = 2048 / 2;
backButton.y = 2200;
backButton.scaleX = 1.5;
backButton.scaleY = 0.6;
backButton.tint = 0xEB4D4B;
self.addChild(backButton);
var backButtonText = new Text2('BACK', {
size: 80,
fill: 0xFFFFFF
});
backButtonText.anchor.set(0.5, 0.5);
backButtonText.x = backButton.x;
backButtonText.y = backButton.y;
self.addChild(backButtonText);
backButton.down = function (x, y, obj) {
// Button press animation
tween(backButton, {
scaleX: 1.3,
scaleY: 0.5
}, {
duration: 100,
onFinish: function onFinish() {
tween(backButton, {
scaleX: 1.5,
scaleY: 0.6
}, {
duration: 100
});
}
});
// Go back to main menu
if (typeof showMainMenu === 'function') {
showMainMenu();
}
};
return self;
});
var MainMenu = Container.expand(function () {
var self = Container.call(this);
// Create gradient background overlay
var gradientOverlay = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
gradientOverlay.x = 2048 / 2;
gradientOverlay.y = 2732 / 2;
gradientOverlay.scaleX = 12;
gradientOverlay.scaleY = 16;
gradientOverlay.alpha = 0.1;
gradientOverlay.tint = 0x000000;
self.addChild(gradientOverlay);
// Add menu decorations
var decorations = new MenuDecoration();
self.addChild(decorations);
// Create floating background particles
var particles = [];
for (var i = 0; i < 20; i++) {
var colors = [0xFF69B4, 0x4ECDC4, 0xF9CA24, 0xEB4D4B, 0x45B7D1, 0xF0932B];
var color = colors[Math.floor(Math.random() * colors.length)];
var size = Math.random() * 0.8 + 0.3;
var particle = new FloatingParticle(color, size);
particle.x = Math.random() * 2048;
particle.y = Math.random() * 2732;
particle.alpha = 0.6;
particles.push(particle);
self.addChild(particle);
}
// Game title with enhanced styling
var titleText = new Text2('🍭 CANDY MATCH 🍭', {
size: 200,
fill: 0xFF69B4
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 500;
self.addChild(titleText);
// Add title shadow effect
var titleShadow = new Text2('🍭 CANDY MATCH 🍭', {
size: 200,
fill: 0x000000
});
titleShadow.anchor.set(0.5, 0.5);
titleShadow.x = 2048 / 2 + 5;
titleShadow.y = 505;
titleShadow.alpha = 0.3;
self.addChildAt(titleShadow, self.getChildIndex(titleText));
// Subtitle
var subtitleText = new Text2('✨ Match candies and create sweet combos! ✨', {
size: 60,
fill: 0xFFFFFF
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 2048 / 2;
subtitleText.y = 650;
subtitleText.alpha = 0.8;
self.addChild(subtitleText);
// Enhanced start button with glow effect
var startButtonGlow = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
startButtonGlow.x = 2048 / 2;
startButtonGlow.y = 1200;
startButtonGlow.scaleX = 3.4;
startButtonGlow.scaleY = 1.4;
startButtonGlow.tint = 0x4ECDC4;
startButtonGlow.alpha = 0.3;
self.addChild(startButtonGlow);
var startButton = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
startButton.x = 2048 / 2;
startButton.y = 1200;
startButton.scaleX = 3.2;
startButton.scaleY = 1.3;
startButton.tint = 0x4ECDC4;
self.addChild(startButton);
var startButtonText = new Text2('🚀 START GAME', {
size: 90,
fill: 0xFFFFFF
});
startButtonText.anchor.set(0.5, 0.5);
startButtonText.x = startButton.x;
startButtonText.y = startButton.y;
self.addChild(startButtonText);
// Enhanced how to play button with glow effect
var howToPlayButtonGlow = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
howToPlayButtonGlow.x = 2048 / 2;
howToPlayButtonGlow.y = 1500;
howToPlayButtonGlow.scaleX = 3.2;
howToPlayButtonGlow.scaleY = 1.3;
howToPlayButtonGlow.tint = 0xF9CA24;
howToPlayButtonGlow.alpha = 0.3;
self.addChild(howToPlayButtonGlow);
var howToPlayButton = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
howToPlayButton.x = 2048 / 2;
howToPlayButton.y = 1500;
howToPlayButton.scaleX = 3.0;
howToPlayButton.scaleY = 1.2;
howToPlayButton.tint = 0xF9CA24;
self.addChild(howToPlayButton);
var howToPlayButtonText = new Text2('❓ HOW TO PLAY', {
size: 90,
fill: 0xFFFFFF
});
howToPlayButtonText.anchor.set(0.5, 0.5);
howToPlayButtonText.x = howToPlayButton.x;
howToPlayButtonText.y = howToPlayButton.y;
self.addChild(howToPlayButtonText);
// Sound control buttons
var soundButtonGlow = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
soundButtonGlow.x = 2048 / 2;
soundButtonGlow.y = 1800;
soundButtonGlow.scaleX = 3.0;
soundButtonGlow.scaleY = 1.2;
soundButtonGlow.tint = 0xEB4D4B;
soundButtonGlow.alpha = 0.3;
self.addChild(soundButtonGlow);
var soundButton = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
soundButton.x = 2048 / 2;
soundButton.y = 1800;
soundButton.scaleX = 2.8;
soundButton.scaleY = 1.1;
soundButton.tint = 0xEB4D4B;
self.addChild(soundButton);
// Get current sound state from storage
var soundEnabled = storage.soundEnabled;
if (soundEnabled === null || soundEnabled === undefined) {
soundEnabled = true;
storage.soundEnabled = soundEnabled;
}
var soundButtonText = new Text2(soundEnabled ? '🔊 SOUND ON' : '🔇 SOUND OFF', {
size: 90,
fill: 0xFFFFFF
});
soundButtonText.anchor.set(0.5, 0.5);
soundButtonText.x = soundButton.x;
soundButtonText.y = soundButton.y;
self.addChild(soundButtonText);
// Apply current sound settings
if (!soundEnabled) {
LK.stopMusic();
}
// Animate title with rainbow effect
self.animateTitle = function () {
// Scale animation
tween(titleText, {
scaleX: 1.15,
scaleY: 1.15
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText, {
scaleX: 1,
scaleY: 1
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.animateTitle();
}
});
}
});
// Color cycle animation
var colors = [0xFF69B4, 0x4ECDC4, 0xF9CA24, 0xEB4D4B, 0x45B7D1];
var currentColorIndex = 0;
function cycleColors() {
currentColorIndex = (currentColorIndex + 1) % colors.length;
tween(titleText, {
tint: colors[currentColorIndex]
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
LK.setTimeout(cycleColors, 500);
}
});
}
cycleColors();
};
// Animate subtitle
function animateSubtitle() {
tween(subtitleText, {
alpha: 1,
y: subtitleText.y - 10
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(subtitleText, {
alpha: 0.6,
y: 650
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: animateSubtitle
});
}
});
}
animateSubtitle();
// Animate button glows
function animateGlows() {
tween(startButtonGlow, {
alpha: 0.6,
scaleX: 3.6,
scaleY: 1.5
}, {
duration: 1200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(startButtonGlow, {
alpha: 0.3,
scaleX: 3.4,
scaleY: 1.4
}, {
duration: 1200,
easing: tween.easeInOut
});
}
});
tween(howToPlayButtonGlow, {
alpha: 0.6,
scaleX: 3.4,
scaleY: 1.4
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(howToPlayButtonGlow, {
alpha: 0.3,
scaleX: 3.2,
scaleY: 1.3
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: animateGlows
});
}
});
}
animateGlows();
// Update particles
self.update = function () {
for (var i = 0; i < particles.length; i++) {
particles[i].update();
}
};
// Enhanced button click handlers
startButton.down = function (x, y, obj) {
// Button press animation with enhanced effects
tween(startButton, {
scaleX: 2.8,
scaleY: 1.0
}, {
duration: 80,
onFinish: function onFinish() {
tween(startButton, {
scaleX: 3.4,
scaleY: 1.4
}, {
duration: 80,
onFinish: function onFinish() {
tween(startButton, {
scaleX: 3.2,
scaleY: 1.3
}, {
duration: 80
});
}
});
}
});
// Animate button glow on press
tween(startButtonGlow, {
alpha: 0.8,
scaleX: 3.8,
scaleY: 1.7
}, {
duration: 150,
onFinish: function onFinish() {
tween(startButtonGlow, {
alpha: 0.3,
scaleX: 3.4,
scaleY: 1.4
}, {
duration: 200
});
}
});
// Start the game
startGame();
};
howToPlayButton.down = function (x, y, obj) {
// Button press animation with enhanced effects
tween(howToPlayButton, {
scaleX: 2.6,
scaleY: 0.9
}, {
duration: 80,
onFinish: function onFinish() {
tween(howToPlayButton, {
scaleX: 3.2,
scaleY: 1.3
}, {
duration: 80,
onFinish: function onFinish() {
tween(howToPlayButton, {
scaleX: 3.0,
scaleY: 1.2
}, {
duration: 80
});
}
});
}
});
// Animate button glow on press
tween(howToPlayButtonGlow, {
alpha: 0.8,
scaleX: 3.6,
scaleY: 1.6
}, {
duration: 150,
onFinish: function onFinish() {
tween(howToPlayButtonGlow, {
alpha: 0.3,
scaleX: 3.2,
scaleY: 1.3
}, {
duration: 200
});
}
});
// Show how to play
if (typeof showHowToPlay === 'function') {
showHowToPlay();
}
};
soundButton.down = function (x, y, obj) {
// Button press animation with enhanced effects
tween(soundButton, {
scaleX: 2.4,
scaleY: 0.9
}, {
duration: 80,
onFinish: function onFinish() {
tween(soundButton, {
scaleX: 3.0,
scaleY: 1.2
}, {
duration: 80,
onFinish: function onFinish() {
tween(soundButton, {
scaleX: 2.8,
scaleY: 1.1
}, {
duration: 80
});
}
});
}
});
// Animate button glow on press
tween(soundButtonGlow, {
alpha: 0.8,
scaleX: 3.4,
scaleY: 1.5
}, {
duration: 150,
onFinish: function onFinish() {
tween(soundButtonGlow, {
alpha: 0.3,
scaleX: 3.0,
scaleY: 1.2
}, {
duration: 200
});
}
});
// Toggle sound
soundEnabled = !soundEnabled;
storage.soundEnabled = soundEnabled;
soundButtonText.setText(soundEnabled ? '🔊 SOUND ON' : '🔇 SOUND OFF');
// Apply sound settings
if (soundEnabled) {
LK.playMusic('rahat');
} else {
LK.stopMusic();
}
};
return self;
});
var MenuDecoration = Container.expand(function () {
var self = Container.call(this);
// Create candy decorations around the screen
var decorationCount = 12;
var _loop = function _loop() {
candyType = Math.floor(Math.random() * 6) + 1;
decoration = LK.getAsset('candy' + candyType, {
anchorX: 0.5,
anchorY: 0.5
});
angle = i / decorationCount * Math.PI * 2;
radius = 800 + Math.random() * 200;
decoration.x = 2048 / 2 + Math.cos(angle) * radius;
decoration.y = 2732 / 2 + Math.sin(angle) * radius;
decoration.alpha = 0.3;
decoration.scaleX = 0.8 + Math.random() * 0.4;
decoration.scaleY = decoration.scaleX;
self.addChild(decoration);
// Animate decorations
animDuration = 3000 + Math.random() * 2000;
targetScale = decoration.scaleX + 0.2;
function animateDecoration(dec) {
tween(dec, {
rotation: dec.rotation + Math.PI * 2,
scaleX: targetScale,
scaleY: targetScale
}, {
duration: animDuration,
easing: tween.easeInOut,
onFinish: function onFinish() {
targetScale = 0.8 + Math.random() * 0.4;
animDuration = 3000 + Math.random() * 2000;
animateDecoration(dec);
}
});
}
animateDecoration(decoration);
},
candyType,
decoration,
angle,
radius,
animDuration,
targetScale;
for (var i = 0; i < decorationCount; i++) {
_loop();
}
return self;
});
var Particle = Container.expand(function (color, startX, startY) {
var self = Container.call(this);
self.x = startX;
self.y = startY;
self.velocityX = (Math.random() - 0.5) * 400;
self.velocityY = (Math.random() - 0.5) * 400;
self.gravity = 300;
self.life = 1.0;
self.maxLife = 1.0;
var particleGraphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
particleGraphics.tint = color;
particleGraphics.scaleX = Math.random() * 0.8 + 0.4;
particleGraphics.scaleY = particleGraphics.scaleX;
self.update = function () {
self.x += self.velocityX * (1 / 60);
self.y += self.velocityY * (1 / 60);
self.velocityY += self.gravity * (1 / 60);
self.life -= 1 / 60 * 2;
var alpha = self.life / self.maxLife;
self.alpha = alpha;
self.scaleX = alpha * particleGraphics.scaleX;
self.scaleY = alpha * particleGraphics.scaleY;
if (self.life <= 0) {
self.destroy();
var index = particles.indexOf(self);
if (index > -1) {
particles.splice(index, 1);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xff69b4
});
/****
* Game Code
****/
function _createForOfIteratorHelper(r, e) {
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (!t) {
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
t && (r = t);
var _n = 0,
F = function F() {};
return {
s: F,
n: function n() {
return _n >= r.length ? {
done: !0
} : {
done: !1,
value: r[_n++]
};
},
e: function e(r) {
throw r;
},
f: F
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var o,
a = !0,
u = !1;
return {
s: function s() {
t = t.call(r);
},
n: function n() {
var r = t.next();
return a = r.done, r;
},
e: function e(r) {
u = !0, o = r;
},
f: function f() {
try {
a || null == t["return"] || t["return"]();
} finally {
if (u) throw o;
}
}
};
}
function _unsupportedIterableToArray(r, a) {
if (r) {
if ("string" == typeof r) return _arrayLikeToArray(r, a);
var t = {}.toString.call(r).slice(8, -1);
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
}
}
function _arrayLikeToArray(r, a) {
(null == a || a > r.length) && (a = r.length);
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
return n;
}
var GRID_SIZE = 8;
var CELL_SIZE = 200;
var GRID_START_X = (2048 - GRID_SIZE * CELL_SIZE) / 2;
var GRID_START_Y = 400;
var gameGrid = [];
var candyTypes = [1, 2, 3, 4, 5, 6];
var selectedCandy = null;
var isProcessing = false;
var movesLeft = 999999;
var score = 0;
var animatingCandies = 0;
var particles = [];
var comboTexts = [];
var currentCombo = 0;
// Power-up variables
var rowCleanerButton = null;
var colorChangerButton = null;
var clearAllButton = null;
var hintButton = null;
var rowCleanerCost = 2000;
var colorChangerCost = 500;
var clearAllCost = 7000;
var hintCost = 4000;
var selectedPowerUp = null; // 'rowCleaner', 'colorChanger', or 'clearAll'
var hintArrows = []; // Array to store hint arrow elements
// Game state variables
var gameState = 'menu'; // 'menu', 'game', 'howtoplay'
var mainMenu = null;
var howToPlayScreen = null;
var gameElements = [];
// Sound control variables
var soundEnabled = true;
// Initialize grid array
for (var x = 0; x < GRID_SIZE; x++) {
gameGrid[x] = [];
for (var y = 0; y < GRID_SIZE; y++) {
gameGrid[x][y] = null;
}
}
// Menu control functions
function startGame() {
gameState = 'game';
hideAllScreens();
initializeGameElements();
}
function showMainMenu() {
gameState = 'menu';
// Clear game grid and destroy candies
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (gameGrid[x][y]) {
gameGrid[x][y].destroy();
gameGrid[x][y] = null;
}
}
}
// Clear particles
for (var i = particles.length - 1; i >= 0; i--) {
particles[i].destroy();
}
particles = [];
// Clear combo texts
for (var i = comboTexts.length - 1; i >= 0; i--) {
comboTexts[i].destroy();
}
comboTexts = [];
// Reset game state
selectedCandy = null;
isProcessing = false;
animatingCandies = 0;
currentCombo = 0;
hideAllScreens();
if (!mainMenu) {
mainMenu = new MainMenu();
game.addChild(mainMenu);
} else {
// Recursively re-enable all menu interactions
var _enableMenuInteractions = function enableMenuInteractions(container) {
container.interactive = true;
if (container.children) {
for (var i = 0; i < container.children.length; i++) {
var child = container.children[i];
child.interactive = true;
if (child.children && child.children.length > 0) {
_enableMenuInteractions(child);
}
}
}
};
mainMenu.alpha = 1;
mainMenu.visible = true;
mainMenu.interactive = true;
_enableMenuInteractions(mainMenu);
}
mainMenu.animateTitle();
}
function showHowToPlay() {
gameState = 'howtoplay';
hideAllScreens();
// Completely hide main menu to prevent interactions
if (mainMenu) {
// Recursively disable all child interactions
var _disableMenuInteractions = function disableMenuInteractions(container) {
container.interactive = false;
if (container.children) {
for (var i = 0; i < container.children.length; i++) {
var child = container.children[i];
child.interactive = false;
if (child.down) {
child.down = null;
}
if (child.children && child.children.length > 0) {
_disableMenuInteractions(child);
}
}
}
};
mainMenu.alpha = 0;
mainMenu.visible = false;
mainMenu.interactive = false;
_disableMenuInteractions(mainMenu);
}
if (!howToPlayScreen) {
howToPlayScreen = new HowToPlayScreen();
game.addChild(howToPlayScreen);
// Ensure how-to-play screen is on top
game.setChildIndex(howToPlayScreen, game.children.length - 1);
} else {
howToPlayScreen.alpha = 1;
howToPlayScreen.visible = true;
// Bring to front when showing
game.setChildIndex(howToPlayScreen, game.children.length - 1);
}
}
function hideAllScreens() {
if (mainMenu) {
mainMenu.alpha = 0;
mainMenu.visible = false;
}
if (howToPlayScreen) {
howToPlayScreen.alpha = 0;
howToPlayScreen.visible = false;
}
// Hide game elements (except persistent ones like scoreText and backgroundImage)
for (var i = 0; i < gameElements.length; i++) {
if (gameElements[i] !== scoreText && gameElements[i] !== backgroundImage) {
gameElements[i].alpha = 0;
}
}
}
function initializeGameElements() {
// Clear existing game elements first
for (var i = gameElements.length - 1; i >= 0; i--) {
if (gameElements[i] !== scoreText && gameElements[i] !== backgroundImage) {
gameElements[i].destroy();
gameElements.splice(i, 1);
}
}
// Show persistent game elements
for (var i = 0; i < gameElements.length; i++) {
gameElements[i].alpha = 1;
}
// Grid background removed - candies display directly on background image
// Add 7000 points to initial score
score += 7000;
scoreText.setText('Score: ' + score);
// Create power-up buttons
createPowerUpButtons();
// Clear hint arrows
clearHintArrows();
// Reset game state
score = 0;
currentCombo = 0;
selectedCandy = null;
isProcessing = false;
scoreText.setText('Score: 0');
// Clear existing candies and initialize fresh grid
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (gameGrid[x][y]) {
gameGrid[x][y].destroy();
gameGrid[x][y] = null;
}
}
}
// Initialize the game grid
initializeGrid();
}
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
gameElements.push(scoreText);
// Create background image
var backgroundImage = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5
});
backgroundImage.x = 2048 / 2;
backgroundImage.y = 2732 / 2;
backgroundImage.scaleX = 2048 / backgroundImage.width;
backgroundImage.scaleY = 2732 / backgroundImage.height;
game.addChild(backgroundImage);
gameElements.push(backgroundImage);
// Grid cells will be created when game starts
function getRandomCandyType() {
return candyTypes[Math.floor(Math.random() * candyTypes.length)];
}
function createCandy(x, y, type) {
if (!type) type = getRandomCandyType();
var candy = new Candy(type);
candy.setGridPosition(x, y);
gameGrid[x][y] = candy;
game.addChild(candy);
// Start idle animations after a short delay to let positioning settle
LK.setTimeout(function () {
if (candy && !candy.isMatched) {
candy.startIdleAnimation();
}
}, 500);
return candy;
}
function initializeGrid() {
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
var type;
var attempts = 0;
do {
type = getRandomCandyType();
attempts++;
} while (attempts < 10 && wouldCreateMatch(x, y, type));
createCandy(x, y, type);
}
}
}
function wouldCreateMatch(x, y, type) {
var horizontalCount = 1;
var verticalCount = 1;
// Check horizontal
for (var i = x - 1; i >= 0 && gameGrid[i][y] && gameGrid[i][y].candyType === type; i--) {
horizontalCount++;
}
for (var i = x + 1; i < GRID_SIZE && gameGrid[i][y] && gameGrid[i][y].candyType === type; i++) {
horizontalCount++;
}
// Check vertical
for (var i = y - 1; i >= 0 && gameGrid[x][i] && gameGrid[x][i].candyType === type; i--) {
verticalCount++;
}
for (var i = y + 1; i < GRID_SIZE && gameGrid[x][i] && gameGrid[x][i].candyType === type; i++) {
verticalCount++;
}
return horizontalCount >= 3 || verticalCount >= 3;
}
function getCandyAt(worldX, worldY) {
var gridX = Math.floor((worldX - GRID_START_X) / CELL_SIZE);
var gridY = Math.floor((worldY - GRID_START_Y) / CELL_SIZE);
if (gridX >= 0 && gridX < GRID_SIZE && gridY >= 0 && gridY < GRID_SIZE) {
return gameGrid[gridX][gridY];
}
return null;
}
function areAdjacent(candy1, candy2) {
var dx = Math.abs(candy1.gridX - candy2.gridX);
var dy = Math.abs(candy1.gridY - candy2.gridY);
return dx === 1 && dy === 0 || dx === 0 && dy === 1;
}
function swapCandies(candy1, candy2) {
var tempX = candy1.gridX;
var tempY = candy1.gridY;
var tempPosX = candy1.x;
var tempPosY = candy1.y;
gameGrid[candy1.gridX][candy1.gridY] = candy2;
gameGrid[candy2.gridX][candy2.gridY] = candy1;
candy1.gridX = candy2.gridX;
candy1.gridY = candy2.gridY;
candy2.gridX = tempX;
candy2.gridY = tempY;
animatingCandies += 2;
// Play boing sound when candies are swapped
LK.getSound('boing').play();
candy1.animateToPosition(candy2.x, candy2.y, function () {
animatingCandies--;
});
candy2.animateToPosition(tempPosX, tempPosY, function () {
animatingCandies--;
});
}
function findMatches() {
var allMatches = [];
var visited = [];
// Initialize visited array
for (var x = 0; x < GRID_SIZE; x++) {
visited[x] = [];
for (var y = 0; y < GRID_SIZE; y++) {
visited[x][y] = false;
}
}
// Flood fill function to find all connected candies of same type (max 6 blocks)
function floodFill(startX, startY, candyType, connectedGroup) {
// Check bounds and if already visited
if (startX < 0 || startX >= GRID_SIZE || startY < 0 || startY >= GRID_SIZE) {
return;
}
if (visited[startX][startY]) {
return;
}
var candy = gameGrid[startX][startY];
if (!candy || candy.candyType !== candyType) {
return;
}
// Limit group size to maximum 6 blocks
if (connectedGroup.length >= 6) {
return;
}
// Mark as visited and add to group
visited[startX][startY] = true;
connectedGroup.push(candy);
// Check all 4 adjacent directions (up, down, left, right) only if we haven't reached the limit
if (connectedGroup.length < 6) {
floodFill(startX - 1, startY, candyType, connectedGroup); // left
floodFill(startX + 1, startY, candyType, connectedGroup); // right
floodFill(startX, startY - 1, candyType, connectedGroup); // up
floodFill(startX, startY + 1, candyType, connectedGroup); // down
}
}
// Check each cell for connected groups
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (!visited[x][y] && gameGrid[x][y]) {
var connectedGroup = [];
var candyType = gameGrid[x][y].candyType;
// Find all connected candies of the same type
floodFill(x, y, candyType, connectedGroup);
// If we found 3 or more connected candies, add this group to allMatches
if (connectedGroup.length >= 3) {
allMatches.push(connectedGroup);
}
}
}
}
return allMatches;
}
function removeMatches(matchGroups) {
if (matchGroups.length === 0) return;
LK.getSound('match').play();
// Flatten all matches for candy removal and particle effects
var allMatches = [];
for (var g = 0; g < matchGroups.length; g++) {
for (var c = 0; c < matchGroups[g].length; c++) {
allMatches.push(matchGroups[g][c]);
}
}
for (var i = 0; i < allMatches.length; i++) {
var candy = allMatches[i];
// Create particle explosion for each candy
var candyColors = [0xff6b6b, 0x4ecdc4, 0x45b7d1, 0xf9ca24, 0xf0932b, 0xeb4d4b];
var particleColor = candyColors[candy.candyType - 1] || 0xffffff;
// Create 8-12 particles per candy
var particleCount = Math.floor(Math.random() * 5) + 8;
for (var p = 0; p < particleCount; p++) {
var particle = new Particle(particleColor, candy.x, candy.y);
particles.push(particle);
game.addChild(particle);
}
candy.markForRemoval();
gameGrid[candy.gridX][candy.gridY] = null;
}
// Update score based on each group's size with new scoring system
var oldScore = score;
var largestGroupSize = 0;
for (var g = 0; g < matchGroups.length; g++) {
var groupSize = Math.min(matchGroups[g].length, 6); // Cap at 6 blocks maximum
if (groupSize > largestGroupSize) {
largestGroupSize = groupSize;
}
if (groupSize === 3) {
score += 50;
} else if (groupSize === 4) {
score += 150;
} else if (groupSize === 5) {
score += 200;
} else if (groupSize >= 6) {
score += 300;
}
}
// Check for score milestones and celebrate
var milestones = [1000, 5000, 10000, 25000, 50000];
for (var m = 0; m < milestones.length; m++) {
if (oldScore < milestones[m] && score >= milestones[m]) {
// Milestone reached! Create celebration effect
var milestoneText = new Text2('MILESTONE!\n' + milestones[m] + ' POINTS!', {
size: 80,
fill: 0xFF69B4
});
milestoneText.anchor.set(0.5, 0.5);
milestoneText.x = 2048 / 2;
milestoneText.y = 400;
milestoneText.alpha = 0;
milestoneText.scaleX = 0.5;
milestoneText.scaleY = 0.5;
game.addChild(milestoneText);
// Animate milestone text
tween(milestoneText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(milestoneText, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5,
y: milestoneText.y - 100
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
milestoneText.destroy();
}
});
}, 1500);
}
});
// Screen flash for milestone
LK.effects.flashScreen(0xFF69B4, 800);
break;
}
}
// Create floating score text for each match group
var scoreIncrease = score - oldScore;
var floatingScoreText = new Text2('+' + scoreIncrease, {
size: 100,
fill: 0xF9CA24
});
floatingScoreText.anchor.set(0.5, 0.5);
// Position above the grid
floatingScoreText.x = 2048 / 2;
floatingScoreText.y = GRID_START_Y - 100;
floatingScoreText.alpha = 0;
// Set initial rotation to be horizontal
floatingScoreText.rotation = 0;
game.addChild(floatingScoreText);
// Animate floating score - first appear, then move towards score display
tween(floatingScoreText, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Convert score text position to game coordinates
var scoreWorldPos = game.toLocal(LK.gui.top.toGlobal({
x: scoreText.x,
y: scoreText.y
}));
tween(floatingScoreText, {
alpha: 0,
x: scoreWorldPos.x,
y: scoreWorldPos.y,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
floatingScoreText.destroy();
}
});
}
});
// Animate main score counter with pulsing effect
tween(scoreText, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xF9CA24
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(scoreText, {
scaleX: 1,
scaleY: 1,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
}
});
// Animate score increase with smooth counting
var tempScore = oldScore;
var scoreAnimationTimer = LK.setInterval(function () {
tempScore += scoreIncrease / 30; // 30 steps over 500ms
if (tempScore >= score) {
tempScore = score;
LK.clearInterval(scoreAnimationTimer);
}
scoreText.setText('Score: ' + Math.floor(tempScore));
}, 16); // ~60fps
// Increment combo counter
currentCombo++;
// Play celebration sound for large matches
if (largestGroupSize >= 5) {
// Celebration sound removed
}
// Show combo text based on largest match size and combo count
var comboMessage = "";
var comboColor = 0xFFFFFF;
if (largestGroupSize >= 5) {
comboMessage = "Fantastic!";
comboColor = 0xFF6B6B;
// Screen shake for 5+ matches
var shakeIntensity = 15;
var originalX = game.x;
var originalY = game.y;
tween(game, {
x: originalX + shakeIntensity,
y: originalY + shakeIntensity * 0.5
}, {
duration: 50,
onFinish: function onFinish() {
tween(game, {
x: originalX - shakeIntensity,
y: originalY - shakeIntensity * 0.5
}, {
duration: 50,
onFinish: function onFinish() {
tween(game, {
x: originalX + shakeIntensity * 0.5,
y: originalY + shakeIntensity
}, {
duration: 50,
onFinish: function onFinish() {
tween(game, {
x: originalX,
y: originalY
}, {
duration: 50
});
}
});
}
});
}
});
} else if (largestGroupSize >= 4) {
comboMessage = "Awesome!";
comboColor = 0x4ECDC4;
// Screen shake for 4+ matches
var shakeIntensity = 10;
var originalX = game.x;
var originalY = game.y;
tween(game, {
x: originalX + shakeIntensity,
y: originalY
}, {
duration: 75,
onFinish: function onFinish() {
tween(game, {
x: originalX - shakeIntensity,
y: originalY
}, {
duration: 75,
onFinish: function onFinish() {
tween(game, {
x: originalX,
y: originalY
}, {
duration: 75
});
}
});
}
});
} else if (currentCombo >= 3) {
comboMessage = "Great Combo!";
comboColor = 0xF9CA24;
// Light screen shake for combo
var shakeIntensity = 5;
var originalX = game.x;
var originalY = game.y;
tween(game, {
x: originalX + shakeIntensity
}, {
duration: 100,
onFinish: function onFinish() {
tween(game, {
x: originalX - shakeIntensity
}, {
duration: 100,
onFinish: function onFinish() {
tween(game, {
x: originalX
}, {
duration: 100
});
}
});
}
});
} else if (currentCombo >= 2) {
comboMessage = "Great!";
comboColor = 0x45B7D1;
}
if (comboMessage !== "") {
var comboX = 2048 / 2;
var comboY = GRID_START_Y + GRID_SIZE * CELL_SIZE / 2;
var comboText = new ComboText(comboMessage, comboX, comboY, comboColor);
comboTexts.push(comboText);
game.addChild(comboText);
}
// Remove candies after animation
LK.setTimeout(function () {
for (var i = 0; i < allMatches.length; i++) {
allMatches[i].destroy();
}
applyGravity();
}, 250);
}
function applyGravity() {
var needsGravity = false;
// Apply gravity physics - make candies fall to fill empty spaces
for (var x = 0; x < GRID_SIZE; x++) {
// Collect all candies in this column that are not null
var candiesInColumn = [];
for (var y = 0; y < GRID_SIZE; y++) {
if (gameGrid[x][y] !== null) {
candiesInColumn.push({
candy: gameGrid[x][y],
originalY: y
});
}
gameGrid[x][y] = null; // Clear the column
}
// Place candies back starting from bottom
var newY = GRID_SIZE - 1;
for (var i = candiesInColumn.length - 1; i >= 0; i--) {
var candyData = candiesInColumn[i];
var candy = candyData.candy;
var originalY = candyData.originalY;
gameGrid[x][newY] = candy;
// Immediately update grid position to prevent overlaps
candy.gridX = x;
candy.gridY = newY;
// Check if candy needs to fall
if (newY !== originalY) {
var targetY = GRID_START_Y + newY * CELL_SIZE + CELL_SIZE / 2;
candy.isAnimating = true;
animatingCandies++;
tween(candy, {
y: targetY
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
candy.isAnimating = false;
animatingCandies--;
}
});
needsGravity = true;
} else {
// Ensure position is correct even if not animating
candy.x = GRID_START_X + x * CELL_SIZE + CELL_SIZE / 2;
candy.y = GRID_START_Y + newY * CELL_SIZE + CELL_SIZE / 2;
}
newY--;
}
// Fill remaining empty spaces at top with new candies
for (var y = 0; y < GRID_SIZE; y++) {
if (gameGrid[x][y] === null) {
var newCandy = createCandy(x, y, getRandomCandyType());
newCandy.y = GRID_START_Y - CELL_SIZE + CELL_SIZE / 2;
newCandy.isAnimating = true;
animatingCandies++;
var targetY = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
tween(newCandy, {
y: targetY
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
newCandy.isAnimating = false;
animatingCandies--;
}
});
needsGravity = true;
}
}
}
if (needsGravity) {
LK.getSound('cascade').play();
LK.setTimeout(function () {
checkForNewMatches();
}, 400);
}
}
function checkForNewMatches() {
if (animatingCandies > 0) {
LK.setTimeout(checkForNewMatches, 100);
return;
}
var matchGroups = findMatches();
if (matchGroups.length > 0) {
removeMatches(matchGroups);
} else {
isProcessing = false;
currentCombo = 0; // Reset combo counter when no more matches
}
}
function findBestMove() {
var bestMove = null;
var bestScore = 0;
// Check all possible moves
for (var x1 = 0; x1 < GRID_SIZE; x1++) {
for (var y1 = 0; y1 < GRID_SIZE; y1++) {
var candy1 = gameGrid[x1][y1];
if (!candy1) continue;
// Check adjacent positions
var adjacentPositions = [{
x: x1 - 1,
y: y1
},
// left
{
x: x1 + 1,
y: y1
},
// right
{
x: x1,
y: y1 - 1
},
// up
{
x: x1,
y: y1 + 1
} // down
];
for (var i = 0; i < adjacentPositions.length; i++) {
var pos = adjacentPositions[i];
if (pos.x < 0 || pos.x >= GRID_SIZE || pos.y < 0 || pos.y >= GRID_SIZE) continue;
var candy2 = gameGrid[pos.x][pos.y];
if (!candy2) continue;
// Temporarily swap to check for matches
var tempX1 = candy1.gridX,
tempY1 = candy1.gridY;
var tempX2 = candy2.gridX,
tempY2 = candy2.gridY;
gameGrid[tempX1][tempY1] = candy2;
gameGrid[tempX2][tempY2] = candy1;
candy1.gridX = tempX2;
candy1.gridY = tempY2;
candy2.gridX = tempX1;
candy2.gridY = tempY1;
var matchGroups = findMatches();
var moveScore = 0;
for (var g = 0; g < matchGroups.length; g++) {
var groupSize = Math.min(matchGroups[g].length, 6);
if (groupSize === 3) moveScore += 50;else if (groupSize === 4) moveScore += 150;else if (groupSize === 5) moveScore += 200;else if (groupSize >= 6) moveScore += 300;
}
// Revert the swap
gameGrid[tempX1][tempY1] = candy1;
gameGrid[tempX2][tempY2] = candy2;
candy1.gridX = tempX1;
candy1.gridY = tempY1;
candy2.gridX = tempX2;
candy2.gridY = tempY2;
if (moveScore > bestScore) {
bestScore = moveScore;
bestMove = {
candy1: candy1,
candy2: candy2,
score: moveScore
};
}
}
}
}
return bestMove;
}
function showHintArrow(candy1, candy2) {
// Clear existing hint arrows
clearHintArrows();
// Create arrow from candy1 to candy2
var arrow = new Container();
var arrowBody = LK.getAsset('gridCell', {
anchorX: 0,
anchorY: 0.5
});
arrowBody.scaleX = 0.8;
arrowBody.scaleY = 0.1;
arrowBody.tint = 0xFFFF00;
arrow.addChild(arrowBody);
var arrowHead = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
arrowHead.scaleX = 0.15;
arrowHead.scaleY = 0.15;
arrowHead.tint = 0xFFFF00;
arrowHead.rotation = Math.PI / 4; // 45 degrees
arrow.addChild(arrowHead);
// Position arrow between the two candies
var midX = (candy1.x + candy2.x) / 2;
var midY = (candy1.y + candy2.y) / 2;
arrow.x = midX;
arrow.y = midY;
// Calculate angle from candy1 to candy2
var dx = candy2.x - candy1.x;
var dy = candy2.y - candy1.y;
var angle = Math.atan2(dy, dx);
arrow.rotation = angle;
// Position arrow body and head
arrowBody.x = -80;
arrowHead.x = 80;
// Add pulsing animation
arrow.alpha = 0;
game.addChild(arrow);
hintArrows.push(arrow);
tween(arrow, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Pulse animation
function pulseArrow() {
tween(arrow, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(arrow, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (hintArrows.indexOf(arrow) !== -1) {
pulseArrow();
}
}
});
}
});
}
pulseArrow();
}
});
// Auto-hide hint after 5 seconds
LK.setTimeout(function () {
clearHintArrows();
}, 5000);
}
function clearHintArrows() {
for (var i = hintArrows.length - 1; i >= 0; i--) {
hintArrows[i].destroy();
}
hintArrows = [];
}
function checkGameState() {
// Endless game - no win/lose conditions
}
function processMove(candy1, candy2) {
if (isProcessing || !candy1 || !candy2 || candy1 === candy2) return false;
if (!areAdjacent(candy1, candy2)) return false;
isProcessing = true;
// Endless game - no move limit
// Temporarily swap to check for matches
var tempX1 = candy1.gridX,
tempY1 = candy1.gridY;
var tempX2 = candy2.gridX,
tempY2 = candy2.gridY;
gameGrid[tempX1][tempY1] = candy2;
gameGrid[tempX2][tempY2] = candy1;
candy1.gridX = tempX2;
candy1.gridY = tempY2;
candy2.gridX = tempX1;
candy2.gridY = tempY1;
var matchGroups = findMatches();
if (matchGroups.length > 0) {
// Valid move - perform the swap animation
swapCandies(candy2, candy1); // Swap back positions for animation
LK.setTimeout(function () {
removeMatches(matchGroups);
}, 350);
} else {
// Invalid move - revert
gameGrid[tempX1][tempY1] = candy1;
gameGrid[tempX2][tempY2] = candy2;
candy1.gridX = tempX1;
candy1.gridY = tempY1;
candy2.gridX = tempX2;
candy2.gridY = tempY2;
// Animate back to original positions
swapCandies(candy1, candy2);
LK.setTimeout(function () {
isProcessing = false;
}, 350);
// Endless game - no move limit
}
return true;
}
game.down = function (x, y, obj) {
if (gameState !== 'game') return;
if (isProcessing) return;
// Check if a power-up is selected
if (selectedPowerUp) {
var candy = getCandyAt(x, y);
if (!candy) {
selectedPowerUp = null;
return;
}
if (selectedPowerUp === 'rowCleaner' && score >= rowCleanerCost) {
// Clear entire row
score -= rowCleanerCost;
scoreText.setText('Score: ' + score);
var row = candy.gridY;
var clearedCandies = [];
for (var x = 0; x < GRID_SIZE; x++) {
if (gameGrid[x][row]) {
clearedCandies.push(gameGrid[x][row]);
gameGrid[x][row] = null;
}
}
// Animate cleared candies
for (var i = 0; i < clearedCandies.length; i++) {
clearedCandies[i].markForRemoval();
}
LK.setTimeout(function () {
for (var i = 0; i < clearedCandies.length; i++) {
clearedCandies[i].destroy();
}
applyGravity();
}, 250);
selectedPowerUp = null;
return;
}
if (selectedPowerUp === 'colorChanger' && score >= colorChangerCost) {
// Change candy color to random type
score -= colorChangerCost;
scoreText.setText('Score: ' + score);
var newType = getRandomCandyType();
var oldCandy = candy;
var x = oldCandy.gridX;
var y = oldCandy.gridY;
// Remove old candy
oldCandy.destroy();
// Create new candy with different type
var newCandy = createCandy(x, y, newType);
// Flash effect
tween(newCandy, {
alpha: 0.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(newCandy, {
alpha: 1
}, {
duration: 100
});
}
});
selectedPowerUp = null;
return;
}
if (selectedPowerUp === 'clearAll' && score >= clearAllCost) {
// Clear all candies from the grid
score -= clearAllCost;
score += 5000; // Bonus points
scoreText.setText('Score: ' + score);
var allCandies = [];
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (gameGrid[x][y]) {
allCandies.push(gameGrid[x][y]);
gameGrid[x][y] = null;
}
}
}
// Animate all candies removal
for (var i = 0; i < allCandies.length; i++) {
allCandies[i].markForRemoval();
}
// Create spectacular particle effects
for (var i = 0; i < allCandies.length; i++) {
var candy = allCandies[i];
var candyColors = [0xff6b6b, 0x4ecdc4, 0x45b7d1, 0xf9ca24, 0xf0932b, 0xeb4d4b];
var particleColor = candyColors[candy.candyType - 1] || 0xffffff;
// Create more particles for spectacular effect
var particleCount = Math.floor(Math.random() * 8) + 12;
for (var p = 0; p < particleCount; p++) {
var particle = new Particle(particleColor, candy.x, candy.y);
particles.push(particle);
game.addChild(particle);
}
}
// Screen flash effect
LK.effects.flashScreen(0xFFFFFF, 500);
// Remove candies and refill grid
LK.setTimeout(function () {
for (var i = 0; i < allCandies.length; i++) {
allCandies[i].destroy();
}
applyGravity();
}, 250);
selectedPowerUp = null;
return;
}
selectedPowerUp = null;
return;
}
var candy = getCandyAt(x, y);
if (!candy) return;
if (selectedCandy) {
if (selectedCandy === candy) {
// Deselect same candy
tween(selectedCandy, {
scaleX: 1,
scaleY: 1
}, {
duration: 150
});
selectedCandy = null;
} else if (areAdjacent(selectedCandy, candy)) {
// Try to make move if candies are adjacent
var success = processMove(selectedCandy, candy);
if (success) {
tween(selectedCandy, {
scaleX: 1,
scaleY: 1
}, {
duration: 150
});
selectedCandy = null;
}
} else {
// Deselect current candy and select new candy
tween(selectedCandy, {
scaleX: 1,
scaleY: 1
}, {
duration: 150
});
selectedCandy = candy;
tween(candy, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 150
});
}
} else {
// Select candy
selectedCandy = candy;
tween(candy, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 150
});
}
};
// Create menu button (hamburger style with candy theme)
var menuButton = null;
function createPowerUpButtons() {
// Calculate position below coffee cup
var coffeeY = GRID_START_Y + GRID_SIZE * CELL_SIZE + 150;
var powerUpStartY = coffeeY + 200;
// Row Cleaner Button
rowCleanerButton = new Container();
var rowCleanerBg = LK.getAsset('powerupButton', {
anchorX: 0.5,
anchorY: 0.5
});
rowCleanerBg.x = 0;
rowCleanerBg.y = 0;
rowCleanerBg.tint = 0xFF6B6B;
rowCleanerButton.addChild(rowCleanerBg);
var rowCleanerIcon = LK.getAsset('rowCleaner', {
anchorX: 0.5,
anchorY: 0.5
});
rowCleanerIcon.x = 0;
rowCleanerIcon.y = -30;
rowCleanerButton.addChild(rowCleanerIcon);
// Progress bar background for row cleaner
var rowCleanerProgressBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
rowCleanerProgressBg.x = 0;
rowCleanerProgressBg.y = 50;
rowCleanerProgressBg.scaleX = 0.6;
rowCleanerProgressBg.scaleY = 0.15;
rowCleanerProgressBg.tint = 0x000000;
rowCleanerProgressBg.alpha = 0.3;
rowCleanerButton.addChild(rowCleanerProgressBg);
// Progress bar fill for row cleaner
var rowCleanerProgressFill = LK.getAsset('gridCell', {
anchorX: 0,
anchorY: 0.5
});
rowCleanerProgressFill.x = -60;
rowCleanerProgressFill.y = 50;
rowCleanerProgressFill.scaleX = 0;
rowCleanerProgressFill.scaleY = 0.15;
rowCleanerProgressFill.tint = 0x00FF00;
rowCleanerButton.addChild(rowCleanerProgressFill);
rowCleanerButton.progressFill = rowCleanerProgressFill;
var rowCleanerText = new Text2('2000', {
size: 40,
fill: 0xFFFFFF
});
rowCleanerText.anchor.set(0.5, 0.5);
rowCleanerText.x = 0;
rowCleanerText.y = 10;
rowCleanerButton.addChild(rowCleanerText);
var rowCleanerDesc = new Text2('Clear Row', {
size: 30,
fill: 0xFFFFFF
});
rowCleanerDesc.anchor.set(0.5, 0.5);
rowCleanerDesc.x = 0;
rowCleanerDesc.y = 40;
rowCleanerButton.addChild(rowCleanerDesc);
rowCleanerButton.x = 2048 / 2 - 200;
rowCleanerButton.y = powerUpStartY;
// Color Changer Button
colorChangerButton = new Container();
var colorChangerBg = LK.getAsset('powerupButton', {
anchorX: 0.5,
anchorY: 0.5
});
colorChangerBg.x = 0;
colorChangerBg.y = 0;
colorChangerBg.tint = 0xF9CA24;
colorChangerButton.addChild(colorChangerBg);
var colorChangerIcon = LK.getAsset('colorChanger', {
anchorX: 0.5,
anchorY: 0.5
});
colorChangerIcon.x = 0;
colorChangerIcon.y = -30;
colorChangerButton.addChild(colorChangerIcon);
// Progress bar background for color changer
var colorChangerProgressBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
colorChangerProgressBg.x = 0;
colorChangerProgressBg.y = 50;
colorChangerProgressBg.scaleX = 0.6;
colorChangerProgressBg.scaleY = 0.15;
colorChangerProgressBg.tint = 0x000000;
colorChangerProgressBg.alpha = 0.3;
colorChangerButton.addChild(colorChangerProgressBg);
// Progress bar fill for color changer
var colorChangerProgressFill = LK.getAsset('gridCell', {
anchorX: 0,
anchorY: 0.5
});
colorChangerProgressFill.x = -60;
colorChangerProgressFill.y = 50;
colorChangerProgressFill.scaleX = 0;
colorChangerProgressFill.scaleY = 0.15;
colorChangerProgressFill.tint = 0x00FF00;
colorChangerButton.addChild(colorChangerProgressFill);
colorChangerButton.progressFill = colorChangerProgressFill;
var colorChangerText = new Text2('500', {
size: 40,
fill: 0xFFFFFF
});
colorChangerText.anchor.set(0.5, 0.5);
colorChangerText.x = 0;
colorChangerText.y = 10;
colorChangerButton.addChild(colorChangerText);
var colorChangerDesc = new Text2('Change Color', {
size: 30,
fill: 0xFFFFFF
});
colorChangerDesc.anchor.set(0.5, 0.5);
colorChangerDesc.x = 0;
colorChangerDesc.y = 40;
colorChangerButton.addChild(colorChangerDesc);
colorChangerButton.x = 2048 / 2;
colorChangerButton.y = powerUpStartY;
// Clear All Button
clearAllButton = new Container();
var clearAllBg = LK.getAsset('powerupButton', {
anchorX: 0.5,
anchorY: 0.5
});
clearAllBg.x = 0;
clearAllBg.y = 0;
clearAllBg.tint = 0x9B59B6;
clearAllButton.addChild(clearAllBg);
var clearAllIcon = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
clearAllIcon.scaleX = 0.4;
clearAllIcon.scaleY = 0.4;
clearAllIcon.x = 0;
clearAllIcon.y = -30;
clearAllButton.addChild(clearAllIcon);
// Progress bar background for clear all
var clearAllProgressBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
clearAllProgressBg.x = 0;
clearAllProgressBg.y = 50;
clearAllProgressBg.scaleX = 0.6;
clearAllProgressBg.scaleY = 0.15;
clearAllProgressBg.tint = 0x000000;
clearAllProgressBg.alpha = 0.3;
clearAllButton.addChild(clearAllProgressBg);
// Progress bar fill for clear all
var clearAllProgressFill = LK.getAsset('gridCell', {
anchorX: 0,
anchorY: 0.5
});
clearAllProgressFill.x = -60;
clearAllProgressFill.y = 50;
clearAllProgressFill.scaleX = 0;
clearAllProgressFill.scaleY = 0.15;
clearAllProgressFill.tint = 0x00FF00;
clearAllButton.addChild(clearAllProgressFill);
clearAllButton.progressFill = clearAllProgressFill;
var clearAllText = new Text2('7000', {
size: 40,
fill: 0xFFFFFF
});
clearAllText.anchor.set(0.5, 0.5);
clearAllText.x = 0;
clearAllText.y = 10;
clearAllButton.addChild(clearAllText);
var clearAllDesc = new Text2('Clear All', {
size: 30,
fill: 0xFFFFFF
});
clearAllDesc.anchor.set(0.5, 0.5);
clearAllDesc.x = 0;
clearAllDesc.y = 40;
clearAllButton.addChild(clearAllDesc);
clearAllButton.x = 2048 / 2 + 200;
clearAllButton.y = powerUpStartY;
// Add click handlers
// Hint Button
var hintButton = new Container();
var hintBg = LK.getAsset('powerupButton', {
anchorX: 0.5,
anchorY: 0.5
});
hintBg.x = 0;
hintBg.y = 0;
hintBg.tint = 0x45B7D1;
hintButton.addChild(hintBg);
var hintIcon = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
hintIcon.x = 0;
hintIcon.y = -30;
hintIcon.scaleX = 0.25;
hintIcon.scaleY = 0.25;
hintIcon.tint = 0xFFFFFF;
hintButton.addChild(hintIcon);
// Progress bar background for hint
var hintProgressBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
hintProgressBg.x = 0;
hintProgressBg.y = 50;
hintProgressBg.scaleX = 0.6;
hintProgressBg.scaleY = 0.15;
hintProgressBg.tint = 0x000000;
hintProgressBg.alpha = 0.3;
hintButton.addChild(hintProgressBg);
// Progress bar fill for hint
var hintProgressFill = LK.getAsset('gridCell', {
anchorX: 0,
anchorY: 0.5
});
hintProgressFill.x = -60;
hintProgressFill.y = 50;
hintProgressFill.scaleX = 0;
hintProgressFill.scaleY = 0.15;
hintProgressFill.tint = 0x00FF00;
hintButton.addChild(hintProgressFill);
hintButton.progressFill = hintProgressFill;
var hintText = new Text2('4000', {
size: 40,
fill: 0xFFFFFF
});
hintText.anchor.set(0.5, 0.5);
hintText.x = 0;
hintText.y = 10;
hintButton.addChild(hintText);
var hintDesc = new Text2('Hint', {
size: 30,
fill: 0xFFFFFF
});
hintDesc.anchor.set(0.5, 0.5);
hintDesc.x = 0;
hintDesc.y = 40;
hintButton.addChild(hintDesc);
hintButton.x = 2048 / 2 - 400;
hintButton.y = powerUpStartY;
rowCleanerButton.down = function (x, y, obj) {
if (score >= rowCleanerCost) {
selectedPowerUp = 'rowCleaner';
// Visual feedback
tween(rowCleanerBg, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(rowCleanerBg, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
}
};
colorChangerButton.down = function (x, y, obj) {
if (score >= colorChangerCost) {
selectedPowerUp = 'colorChanger';
// Visual feedback
tween(colorChangerBg, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(colorChangerBg, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
}
};
// Add hint button click handler
hintButton.down = function (x, y, obj) {
if (score >= 4000) {
score -= 4000;
scoreText.setText('Score: ' + score);
// Find best move
var bestMove = findBestMove();
if (bestMove) {
showHintArrow(bestMove.candy1, bestMove.candy2);
}
// Visual feedback
tween(hintBg, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(hintBg, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
}
};
// Add clear all button click handler
clearAllButton.down = function (x, y, obj) {
if (score >= clearAllCost) {
// Execute clear all immediately instead of setting selectedPowerUp
score -= clearAllCost;
score += 5000; // Bonus points
scoreText.setText('Score: ' + score);
var allCandies = [];
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (gameGrid[x][y]) {
allCandies.push(gameGrid[x][y]);
gameGrid[x][y] = null;
}
}
}
// Animate all candies removal
for (var i = 0; i < allCandies.length; i++) {
allCandies[i].markForRemoval();
}
// Create spectacular particle effects
for (var i = 0; i < allCandies.length; i++) {
var candy = allCandies[i];
var candyColors = [0xff6b6b, 0x4ecdc4, 0x45b7d1, 0xf9ca24, 0xf0932b, 0xeb4d4b];
var particleColor = candyColors[candy.candyType - 1] || 0xffffff;
// Create more particles for spectacular effect
var particleCount = Math.floor(Math.random() * 8) + 12;
for (var p = 0; p < particleCount; p++) {
var particle = new Particle(particleColor, candy.x, candy.y);
particles.push(particle);
game.addChild(particle);
}
}
// Screen flash effect
LK.effects.flashScreen(0xFFFFFF, 500);
// Remove candies and refill grid
LK.setTimeout(function () {
for (var i = 0; i < allCandies.length; i++) {
allCandies[i].destroy();
}
applyGravity();
}, 250);
// Visual feedback
tween(clearAllBg, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(clearAllBg, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
}
};
game.addChild(hintButton);
game.addChild(rowCleanerButton);
game.addChild(colorChangerButton);
game.addChild(clearAllButton);
gameElements.push(hintButton);
gameElements.push(rowCleanerButton);
gameElements.push(colorChangerButton);
gameElements.push(clearAllButton);
}
// Menu button functionality removed
// Coffee cup will be created when game starts
// Initialize sound settings from storage
try {
var storedSoundSetting = storage.soundEnabled;
if (storedSoundSetting === null || storedSoundSetting === undefined) {
soundEnabled = true;
storage.soundEnabled = soundEnabled;
} else {
soundEnabled = storedSoundSetting;
}
} catch (e) {
// Fallback if storage is not available
soundEnabled = true;
}
// Start background music if sound is enabled
if (soundEnabled) {
LK.playMusic('rahat');
}
// Show main menu instead of initializing game immediately
showMainMenu();
game.update = function () {
// Update menu elements when in menu state
if (gameState === 'menu' && mainMenu) {
mainMenu.update();
}
// Update particles during game
for (var i = particles.length - 1; i >= 0; i--) {
particles[i].update();
}
// Combo texts are automatically managed by their own animations
// No manual update needed as they self-destruct
// Background is now static image - no animation needed
// Update power-up button states and progress bars based on score
if (gameState === 'game' && hintButton && rowCleanerButton && colorChangerButton && clearAllButton) {
// Update hint button and progress bar
var hintProgress = Math.min(score / hintCost, 1);
if (hintButton.progressFill) {
tween(hintButton.progressFill, {
scaleX: hintProgress * 0.6
}, {
duration: 200,
easing: tween.easeOut
});
// Change color based on availability
var fillColor = score >= hintCost ? 0x00FF00 : 0xFFAA00;
tween(hintButton.progressFill, {
tint: fillColor
}, {
duration: 200
});
}
if (score >= hintCost) {
hintButton.alpha = 1;
} else {
hintButton.alpha = 0.8;
}
// Update row cleaner button and progress bar
var rowCleanerProgress = Math.min(score / rowCleanerCost, 1);
if (rowCleanerButton.progressFill) {
tween(rowCleanerButton.progressFill, {
scaleX: rowCleanerProgress * 0.6
}, {
duration: 200,
easing: tween.easeOut
});
// Change color based on availability
var fillColor = score >= rowCleanerCost ? 0x00FF00 : 0xFFAA00;
tween(rowCleanerButton.progressFill, {
tint: fillColor
}, {
duration: 200
});
}
if (score >= rowCleanerCost) {
rowCleanerButton.alpha = 1;
} else {
rowCleanerButton.alpha = 0.8;
}
// Update color changer button and progress bar
var colorChangerProgress = Math.min(score / colorChangerCost, 1);
if (colorChangerButton.progressFill) {
tween(colorChangerButton.progressFill, {
scaleX: colorChangerProgress * 0.6
}, {
duration: 200,
easing: tween.easeOut
});
// Change color based on availability
var fillColor = score >= colorChangerCost ? 0x00FF00 : 0xFFAA00;
tween(colorChangerButton.progressFill, {
tint: fillColor
}, {
duration: 200
});
}
if (score >= colorChangerCost) {
colorChangerButton.alpha = 1;
} else {
colorChangerButton.alpha = 0.8;
}
// Update clear all button and progress bar
var clearAllProgress = Math.min(score / clearAllCost, 1);
if (clearAllButton.progressFill) {
tween(clearAllButton.progressFill, {
scaleX: clearAllProgress * 0.6
}, {
duration: 200,
easing: tween.easeOut
});
// Change color based on availability
var fillColor = score >= clearAllCost ? 0x00FF00 : 0xFFAA00;
tween(clearAllButton.progressFill, {
tint: fillColor
}, {
duration: 200
});
}
if (score >= clearAllCost) {
clearAllButton.alpha = 1;
} else {
clearAllButton.alpha = 0.8;
}
}
// Only run game physics during game state
if (gameState === 'game') {
// Add sparkle effects to random candies
if (LK.ticks % 180 === 0) {
// Every 3 seconds at 60fps
// Pick a random candy to sparkle
var validCandies = [];
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (gameGrid[x][y] && !gameGrid[x][y].isAnimating && !gameGrid[x][y].isMatched) {
validCandies.push(gameGrid[x][y]);
}
}
}
if (validCandies.length > 0) {
var randomCandy = validCandies[Math.floor(Math.random() * validCandies.length)];
randomCandy.sparkle();
}
}
// Continuously check for physics updates when not processing moves
if (!isProcessing && animatingCandies === 0) {
// Check if any candies need to fall due to physics
var needsPhysicsUpdate = false;
for (var x = 0; x < GRID_SIZE && !needsPhysicsUpdate; x++) {
// Check entire column from bottom to top for any candy that should fall
for (var y = GRID_SIZE - 1; y >= 0; y--) {
if (gameGrid[x][y] === null) {
// Found empty space, check if there's a candy above it
for (var checkY = y - 1; checkY >= 0; checkY--) {
if (gameGrid[x][checkY] !== null) {
needsPhysicsUpdate = true;
break;
}
}
if (needsPhysicsUpdate) break;
}
}
}
if (needsPhysicsUpdate) {
applyGravity();
}
}
}
};
gerçekçi bir şeker. yuvarlak bir şeker ve kırmızı renk. In-Game asset. 2d. High contrast. No shadows
gerçekçi bir şeker. yuvarlak bir şeker ve pembe renk.. In-Game asset. 2d. High contrast. No shadows
gerçekçi bir şeker. yuvarlak bir şeker ve koyu mavi renk. aynı candy2 deki gibi In-Game asset. 2d. High contrast. No shadows
gerçekçi bir şeker. yuvarlak bir şeker ve sarı renk. aynı candy2 deki gibi olsun. In-Game asset. 2d. High contrast. No shadows
gerçekçi bir şeker. yuvarlak bir şeker ve kahverengi renk. aynı candy2 deki gibi olsun. In-Game asset. 2d. High contrast. No shadows
gerçekçi bir şeker. yuvarlak bir şeker ve yeşil renk. aynı candy2 deki gibi olsun. In-Game asset. 2d. High contrast. No shadows
a coffee. In-Game asset. 2d. High contrast. No shadows
Bir satırda oyundaki tüm şekerler yan yana dizilsin. In-Game asset. 2d. High contrast. No shadows
Yuvarlak bir şeker ve üstünde ona ucu değen sağ üstte bir kalem. In-Game asset. 2d. High contrast. No shadows