User prompt
iç içe giriyor şekerler onu düzelt
User prompt
olmuyor hala olmuyor
User prompt
olmamış bak o boşluğun üstündeki yeşil şeker düşmüyor
User prompt
fizik ekle oyuna arada boşluk kalmasın şekerlerin altında boşluk var ise şekerler o boşluğa düşsün ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
sürekli rahat music çalsın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
arada bir şekerlere dokunamıyorumbu bir bug mu
User prompt
kahveye dokununca coffee sesi çalsın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
tekrardan ekle ama 1 tane assets şeklinde olsun ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
coffee cup kaldır
User prompt
tıklayınca dolan o şeyi kaldır sadece sallansın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
tamam kahve içme animasyonu ekleme ama tıklayınca sallansın çok az ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
kahveyi biraz daha alta alsak
User prompt
sakin bir müzik arkaya. o şekerlerin bulunduğu karenin altına bir kahve koy ve kahveye tıkladıkça içebilelim ve kahve içme sesi ekle tıklayınca ona özelde animasyon koy ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
yazılar vs. hepsi türkçe olsun
User prompt
leveli geçtiğimizde yeaahh soundu çalsın
User prompt
her şeker kaydırdığımızda boing soundu çalsın
Code edit (1 edits merged)
Please save this source code
User prompt
Sweet Match Cascade
Initial prompt
candy crush game
/**** * 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