Code edit (2 edits merged)
Please save this source code
Code edit (6 edits merged)
Please save this source code
User prompt
after `var nbNotDestroyedGems = 0;` count remaining gem in board
User prompt
after `var nbDestroyedGems = 0;` count the gems that are in status Destroyed
Code edit (1 edits merged)
Please save this source code
User prompt
in animateWitchSlideIn begining, browse gems to destroy them
Code edit (4 edits merged)
Please save this source code
User prompt
stop fillEmptySpaces and animations within it when time is up
Code edit (6 edits merged)
Please save this source code
User prompt
in animateWitchSlideIn, move the scoreText progressively to the center of the screens and make it 4 times bigger
Code edit (1 edits merged)
Please save this source code
/**** * Classes ****/ // Board class var Board = Container.expand(function () { var self = Container.call(this); // Function to shuffle gems around randomly Board.prototype.shuffleGems = function () { console.log("shuffleGems"); self.isShuffling = true; // Removed usage of Set for compatibility for (var i = this.gems.length - 1; i > 0; i--) { this.gems[i].newPosition = false; } for (var i = this.gems.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); // Swap the gems var tempNewPosition = this.gems[i].newPosition || { x: this.gems[i].x, y: this.gems[i].y }; this.gems[i].newPosition = this.gems[j].newPosition || { x: this.gems[j].x, y: this.gems[j].y }; this.gems[j].newPosition = tempNewPosition; } // The rest of your method remains unchanged function animateGemToPosition(gem, x, y) { var animationDuration = 1000; // Duration of the animation in milliseconds var startX = gem.x; var startY = gem.y; var deltaX = x - startX; var deltaY = y - startY; var startTime = Date.now(); var animate = function animate() { var now = Date.now(); var progress = Math.min(1, (now - startTime) / animationDuration); gem.x = startX + deltaX * progress; gem.y = startY + deltaY * progress; if (progress < 1) { LK.setTimeout(animate, 16); // Aim for roughly 60fps } else { gem.x = x; gem.y = y; self.isShuffling = false; } }; LK.setTimeout(animate, 16); } // Update the positions of the shuffled gems and ensure they have the correct new position in the gems array var newGemsArray = new Array(this.gems.length); this.gems.forEach(function (gem, index) { if (gem.newPosition) { var newPositionIndex = this.gems.findIndex(function (g) { return g.x === gem.newPosition.x && g.y === gem.newPosition.y; }); var aNewPosition = this.snapToGrid(gem.newPosition.x, gem.newPosition.y); animateGemToPosition(gem, aNewPosition.x, aNewPosition.y); newGemsArray[newPositionIndex] = gem; } }.bind(this)); this.gems = newGemsArray.filter(function (g) { return g !== undefined; }); LK.setTimeout(self.checkForMatches, 1000); }; // Method to round or snap any position to the nearest position in the grid made by the 6x8 gems this.snapToGrid = function (x, y) { // Ensure there is at least one gem in the array before accessing its properties var margin = 10; var boardWidth = game.width * .9; var boardHeight = game.height * .9; var gemsPerRow = 6; var gemsPerColumn = 8; var totalMarginWidth = margin * (gemsPerRow + 1); var totalMarginHeight = margin * (gemsPerColumn + 1); var availableWidth = boardWidth - totalMarginWidth; var availableHeight = boardHeight - totalMarginHeight; var scaledGemSize = Math.min(availableWidth / gemsPerRow, availableHeight / gemsPerColumn); var xOffset = (game.width - boardWidth) / 2 + scaledGemSize / 2; var yOffset = (game.height - boardHeight) / 2 + scaledGemSize / 2 + 80; var columnWidth = (boardWidth - margin) / 6; var rowHeight = (boardHeight - margin) / 8; var snappedX = Math.round((x - xOffset) / columnWidth) * columnWidth + xOffset; var snappedY = Math.round((y - yOffset) / rowHeight) * rowHeight + yOffset; return { x: snappedX, y: snappedY }; }; // Method to show a hint for a possible match this.showHint = function () { if (!isPlaying) { return; } console.log('showHint function started'); var possibleMatches = this.checkIfAnyMoveCausesMatch(); if (possibleMatches.length > 0) { var animateMove = function animateMove(repeatCount) { if (move.gem.isUsed) { // Start fade-out effect for hint overlay var fadeOutDuration = 500; // Fade out over 500ms var startTime = Date.now(); var fadeStep = function fadeStep() { var currentTime = Date.now(); var progress = (currentTime - startTime) / fadeOutDuration; hintOverlay.alpha = 1 - progress; // Fade out effect if (progress < 1) { LK.setTimeout(fadeStep, 16); // Continue fading } else { hintOverlay.destroy(); // Destroy after faded out } }; fadeStep(); return; } var totalDuration = 1000; // Half a second for each back and forth movement var repeatLimit = 1; // Repeat the animation three times var animationCount = 0; var startTime = Date.now(); var animateStep = function animateStep() { if (move.gem.isUsed || !hintOverlay) { if (hintOverlay) { hintOverlay.destroy(); } return; } var currentTime = Date.now(); var progress = (currentTime - startTime) / totalDuration; var waveProgress = (Math.sin(progress * Math.PI * 2) + 1) / 2; // Adjusted to ensure it never goes below zero hintOverlay.x = move.gemStartPosition.x + moveDirection.dx * moveDistance * waveProgress; hintOverlay.y = move.gemStartPosition.y + moveDirection.dy * moveDistance * waveProgress; if (progress >= 1) { animationCount++; if (animationCount < repeatLimit) { startTime = Date.now(); // Reset start time for the next cycle animateStep(); // Continue animation } else { hintOverlay.destroy(); } } else { LK.setTimeout(animateStep, 16); // Continue animation } }; animateStep(); }; console.log('Possible matches:', possibleMatches); var move = possibleMatches[0]; var hintOverlay = LK.getAsset('hintOverlay', {}); self.lastHintOverlay = hintOverlay; hintOverlay.anchor.set(0, 0); self.addChild(hintOverlay); hintOverlay.x = move.gem.x; hintOverlay.y = move.gem.y; move.gemStartPosition = { x: move.gem.x, y: move.gem.y }; // Track starting position for animation var moveDirection = move.move || { dx: 0, dy: 0 }; var moveDistance = move.gem.spacing; // Distance to move back and forth var moveDuration = 500; // Duration of each move animateMove(); } else { console.log("no possible matches"); if (!self.fillingEmptySpaces && !self.gemsFalling && !self.isShuffling && !isDragoning) { triggerDragon(); } } }; // Method to find possible matches on the board // Method to find possible matches on the board // Method to find possible matches on the board this.findPossibleMatches = function () { var matches = []; var width = 6; // Board width var height = 8; // Board height for (var i = 0; i < height; i++) { for (var j = 0; j < width; j++) { var currentGem = this.gems[i * width + j]; // Check right and down for potential matches var directions = [{ dx: 1, dy: 0 }, // Right { dx: 0, dy: 1 } // Down ]; directions.forEach(function (dir) { var match = [currentGem]; for (var k = 1; k < 3; k++) { var nextGemX = j + dir.dx * k; var nextGemY = i + dir.dy * k; if (nextGemX < width && nextGemY < height) { var nextGem = this.gems[nextGemY * width + nextGemX]; if (nextGem && currentGem && nextGem.color === currentGem.color) { match.push(nextGem); } else { break; } } } if (match.length >= 3) { // Allows for matches longer than 3 matches.push(match); } }, this); } } return matches; }; // Method to check if moving any gem results in a match this.checkIfAnyMoveCausesMatch = function () { var matches = []; var width = 6; // Board width var height = 8; // Board height // Simulate moving each gem in all four directions and check for matches for (var i = 0; i < height; i++) { for (var j = 0; j < width; j++) { var currentGem = this.gems[i * width + j]; if (!currentGem) { continue; } // Possible moves: up, down, left, right var moves = [{ dx: -1, dy: 0 }, { dx: 1, dy: 0 }, { dx: 0, dy: -1 }, { dx: 0, dy: 1 }]; moves.forEach(function (move) { var newX = j + move.dx; var newY = i + move.dy; // Check if the new position is within the board if (newX >= 0 && newX < width && newY >= 0 && newY < height) { var targetGem = this.findGemByPosition(currentGem.x + currentGem.spacing * move.dx, currentGem.y + currentGem.spacing * move.dy); if (targetGem && this.wouldSwapResultInMatch(currentGem, targetGem)) { matches.push({ gem: currentGem, move: move }); } } }, this); } } return matches; }; // Check if swapping two gems would result in a match this.wouldSwapResultInMatch = function (gemA, gemB) { var gemAIndex = this.gems.indexOf(gemA); var gemBIndex = this.gems.indexOf(gemB); this.gems[gemAIndex] = gemB; this.gems[gemBIndex] = gemA; // Check for matches var matchFound = false; var matchedGems = []; // Check for horizontal matches for (var i = 0; i < 8; i++) { for (var j = 0; j < 6; j++) { // Adjust to allow checks across all columns var gem1 = this.gems[i * 6 + j]; var nowMatchingGems = []; for (var k = j; k < 6; k++) { var nextGem = this.gems[i * 6 + k]; if (nextGem && nextGem.color === gem1.color) { nowMatchingGems.push(nextGem); } else { break; } } if (nowMatchingGems.length >= 3) { matchFound = true; matchedGems = matchedGems.concat(nowMatchingGems.filter(function (gem) { return matchedGems.indexOf(gem) === -1; })); } } } // Check for vertical matches for (var i = 0; i < 6; i++) { for (var j = 0; j < 8; j++) { // Adjust to allow checks across all rows var gem1 = this.gems[j * 6 + i]; var nowMatchingGems = []; for (var k = j; k < 8; k++) { var nextGem = this.gems[k * 6 + i]; if (nextGem && nextGem.color === gem1.color) { nowMatchingGems.push(nextGem); } else { break; } } if (nowMatchingGems.length >= 3) { matchFound = true; matchedGems = matchedGems.concat(nowMatchingGems.filter(function (gem) { return matchedGems.indexOf(gem) === -1; })); } } } // Swap back this.gems[gemAIndex] = gemA; this.gems[gemBIndex] = gemB; return matchFound; }; this.swapGems = function (gem1, gem2) { var gem1Index = this.gems.indexOf(gem1); var gem2Index = this.gems.indexOf(gem2); if (gem1Index !== -1 && gem2Index !== -1) { // Animate swap positions with easing var swapDuration = 150; // Duration in milliseconds var gem1StartPos = { x: gem1.x, y: gem1.y }; if (!gem2) { return; } // Prevent TypeError if gem2 is null var gem2StartPos = { x: gem2.x, y: gem2.y }; gem1.isUsed = true; gem2.isUsed = true; gem1.alpha = 1; gem2.alpha = 1; var startTime = Date.now(); var animateSwap = function animateSwap() { var currentTime = Date.now(); var progress = Math.min(1, (currentTime - startTime) / swapDuration); var easeInOut = progress < 0.5 ? 2 * progress * progress : -1 + (4 - 2 * progress) * progress; gem1.x = gem1StartPos.x + (gem2StartPos.x - gem1StartPos.x) * easeInOut; gem1.y = gem1StartPos.y + (gem2StartPos.y - gem1StartPos.y) * easeInOut; gem2.x = gem2StartPos.x + (gem1StartPos.x - gem2StartPos.x) * easeInOut; gem2.y = gem2StartPos.y + (gem1StartPos.y - gem2StartPos.y) * easeInOut; if (progress < 1) { LK.setTimeout(animateSwap, 16); // Aim for roughly 60fps } else { gem1.isUsed = false; gem2.isUsed = false; var snappedOne = self.snapToGrid(gem1.x, gem1.y); gem1.x = snappedOne.x; gem1.y = snappedOne.y; var snappedOne = self.snapToGrid(gem2.x, gem2.y); gem2.x = snappedOne.x; gem2.y = snappedOne.y; self.checkForMatches(); } }; animateSwap(); // Swap in gems array this.gems[gem1Index] = gem2; this.gems[gem2Index] = gem1; // Check for matches after swap } }; this.faintSwapGems = function (gem1, gem2, firstFaint) { var gem1Index = this.gems.indexOf(gem1); var gem2Index = this.gems.indexOf(gem2); if (gem1Index !== -1 && gem2Index !== -1) { // Animate swap positions with easing var swapDuration = 150; // Duration in milliseconds var gem1StartPos = { x: gem1.x, y: gem1.y }; var gem2StartPos = { x: gem2.x, y: gem2.y }; var startTime = Date.now(); var animateSwap = function animateSwap() { var currentTime = Date.now(); var progress = Math.min(1, (currentTime - startTime) / swapDuration); var easeInOut = progress < 0.5 ? 2 * progress * progress : -1 + (4 - 2 * progress) * progress; gem1.x = gem1StartPos.x + (gem2StartPos.x - gem1StartPos.x) * easeInOut; gem1.y = gem1StartPos.y + (gem2StartPos.y - gem1StartPos.y) * easeInOut; gem2.x = gem2StartPos.x + (gem1StartPos.x - gem2StartPos.x) * easeInOut; gem2.y = gem2StartPos.y + (gem1StartPos.y - gem2StartPos.y) * easeInOut; if (progress < 1) { LK.setTimeout(animateSwap, 16); // Aim for roughly 60fps } else if (firstFaint) { self.faintSwapGems(gem1, gem2); } }; animateSwap(); // Swap in gems array this.gems[gem1Index] = gem2; this.gems[gem2Index] = gem1; } }; // Find a gem by its position this.findGemByPosition = function (x, y, exceptThisGem) { for (var i = 0; i < this.gems.length; i++) { var gem = this.gems[i]; if (gem == exceptThisGem) { continue; } if (gem) { var tolerance = gem.spacing / 2; // Tolerance in pixels for approximate position if (Math.abs(x - gem.x) < tolerance && Math.abs(y - gem.y) < tolerance) { return gem; } } } return null; }; this.fillEmptySpaces = function () { if (!isPlaying) { return; } self.fillingEmptySpaces = true; var _animateGemDown = function animateGemDown(newGem, finalY, initialY) { var snappedOne = self.snapToGrid(newGem.x, finalY); finalY = snappedOne.y; var animationDuration = 250; // Duration in milliseconds var startTime = Date.now(); var animate = function animate() { if (!isPlaying) { return; } var currentTime = Date.now(); var progress = Math.min(1, (currentTime - startTime) / animationDuration); // Apply easing for smoother animation var easedProgress = Math.sin(progress * Math.PI / 2); if (progress < 1) { newGem.y = initialY + (finalY - initialY) * easedProgress; LK.setTimeout(animate, 16); // Aim for roughly 60fps } else { newGem.y = finalY; // Ensure final position is accurate self.fillingEmptySpaces = false; } }; animate(); }; for (var i = 0; i < 8; i++) { for (var j = 0; j < 6; j++) { var index = i * 6 + j; if (!self.gems[index]) { var possibleColors = ['gemBlue', 'gemGreen', 'gemRed', 'gemPurple', 'gemYellow', 'gemOrange', 'gemCyan']; // Filter colors to ensure at least one possible match var colors = possibleColors.filter(function (color) { return true; }, this); var color = colors.length > 0 ? colors[Math.floor(Math.random() * colors.length)] : possibleColors[Math.floor(Math.random() * possibleColors.length)]; var newGem = new Gem(color); // Calculate x and y position for new gems when there are no existing gems to reference var gemSize = 100; var margin = 10; var boardWidth = 1800; // Assuming the board width is known var boardHeight = 2400; // Assuming the board height is known var gemsPerRow = 6; var gemsPerColumn = 8; var totalMarginWidth = margin * (gemsPerRow + 1); var totalMarginHeight = margin * (gemsPerColumn + 1); var availableWidth = boardWidth - totalMarginWidth; var availableHeight = boardHeight - totalMarginHeight; var scaledGemSize = Math.min(availableWidth / gemsPerRow, availableHeight / gemsPerColumn); var xOffset = (2048 - boardWidth) / 2 + scaledGemSize / 2; // Assuming game width is 2048 var yOffset = (2732 - boardHeight) / 2 + scaledGemSize / 2; var snapped = self.snapToGrid(xOffset + (scaledGemSize + margin) * j, yOffset + (scaledGemSize + margin) * i); newGem.x = snapped.x; // Calculate initial y position for animation start var initialY = -gemSize; // Start above the screen to simulate falling into place newGem.y = initialY; // Animate gem to its final position var finalY = snapped.y; _animateGemDown(newGem, finalY, initialY); newGem.spacing = scaledGemSize + margin; newGem.scale.set(scaledGemSize / gemSize); newGem.baseScale = scaledGemSize / gemSize; self.addChild(newGem); self.gems[index] = newGem; self.handleGemClick(newGem); } } } }; self.gems = []; this.handleFallingGems = function () { if (!isPlaying) { return; } console.log("handle Falling gems"); var didFall = false; for (var i = 0; i < 6; i++) { for (var j = 7; j >= 0; j--) { var index = j * 6 + i; if (index >= 0 && index < self.gems.length && !self.gems[index]) { var emptySpaces = 1; for (var k = j - 1; k >= 0; k--) { var aboveIndex = k * 6 + i; if (!self.gems[aboveIndex]) { emptySpaces++; } else { var gemAbove = self.gems[aboveIndex]; var targetIndex = (k + emptySpaces) * 6 + i; self.gems[targetIndex] = gemAbove; self.gems[aboveIndex] = null; // Calculate the new Y position based on the number of empty spaces var margin = 10; var snapped = self.snapToGrid(gemAbove.x, gemAbove.y + gemAbove.spacing * emptySpaces); var newY = snapped.y; // Animate the gem moving to the new position gemAbove.alpha = 1; animateGemToPosition(gemAbove, gemAbove.x, newY); didFall = true; break; } } } } } if (didFall) { self.gemsFalling = true; LK.setTimeout(function () { self.fillEmptySpaces(); LK.setTimeout(function () { self.gemsFalling = false; self.checkForMatches(); }, 250); }, 250); } else { // Trigger fillEmptySpaces even if no gems fell to ensure no gaps are left self.fillEmptySpaces(); LK.setTimeout(function () { self.checkForMatches(); }, 250); } }; function animateGemToPosition(gem, newX, newY) { var fallDuration = 500; // Duration for the gem to fall to its new position var bounceDuration = 300; // Duration for the bounce effect, slightly longer for realism var scaleDuration = 150; // Duration for the scale effect after bouncing var startTime = Date.now(); var animateStep = function animateStep() { var currentTime = Date.now(); var elapsedTime = currentTime - startTime; var progress = elapsedTime / fallDuration; // First, handle the falling animation with a linear or ease-in effect if (progress < 1) { var fallProgress = Math.min(1, progress); // Ensure progress doesn't exceed 1 // Simple linear interpolation for falling gem.y = gem.y + (newY - gem.y) * fallProgress; if (fallProgress < 1) { LK.setTimeout(animateStep, 16); // Continue the fall animation } else { gem.y = newY; gem.isUsed = false; } } }; animateStep(); // Start the animation with the fall } this.handleGemMatched = function (gem) { if (gem.color == goalGemType) { matchedGemCount++; goalTxt.setText(matchedGemCount + "/" + goalGemCount); if (matchedGemCount >= goalGemCount) { LK.getSound('happyWitch').play(); game.timer += 10; timerTxt.setText(game.timer.toString()); stopTimer(); if (isDragoning) { isDragoning = false; if (dragonSpawnTimer) { LK.clearTimeout(dragonSpawnTimer); } } // Show modal pop-up for 10 more seconds var modalContainer = new Container(); LK.gui.center.addChild(modalContainer); var modalBackground = LK.getAsset('goalCompleteBg', {}); modalBackground.anchor.set(.5, .5); modalBackground.alpha = .75; modalContainer.addChild(modalBackground); // Animate scale of the modal container for excitement var scaleStartTime = Date.now(); var scaleDuration = 500; // Scale animation duration in milliseconds var animateScale = function animateScale() { var currentTime = Date.now(); var progress = (currentTime - scaleStartTime) / scaleDuration; var scale = 1 + 0.1 * Math.sin(progress * Math.PI * 2); // Oscillate scale between 1 and 1.1 modalContainer.scale.set(scale); if (progress < 1) { LK.setTimeout(animateScale, 16); } }; animateScale(); // Trigger lots of confetti balls on mission complete for (var i = 0; i < 100; i++) { var confetti = new ConfettiParticle(); confetti.init(Math.random() * game.width, Math.random() * game.height); game.addChild(confetti); } showPastGoalSprite = LK.getAsset(goalGemType, { // Align with the timer's top margin anchorX: .5, // Anchor right for right alignment anchorY: .5 // Anchor top for top alignment }); goalGemType = false; // Add hourglass sprite next to the timer var pastGoalBackground = LK.getAsset('newSpriteId', {}); pastGoalBackground.y = 0; pastGoalBackground.x = -100; pastGoalBackground.anchor.set(0.5, 0.5); // Align with the timer's top margin modalContainer.addChild(pastGoalBackground); pastGoalBackground.alpha = .75; showPastGoalSprite.y = pastGoalBackground.y; showPastGoalSprite.x = pastGoalBackground.x; showPastGoalSprite.anchor.set(.5, 0.5); // Align with the timer's top margin modalContainer.addChild(showPastGoalSprite); showPastGoalSprite.rotation = -.2; var showPastGoalText = new Text2(matchedGemCount + "/" + goalGemCount, { size: 100, weight: 600, fill: "#ffffff", x: 1024, y: 1366, anchorX: 0.5, anchorY: 0.5, dropShadow: true, dropShadowColor: '#000000', dropShadowBlur: 8, dropShadowOffsetX: 4, dropShadowOffsetY: 4, stroke: true, strokeColor: '#000000', strokeThickness: 4 }); showPastGoalText.y = pastGoalBackground.y; showPastGoalText.x = 0; showPastGoalText.anchor.set(0, 0.5); // Align with the timer's top margin modalContainer.addChild(showPastGoalText); var modalInfoText = new Text2('MISSION COMPLETE:', { size: 50, weight: 600, fill: "#ffffff", x: 1024, y: 1366, anchorX: 0.5, anchorY: 0.5, dropShadow: true, dropShadowColor: '#000000', dropShadowBlur: 8, dropShadowOffsetX: 4, dropShadowOffsetY: 4, stroke: true, strokeColor: '#000000', strokeThickness: 2 }); modalInfoText.anchor.set(.5); modalInfoText.y = -100; modalContainer.addChild(modalInfoText); var modalText = new Text2('+10 seconds!', { size: 100, weight: 600, fill: "#ffffff", x: 1024 + 70, // Adjust x position to make space for the hourglass sprite y: 1366, anchorX: 0.5, anchorY: 0.5, dropShadow: true, dropShadowColor: '#000000', dropShadowBlur: 8, dropShadowOffsetX: 4, dropShadowOffsetY: 4, stroke: true, strokeColor: '#000000', strokeThickness: 2 }); modalText.anchor.set(.5); modalText.y = 100; modalContainer.addChild(modalText); // Add hourglass sprite next to the '+10 seconds!' text var hourglassSpriteModal = LK.getAsset('hourglass', { anchorX: .5, anchorY: .5 }); hourglassSpriteModal.x = 1024 - 70; // Position hourglass to the left of the text hourglassSpriteModal.y = 1366; modalContainer.addChild(hourglassSpriteModal); var thumbUpSprite = LK.getAsset('thumbUp', { // Align with the timer's top margin anchorX: .5, // Anchor right for right alignment anchorY: .5 // Anchor top for top alignment }); thumbUpSprite.y = 0; thumbUpSprite.x = -500; thumbUpSprite.anchor.set(.5, 0.5); // Align with the timer's top margin modalContainer.addChild(thumbUpSprite); var thumbUpSprite2 = LK.getAsset('woodLockAcid', { // Align with the timer's top margin anchorX: .5, // Anchor right for right alignment anchorY: .5 // Anchor top for top alignment }); thumbUpSprite2.y = 0; thumbUpSprite2.x = 500; thumbUpSprite2.anchor.set(.5, 0.5); // Align with the timer's top margin modalContainer.addChild(thumbUpSprite2); var modalText = new Text2('+', { size: 120, weight: 600, fill: "#ffffff", x: 1024 + 70, // Adjust x position to make space for the hourglass sprite y: 1366, anchorX: 0.5, anchorY: 0.5, dropShadow: true, dropShadowColor: '#000000', dropShadowBlur: 8, dropShadowOffsetX: 4, dropShadowOffsetY: 4, stroke: true, strokeColor: '#000000', strokeThickness: 2 }); modalText.anchor.set(.5); modalText.x = 400; modalText.y = 0; modalContainer.addChild(modalText); // Automatically remove the modal and background after 2 seconds // Start animation for modal elements var duration = 2000; // 3 seconds for the animation LK.setTimeout(function () { var startTime = Date.now(); var simpleCountdownInterval = LK.setInterval(function () { var currentTime = Date.now(); var progress = (currentTime - startTime) / duration; var moveDistance = 2048; // Move to the right side off-screen modalContainer.x += moveDistance * progress; if (progress >= 1) { LK.clearInterval(simpleCountdownInterval); modalContainer.destroy(); startTimer(); } }, 16); }, 2000); goalLevel++; updateBackground(); setRandomGoalGemType(); } } }; this.checkForMatches = function (matchFoundPreviously) { var matchFound = false; var matchedGems = []; // Check for horizontal matches for (var i = 0; i < 8; i++) { for (var j = 0; j < 6; j++) { // Adjust to allow checks across all columns if (!this.gems || !this.gems[i * 6 + j] || typeof this.gems[i * 6 + j] === 'undefined') { continue; } var gem1 = this.gems[i * 6 + j]; if (!gem1) { continue; } var gem1 = this.gems[i * 6 + j]; var nowMatchingGems = []; for (var k = j; k < 6; k++) { var nextGem = this.gems[i * 6 + k]; if (nextGem && nextGem.color === gem1.color) { nowMatchingGems.push(nextGem); } else { break; } } if (nowMatchingGems.length >= 3) { matchFound = true; matchedGems = matchedGems.concat(nowMatchingGems.filter(function (gem) { return matchedGems.indexOf(gem) === -1; })); } } } // Check for vertical matches for (var i = 0; i < 6; i++) { for (var j = 0; j < 8; j++) { // Adjust to allow checks across all rows if (!this.gems || !this.gems[j * 6 + i]) { continue; } var gem1 = this.gems[j * 6 + i]; var nowMatchingGems = []; for (var k = j; k < 8; k++) { var nextGem = this.gems[k * 6 + i]; if (nextGem && nextGem.color === gem1.color) { nowMatchingGems.push(nextGem); } else { break; } } if (nowMatchingGems.length >= 3) { matchFound = true; matchedGems = matchedGems.concat(nowMatchingGems.filter(function (gem) { return matchedGems.indexOf(gem) === -1; })); } } } var matchesHandled = 0; matchedGems.forEach(function (gem) { // Play gemMatch sound when gems are matched LK.getSound('gemMatch').play(); if (gem.color == goalGemType) { self.handleGemMatched(gem); // Move gem to the goalGemSprite instead of destroying it matchesHandled++; game.addChild(gem); var moveGemToGoal = function moveGemToGoal(gem) { LK.setTimeout(function () { var goalGemSpriteX = currentGoalGemSprite ? currentGoalGemSprite.x + (currentGoalGemSprite.parent ? currentGoalGemSprite.parent.x : 0) : 0; var goalGemSpriteY = currentGoalGemSprite ? currentGoalGemSprite.y + (currentGoalGemSprite.parent ? currentGoalGemSprite.parent.y : 0) : 0; if (currentGoalGemSprite) { var goalGemSpriteScale = currentGoalGemSprite.scale.x; } var moveDuration = 500 + matchesHandled * 100; // Duration in milliseconds var startTime = Date.now(); var animateMove = function animateMove() { var currentTime = Date.now(); var progress = Math.min(1, (currentTime - startTime) / moveDuration); var newX = gem.x + (goalGemSpriteX - gem.x) * progress; var newY = gem.y + (goalGemSpriteY - gem.y) * progress; var newScale = gem.scale.x + (goalGemSpriteScale - gem.scale.x) * progress; gem.x = newX; gem.y = newY; gem.scale.set(newScale); if (progress < 1) { LK.setTimeout(animateMove, 16); // Aim for roughly 60fps } else { gem.destroy(); // Destroy gem after reaching the goal } }; animateMove(); }, matchesHandled * 100); }; moveGemToGoal(gem); } else { self.handleGemMatched(gem); gem.scaleUpAndDisappear(); // Trigger glowing particles effect at the gem's position var glowingParticles = new GlowingParticles(); glowingParticles.init(gem.x, gem.y); self.addChild(glowingParticles); } var index = self.gems.indexOf(gem); if (index > -1) { self.gems[index] = false; // Increase score based on combo multiplier var pointsAwarded = 10 * self.comboMultiplier; score += pointsAwarded; // Update score with points awarded based on combo multiplier LK.setScore(score); // Display points at the gem's location with animation var pointsText = new Text2("+" + pointsAwarded.toString(), { size: 80, weight: 600, fill: "#ffffff", anchorX: 0.5, anchorY: 0.5, dropShadow: true, dropShadowColor: '#000000', dropShadowBlur: 8, dropShadowOffsetX: 4, dropShadowOffsetY: 4, outline: true, outlineColor: '#000000', outlineThickness: 5 }); pointsText.y -= 20; // Make it a little bit higher pointsText.anchor.set(.5); pointsText.x = gem.x; pointsText.y = gem.y; game.addChild(pointsText); // Animate points text: scale up and fade out var scaleUpDuration = 500; // Duration to scale up in milliseconds var fadeOutDuration = 500; // Duration to fade out in milliseconds var maxScale = 1.5; // Maximum scale factor var originalScale = 1; // Original scale var startTime = Date.now(); var animate = function animate() { var currentTime = Date.now(); var progress = Math.min(1, (currentTime - startTime) / scaleUpDuration); pointsText.scale.set(originalScale + (maxScale - originalScale) * progress); pointsText.alpha = 1 - progress; // Fade out if (progress < 1) { LK.setTimeout(animate, 16); // Aim for roughly 60fps } else { pointsText.destroy(); // Destroy text after animation } }; animate(); // Increase combo multiplier for each consecutive match self.comboMultiplier++; scoreTxt.setText(score.toString()); // Update score display } }); if (matchFound) { // If no match was found previously and it's not the first check, reset the combo multiplier if (!matchFoundPreviously && matchFound) { self.comboMultiplier = 1; } else if (matchFound) { // Increase combo multiplier for each consecutive match self.comboMultiplier++; } self.checkForMatches(true); } else if (matchFoundPreviously) { LK.setTimeout(function () { this.handleFallingGems(); }.bind(this), 200); } return matchFound; }; self.handleGemClick = function (gem) { gem.on('down', function (x, y, obj) { if (!isPlaying) { return; } self.dragStartGem = gem; self.dragStartGemStartPosition = { x: gem.x, y: gem.y }; var currentPos = game.toLocal(obj.global); self.dragStartPos = { x: currentPos.x, y: currentPos.y }; // Highlight the drag start gem self.dragStartGem.alpha = 0.5; self.dragStartGem.scale.set(self.dragStartGem.baseScale * 1.1); }); gem.on('move', function (x, y, obj) { if (!isPlaying || !self.dragStartGem) { return; } var currentPos = game.toLocal(obj.global); //self.dragStartGem.x = self.dragStartGemStartPosition.x + currentPos.x - self.dragStartPos.x; //self.dragStartGem.y = self.dragStartGemStartPosition.y + currentPos.y - self.dragStartPos.y; var dx = currentPos.x - self.dragStartPos.x; var dy = currentPos.y - self.dragStartPos.y; if (Math.abs(dx) > gem.spacing / 2 || Math.abs(dy) > gem.spacing / 2) { var directionX = dx > 0 ? 1 : -1; var directionY = dy > 0 ? 1 : -1; // Correctly identify if we should swap horizontally or vertically if (Math.abs(dx) > Math.abs(dy)) { // Swap horizontally var swapGem = self.findGemByPosition(self.dragStartGem.x + gem.spacing * directionX, self.dragStartGem.y, self.dragStartGem); } else { // Swap vertically var swapGem = self.findGemByPosition(self.dragStartGem.x, self.dragStartGem.y + gem.spacing * directionY, self.dragStartGem); } if (self.lastHintOverlay) { self.lastHintOverlay.destroy(); } if (swapGem && self.wouldSwapResultInMatch(self.dragStartGem, swapGem)) { self.swapGems(self.dragStartGem, swapGem); } else { self.faintSwapGems(self.dragStartGem, swapGem, true); // Play wrong sound when a wrong move is made LK.getSound('wrong').play(); } self.dragStartGem.alpha = 1; self.dragStartGem.scale.set(self.dragStartGem.baseScale * 1); self.dragStartGem = null; self.dragStartPos = null; } }); gem.on('up', function () { if (!isPlaying) { return; } if (self.dragStartGem) { self.dragStartGem.alpha = 1; // Reset alpha to unhighlight the gem self.dragStartGem.scale.set(self.dragStartGem.baseScale * 1); } self.dragStartGem = null; self.dragStartPos = null; }); }; self.initBoard = function () { var colors = game.timer > 60 ? ['gemBlue', 'gemGreen', 'gemRed', 'gemPurple', 'gemYellow', 'gemOrange', 'gemCyan'] : ['gemBlue', 'gemGreen', 'gemRed', 'gemPurple', 'gemYellow', 'gemOrange']; for (var i = 0; i < 8; i++) { for (var j = 0; j < 6; j++) { var color = colors[Math.floor(Math.random() * colors.length)]; var gem = new Gem(color); var gem = new Gem(color); var gemSize = 100; var margin = 10; var boardWidth = game.width * .9; var boardHeight = game.height * .9; var gemsPerRow = 6; var gemsPerColumn = 8; var totalMarginWidth = margin * (gemsPerRow + 1); var totalMarginHeight = margin * (gemsPerColumn + 1); var availableWidth = boardWidth - totalMarginWidth; var availableHeight = boardHeight - totalMarginHeight; var scaledGemSize = Math.min(availableWidth / gemsPerRow, availableHeight / gemsPerColumn); var xOffset = (game.width - boardWidth) / 2 + scaledGemSize / 2; var yOffset = (game.height - boardHeight) / 2 + scaledGemSize / 2; gem.spacing = scaledGemSize + margin; self.spacing = gem.spacing; var snappedPos = self.snapToGrid(xOffset + (scaledGemSize + margin) * j, yOffset + (scaledGemSize + margin) * i); gem.x = snappedPos.x; gem.y = snappedPos.y; gem.scale.set(scaledGemSize / gemSize); gem.scale.set(scaledGemSize / gemSize); gem.baseScale = scaledGemSize / gemSize; self.addChild(gem); self.gems.push(gem); self.handleGemClick(gem); } } self.comboMultiplier = 1; // Initialize combo multiplier self.checkForMatches(); }; }); // ChineseRedEnvelope class var ChineseRedEnvelope = Container.expand(function () { var self = Container.call(this); var envelopeGraphics = self.attachAsset('redEnvelope', { anchorX: 0.5, anchorY: 0.5 }); self.init = function (x, y) { self.x = x; self.y = y; var scaleAnimation = function scaleAnimation() { var scaleUp = true; var scaleValue = 1; LK.setInterval(function () { if (scaleUp) { scaleValue += 0.01; } else { scaleValue -= 0.01; } if (scaleValue >= 1.1) { scaleUp = false; } if (scaleValue <= 1) { scaleUp = true; } self.scale.set(scaleValue * 2.0); // Make the envelope significantly larger }, 100); }; scaleAnimation(); self.on('down', function () { var targetX = timerTxt.x; var targetY = timerTxt.y; var moveDuration = 1000; // Duration in milliseconds var startTime = Date.now(); var animateMove = function animateMove() { var currentTime = Date.now(); var progress = Math.min(1, (currentTime - startTime) / moveDuration); // Apply a quadratic easing for a smooth curve var curveProgress = Math.pow(progress, 2); self.x = self.x + (targetX - self.x) * curveProgress; self.y = self.y - 75 * Math.sin(Math.PI * progress) + (targetY - self.y) * curveProgress; // Add a sine wave pattern for vertical movement if (progress < 1) { LK.setTimeout(animateMove, 16); } else { game.timer += 5; // Grant 5 more seconds timerTxt.setText(game.timer.toString()); // Update timer display self.destroy(); // Remove the envelope after reaching the timer } }; animateMove(); }); // Initiate continuous glowing effect function glowEffect() { var glowParticle = new GlowingParticlesForRedEnvelopes(.3); glowParticle.init(0, 0); self.addChildAt(glowParticle, 0); } ; glowEffect(); // LK.setInterval(glowEffect, 500); // Add a glowing particle effect every 500ms }; }); // ConfettiParticle class var ConfettiParticle = Container.expand(function () { var self = Container.call(this); var confettiColors = ['confettiRed', 'confettiBlue', 'confettiGreen', 'confettiYellow', 'confettiPurple']; var randomColor = confettiColors[Math.floor(Math.random() * confettiColors.length)]; var confettiGraphics = self.attachAsset(randomColor, { anchorX: 0.5, anchorY: 0.5 }); self.init = function (x, y) { self.x = x; self.y = y; var angle = Math.random() * Math.PI * 2; var speed = 0.5 + Math.random(); // Reduced speed for smoother appearance var duration = 1500 + Math.random() * 2500; // Extended duration for smoother fade var startTime = Date.now(); var floatGravity = 1 + 20 * Math.random(); var animate = function animate() { var currentTime = Date.now(); var progress = (currentTime - startTime) / duration; self.x += Math.cos(angle) * speed; self.y -= Math.sin(angle) * speed; self.y -= floatGravity; // Apply upward gravity to make confetti float upwards self.alpha = Math.sin(progress * Math.PI); // Smooth in and out fading effect if (progress < 1) { LK.setTimeout(animate, 16); } else { self.destroy(); } }; animate(); }; }); // Dragon class var Dragon = Container.expand(function (gem) { var self = Container.call(this); var dragonGraphics = self.attachAsset('dragon', { anchorX: 0.5, anchorY: 0.5 }); dragonGraphics.anchor.set(1, .7); self.speed = 5; var hasTakenGem = false; self._move_migrated = function () { var endX = 2048 + self.width; // Ensure dragon ends off-screen to the right var startX = -self.width; // Start off-screen to the left var travelDistance = endX - startX; var travelTime = 3000; // Time in milliseconds for the dragon to cross the screen var startTime = Date.now(); var particleParts = []; function animate() { var currentTime = Date.now(); var elapsedTime = currentTime - startTime; var progress = elapsedTime / travelTime; self.x = startX + travelDistance * progress; if (self.x > gem.x && !hasTakenGem) { hasTakenGem = true; self.addChild(gem); LK.getSound('batRoar').play(); // Animate gem scale upon grabbing var scaleAnimationDuration = 300; // Duration of the scale animation in milliseconds var scaleAnimationStartTime = Date.now(); var animateGemScale = function animateGemScale() { var currentTime = Date.now(); var progress = Math.min(1, (currentTime - scaleAnimationStartTime) / scaleAnimationDuration); gem.scale.set(gem.baseScale * (.8 + .2 * Math.sin(progress * Math.PI * 2))); // Animate scale if (progress < 1) { LK.setTimeout(animateGemScale, 16); } else { gem.scale.set(gem.baseScale * .8); } }; animateGemScale(); gem.x = 50; gem.y = 0; var index = board.gems.indexOf(gem); if (index > -1) { if (board.gems[index] == gem) { board.gems[index] = false; } } LK.setTimeout(function () { board.handleFallingGems(); }, 200); } if (hasTakenGem) { self.addChild(gem); //gem.scale.set(gem.baseScale * .8); gem.x = 50; gem.y = 0; } // Generate particle trail if (progress < 1) { LK.setTimeout(animate, 16); // Aim for roughly 60fps } else { var fadeoutparticle = function fadeoutparticle(particle) { // Start fade out effect var fadeOutDuration = 500; // Duration for the fade out in milliseconds var fadeStartTime = Date.now(); var fadeStep = function fadeStep() { var currentTime = Date.now(); var progress = (currentTime - fadeStartTime) / fadeOutDuration; particle.alpha = 1 - progress; // Fade out if (progress < 1) { LK.setTimeout(fadeStep, 16); } else { particle.destroy(); // Destroy particle after fade out } }; fadeStep(); }; ; // Spawn a red envelope at a random position //var envelope = new ChineseRedEnvelope(); //envelope.init(Math.random() * game.width, self.y); //game.addChild(envelope); // Destroy the dragon instance once it crosses the screen isDragoning = false; particleParts.forEach(function (particle) { fadeoutparticle(particle); }); self.destroy(); } } animate(); }; }); var FireworkEffect = Container.expand(function (x, y, numParticles, color) { var self = Container.call(this); self.x = x; self.y = y; for (var i = 0; i < numParticles; i++) { var angle = i / numParticles * 2 * Math.PI; var speed = 5 + Math.random() * 5; // Random speed between 5 and 10 var expansionSize = 0.5 + Math.random() * 1.5; // Variable size of expansion between 0.5 and 2 var particle = new FireworkParticle(); particle.init(self.x, self.y, angle, speed, color); self.addChild(particle); } }); // FireworkParticle class var FireworkParticle = Container.expand(function () { var self = Container.call(this); var particleGraphics = self.attachAsset('fireworkParticle', { anchorX: 0.5, anchorY: 0.5 }); self.init = function (x, y, angle, speed, color) { particleGraphics.tint = color; particleGraphics.scale.set(.5 + Math.random() * 1); particleGraphics.rotation = Math.PI * 2 * Math.random(); self.x = x; self.y = y; self.angle = angle; self.speed = speed; self.alpha = 1; var decay = 0.95; var gravity = 0.05; self._move_migrated = function () { var decay = 0.95; var gravity = 0.05; self.x += Math.cos(self.angle) * self.speed; self.y += Math.sin(self.angle) * self.speed; self.speed *= decay; self.y += gravity; self.alpha *= decay; if (self.alpha < 0.05) { self.destroy(); } }; LK.on('tick', function () { self._move_migrated(); }); }; }); // Gem class var Gem = Container.expand(function (color) { var self = Container.call(this); self.scaleUpAndDown = function (delay) { LK.setTimeout(function () { var scaleUpDuration = 150; // Duration to scale up in milliseconds var scaleDownDuration = 150; // Duration to scale down in milliseconds var maxScale = self.baseScale * 1.3; // Maximum scale factor var originalScale = self.baseScale; // Remember the original scale var scaleUp = function scaleUp() { var startTime = Date.now(); var scaleStep = function scaleStep() { var currentTime = Date.now(); var progress = Math.min(1, (currentTime - startTime) / scaleUpDuration); self.scale.set(originalScale + (maxScale - originalScale) * progress); if (progress < 1) { LK.setTimeout(scaleStep, 16); } else { scaleDown(); } }; scaleStep(); }; var scaleDown = function scaleDown() { var startTime = Date.now(); var scaleStep = function scaleStep() { var currentTime = Date.now(); var progress = Math.min(1, (currentTime - startTime) / scaleDownDuration); self.scale.set(maxScale - (maxScale - originalScale) * progress); if (progress < 1) { LK.setTimeout(scaleStep, 16); } }; scaleStep(); }; scaleUp(); }, delay); }; self.scaleUpAndDisappear = function scaleUpAndDisappear() { var scaleUpDuration = 100; // Duration to scale up in milliseconds var scaleDownDuration = 200; // Duration to scale down to zero var maxScale = self.baseScale * 1.2; // Maximum scale factor var disappearScale = 0; // Scale factor to disappear var originalScale = self.baseScale; // Remember the original scale // Animate scale up // Start scale up var scaleUpDuration = 100; // Duration to scale up in milliseconds var disappearDuration = 200; // Duration to scale down to zero var maxScale = self.baseScale * 1.2; // Maximum scale factor var disappearScale = 0; // Scale factor to disappear var originalScale = self.baseScale; // Remember the original scale // Animate scale up var startTime = Date.now(); var _scaleStep2 = function _scaleStep() { var currentTime = Date.now(); var progress = Math.min(1, (currentTime - startTime) / scaleUpDuration); self.scale.set(originalScale + (maxScale - originalScale) * progress); if (progress < 1) { LK.setTimeout(_scaleStep2, 16); } else { // Once scaled up, start disappearing startTime = Date.now(); _scaleStep2 = function scaleStep() { var currentTime = Date.now(); var progress = Math.min(1, (currentTime - startTime) / disappearDuration); self.scale.set(maxScale - (maxScale - disappearScale) * progress); if (progress < 1) { LK.setTimeout(_scaleStep2, 16); } else { self.destroy(); } }; _scaleStep2(); } }; _scaleStep2(); }; var gemGraphics = self.attachAsset(color, { anchorX: 0.5, anchorY: 0.5 }); self.color = color; self.isSelected = false; self.toggleSelect = function () { self.isSelected = !self.isSelected; if (self.isSelected) { gemGraphics.alpha = 0.5; self.scale.set(self.baseScale * 1.1); } else { gemGraphics.alpha = 1; self.scale.set(self.baseScale); } }; }); // GlowingParticles class enhancement var GlowingParticles = Container.expand(function () { var self = Container.call(this); scaleMultiplier = 1; var _animateParticle = function animateParticle(particle) { var currentTime = Date.now(); var elapsedTime = currentTime - particle.startTime; var progress = elapsedTime / particle.duration; if (progress < 1) { particle.x += Math.cos(particle.angle) * particle.speed; particle.y += Math.sin(particle.angle) * particle.speed; particle.alpha = Math.cos(progress * Math.PI); // Smooth in and out fading effect particle.rotation += particle.rotationVelocity; // Add rotation to each particle LK.setTimeout(function () { _animateParticle(particle); }, 16); } else { particle.destroy(); } }; self.init = function (x, y) { for (var i = 0; i < 50; i++) { var particle = self.attachAsset('glowEffect', { x: x, y: y, anchorX: 0.5, anchorY: 0.5 }); particle.blendMode = 1; particle.angle = Math.random() * Math.PI * 2; // Random angle for direction particle.speed = 1 + Math.random() * 2.5; // Adjusted speed for varied particle movement particle.duration = 500 + Math.random() * 1000; // Keeping the duration dynamic // Introduce gravity effect to some particles for (var i = 0; i < 50; i++) { var particle = self.attachAsset('glowEffect', { x: x, y: y, anchorX: 0.5, anchorY: 0.5 }); particle.blendMode = 1; particle.angle = Math.random() * Math.PI * 2; // Random angle for direction particle.speed = 1 + Math.random() * 2.5; // Adjusted speed for varied particle movement particle.duration = 500 + Math.random() * 1000; // Keeping the duration dynamic particle.gravity = Math.random() > 0.5 ? 0.01 : 0; // Half the particles have a gravity effect particle.targetScale = 0.5 + Math.random() * 1.5; // Varied scale for more visual variety particle.scale.set(particle.targetScale * scaleMultiplier); // Initial scale set based on the random scale variable particle.startTime = Date.now(); particle.rotationVelocity = -0.1 + Math.random() * .2; particle.x += Math.cos(particle.angle) * Math.random() * 80; particle.y += Math.sin(particle.angle) * Math.random() * 80; _animateParticle(particle); } particle.targetScale = 0.5 + Math.random() * 1.5; // Varied scale for more visual variety particle.scale.set(particle.targetScale * scaleMultiplier); // Initial scale set based on the random scale variable particle.startTime = Date.now(); particle.rotationVelocity = -0.1 + Math.random() * .2; particle.x += Math.cos(particle.angle) * Math.random() * 80; particle.y += Math.sin(particle.angle) * Math.random() * 80; _animateParticle(particle); } }; }); // Define the GlowingParticlesForRedEnvelope class var GlowingParticlesForRedEnvelope = Container.expand(function (scaleMultiplier) { var self = Container.call(this); var _animateParticle = function animateParticle(particle) { var currentTime = Date.now(); var elapsedTime = currentTime - particle.startTime; var progress = elapsedTime / particle.duration; if (progress < 1) { // Update particle properties for movement, fading, and rotation particle.x += Math.cos(particle.angle) * particle.speed; particle.y += Math.sin(particle.angle) * particle.speed; particle.alpha = Math.cos(progress * Math.PI); // Fading effect particle.rotation += particle.rotationVelocity; } else { // Reset particle to create a continuous effect particle.startTime = Date.now(); // Reset start time // Optionally, re-randomize properties for varied continuous effect particle.angle = Math.random() * Math.PI * 2; particle.speed = 1 + Math.random() * 1.5; particle.duration = 500 + Math.random() * 1000; particle.rotationVelocity = -0.1 + Math.random() * 0.2; particle.x = particle.initialX + Math.cos(particle.angle) * Math.random() * 50; particle.y = particle.initialY + Math.sin(particle.angle) * Math.random() * 50; } LK.setTimeout(function () { _animateParticle(particle); }, 16); // Continue animation loop }; self.init = function (x, y) { for (var i = 0; i < 50; i++) { var particle = self.attachAsset('glowEffect', { x: x, y: y, anchorX: 0.5, anchorY: 0.5 }); particle.blendMode = 1; particle.alpha = 0; particle.initialX = x; // Store initial position particle.initialY = y; particle.angle = Math.random() * Math.PI * 2; particle.speed = 1 + Math.random() * 1.5; particle.duration = 500 + Math.random() * 1000; particle.targetScale = 0.5 + Math.random() * 1.5; particle.scale.set(particle.targetScale * scaleMultiplier); particle.startTime = Date.now(); particle.rotationVelocity = -0.1 + Math.random() * 0.2; particle.x += Math.cos(particle.angle) * Math.random() * 70; particle.y += Math.sin(particle.angle) * Math.random() * 70; _animateParticle(particle); } }; }); var GlowingParticlesForRedEnvelopes = Container.expand(function (scaleMultiplier) { var self = Container.call(this); var _animateParticle = function animateParticle(particle) { var currentTime = Date.now(); var elapsedTime = currentTime - particle.startTime; var progress = elapsedTime / particle.duration; if (progress < 1) { // Update particle properties for movement, fading, and rotation particle.x += Math.cos(particle.angle) * particle.speed; particle.y += Math.sin(particle.angle) * particle.speed; particle.alpha = Math.cos(progress * Math.PI); // Fading effect particle.rotation += particle.rotationVelocity; } else { // Reset particle to create a continuous effect particle.startTime = Date.now(); // Reset start time // Optionally, re-randomize properties for varied continuous effect particle.angle = Math.random() * Math.PI * 2; particle.speed = 1 + Math.random() * 1.5; particle.duration = 500 + Math.random() * 1000; particle.rotationVelocity = -0.1 + Math.random() * 0.2; particle.x = particle.initialX + Math.cos(particle.angle) * Math.random() * 50; particle.y = particle.initialY + Math.sin(particle.angle) * Math.random() * 50; } LK.setTimeout(function () { _animateParticle(particle); }, 16); // Continue animation loop }; self.init = function (x, y) { for (var i = 0; i < 50; i++) { var particle = self.attachAsset('glowEffect', { x: x, y: y, anchorX: 0.5, anchorY: 0.5 }); particle.blendMode = 1; particle.alpha = 0; particle.initialX = x; // Store initial position particle.initialY = y; particle.angle = Math.random() * Math.PI * 2; particle.speed = 1 + Math.random() * 1.5; particle.duration = 500 + Math.random() * 1000; particle.targetScale = 0.5 + Math.random() * 1.5; particle.scale.set(particle.targetScale * scaleMultiplier); particle.startTime = Date.now(); particle.rotationVelocity = -0.1 + Math.random() * 0.2; particle.x += Math.cos(particle.angle) * Math.random() * 70; particle.y += Math.sin(particle.angle) * Math.random() * 70; _animateParticle(particle); } }; }); // LineSprite class var LineSprite = Container.expand(function () { var self = Container.call(this); self.updateLine = function (startX, startY, endX, endY) { var dx = endX - startX; var dy = endY - startY; var distance = Math.sqrt(dx * dx + dy * dy); self.width = distance; self.height = 5; // Fixed height for the line self.rotation = Math.atan2(dy, dx); self.x = startX + dx / 2; self.y = startY + dy / 2; self.anchorX = 0.5; self.anchorY = 0.5; }; }); // RowBlasterGem class var RowBlasterGem = Container.expand(function (color) { var self = Container.call(this); var gemGraphics = self.attachAsset(color, { anchorX: 0.5, anchorY: 0.5 }); self.color = color; // Unique behavior for RowBlasterGem self.activate = function () { // Logic to blast the entire row console.log('Blasting row...'); }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 // Init game with black background }); /**** * Game Code ****/ function animateGemsOutOfScreen() { var gems = board.gems; var gemsDestroyed = 0; var gemsToClean = gems.length; gems.forEach(function (gem) { if (gem) { var randomAngle = Math.random() * 2 * Math.PI; var speed = 15 + Math.random() * 10; var moveDuration = 2600; // Duration in milliseconds var startTime = Date.now(); var animateMove = function animateMove() { var currentTime = Date.now(); var progress = (currentTime - startTime) / moveDuration; gem.x += Math.cos(randomAngle) * speed; gem.y += Math.sin(randomAngle) * speed; if (progress < 1) { LK.setTimeout(animateMove, 16); // Continue animation } else { gem.destroy(); // Destroy gem after moving out of screen gemsDestroyed++; if (gemsDestroyed >= gemsToClean) { animateWitchSlideIn(); // Call animateWitchSlideIn after all gems are destroyed } } }; animateMove(); } }); } function animateWitchSlideIn() { // Browse gems to destroy them board.gems.forEach(function (gem) { if (gem) { gem.destroy(); } }); // Animate littleWitch sliding in after all gems are destroyed var littleWitch = LK.getAsset('littleWitch', { anchorX: 0.5, anchorY: 0.5 }); littleWitch.x = -littleWitch.width / 2; // Start off-screen to the left littleWitch.y = game.height - littleWitch.height / 2 + 100; game.addChild(littleWitch); var slideInDuration = 1000; // Duration for the slide-in animation in milliseconds var startTime = Date.now(); var animateSlideIn = function animateSlideIn() { var currentTime = Date.now(); var progress = (currentTime - startTime) / slideInDuration; littleWitch.x = littleWitch.width / 2 * progress; //scoreTxt.x = game.width / 2 * progress; scoreTxt.y = game.height / 3 * progress; scoreTxt.scale.set(1 + 3 * progress); // Scale to 4 times its original size if (progress < 1) { LK.setTimeout(animateSlideIn, 16); // Continue animation } else { littleWitch.x = littleWitch.width / 2; // Ensure final position is accurate //scoreTxt.x = game.width / 2; scoreTxt.y = game.height / 3; scoreTxt.scale.set(4); // Ensure final scale is accurate } }; animateSlideIn(); } var dragon; var isPlaying = true; // Function to show the current score function showScore() { console.log("showScore function called"); isPlaying = false; stopTimer(); if (isDragoning) { isDragoning = false; } if (dragonSpawnTimer) { LK.clearTimeout(dragonSpawnTimer); } if (dragon) { dragon.destroy(); dragon = null; } gameBoardBg.visible = false; // Hide the game board background board.fillingEmptySpaces = false; board.gemsFalling = false; if (hintTimer) { LK.clearTimeout(hintTimer); } if (goalBackground) { goalBackground.visible = false; } if (goalTxt) { goalTxt.visible = false; } if (missionLabel) { missionLabel.visible = false; } if (currentGoalGemSprite) { currentGoalGemSprite.visible = false; } if (timerTxt) { timerTxt.visible = false; } if (hourglassSprite) { hourglassSprite.visible = false; } LK.getSound('bgMusic').stop(); LK.getSound('gameEnd').play(); console.log("clean gems..."); animateGemsOutOfScreen(); // ... then animateWitchSlideIn(); console.log("Show score..."); // Set a timeout to call LK.showGameOver with the final score after 3 seconds LK.setTimeout(function () { // Add an event listener for tap on the screen game.on('down', function () { LK.showGameOver('Final Score: ' + score); }); }, 3000); /* var scoreContainer = new Container(); LK.gui.center.addChild(scoreContainer); var scoreBackground = LK.getAsset('scoreBg', { anchorX: 0.5, anchorY: 0.5 }); scoreContainer.addChild(scoreBackground); //LK.showGameOver('Final Score: ' + score); var scoreText = new Text2(score.toString(), { size: 150, fill: "#ffffff", anchorX: 0.5, anchorY: 0.5 }); scoreContainer.addChild(scoreText); scoreContainer.x = game.width / 2; scoreContainer.y = game.height / 2; // Animate the score display var startTime = Date.now(); var duration = 2000; // 2 seconds var animate = function animate() { var currentTime = Date.now(); var progress = (currentTime - startTime) / duration; scoreContainer.alpha = 1 - progress; // Fade out effect if (progress < 1) { LK.setTimeout(animate, 16); // Continue animation } else { scoreContainer.destroy(); // Remove the score display after animation } }; animate(); */ } // Function to loop background music function loopBgMusic() { if (!loopBgMusicInterval) { // Play the background music immediately if (isPlaying) { LK.getSound('bgMusic').play(); // Set an interval to loop the background music loopBgMusicInterval = LK.setInterval(function () { if (isPlaying) { LK.getSound('bgMusic').play(); } }, 6030); // Assuming the background music duration is 60 seconds } } } // Global variable to store the interval ID for looping background music var loopBgMusicInterval; // Start looping background music loopBgMusic(); // Initialize a timer for showing hints // Initialize 2-minute timer // Initialize score // Initialize large countdown at the beginning of the game // Goal gem type and count // Dragon spawn timer // SagaMap class // SagaMap class // FireworkEffect class function _typeof3(o) { "@babel/helpers - typeof"; return _typeof3 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof3(o); } function __defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) { descriptor.writable = true; } Object.defineProperty(target, _toPropertyKey3(descriptor.key), descriptor); } } function _createClass2(Constructor, protoProps, staticProps) { if (protoProps) { __defineProperties(Constructor.prototype, protoProps); } if (staticProps) { __defineProperties(Constructor, staticProps); } Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _toPropertyKey3(t) { var i = _toPrimitive3(t, "string"); return "symbol" == _typeof3(i) ? i : String(i); } function _toPrimitive3(t, r) { if ("object" != _typeof3(t) || !t) { return t; } var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof3(i)) { return i; } throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _classCallCheck2(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _callSuper2(t, o, e) { return o = _getPrototypeOf2(o), _possibleConstructorReturn2(t, _isNativeReflectConstruct2() ? Reflect.construct(o, e || [], _getPrototypeOf2(t).constructor) : o.apply(t, e)); } function _possibleConstructorReturn2(self, call) { if (call && (_typeof3(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized2(self); } function _assertThisInitialized2(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _isNativeReflectConstruct2() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct2 = function _isNativeReflectConstruct2() { return !!t; })(); } function _getPrototypeOf2(o) { _getPrototypeOf2 = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf2(o); } function _inherits2(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) { _setPrototypeOf2(subClass, superClass); } } function _setPrototypeOf2(o, p) { _setPrototypeOf2 = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf2(o, p); } var SagaMap = /*#__PURE__*/function (_Container) { _inherits(SagaMap, _Container); function SagaMap() { var _this; _classCallCheck(this, SagaMap); _this = _callSuper(this, SagaMap); _this.levels = []; _this.currentLevel = 0; return _this; } _createClass(SagaMap, [{ key: "addLevel", value: function addLevel(level) { this.levels.push(level); } }, { key: "goToLevel", value: function goToLevel(index) { this.currentLevel = index; // Logic to switch to the specified level console.log('Switching to level:', index); } }, { key: "nextLevel", value: function nextLevel() { if (this.currentLevel < this.levels.length - 1) { this.goToLevel(this.currentLevel + 1); } else { console.log('No more levels!'); } } }]); return SagaMap; }(Container); function _typeof2(o) { "@babel/helpers - typeof"; return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof2(o); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) { descriptor.writable = true; } Object.defineProperty(target, _toPropertyKey2(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) { _defineProperties(Constructor.prototype, protoProps); } if (staticProps) { _defineProperties(Constructor, staticProps); } Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _toPropertyKey2(t) { var i = _toPrimitive2(t, "string"); return "symbol" == _typeof2(i) ? i : String(i); } function _toPrimitive2(t, r) { if ("object" != _typeof2(t) || !t) { return t; } var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof2(i)) { return i; } throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _possibleConstructorReturn(self, call) { if (call && (_typeof2(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) { _setPrototypeOf(subClass, superClass); } } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } var SagaMap = /*#__PURE__*/function (_Container) { _inherits(SagaMap, _Container); function SagaMap() { var _this; _classCallCheck(this, SagaMap); _this = _callSuper(this, SagaMap); _this.levels = []; _this.currentLevel = 0; return _this; } _createClass(SagaMap, [{ key: "addLevel", value: function addLevel(level) { this.levels.push(level); } }, { key: "goToLevel", value: function goToLevel(index) { this.currentLevel = index; // Logic to switch to the specified level console.log('Switching to level:', index); } }, { key: "nextLevel", value: function nextLevel() { if (this.currentLevel < this.levels.length - 1) { this.goToLevel(this.currentLevel + 1); } else { console.log('No more levels!'); } } }]); return SagaMap; }(Container); var dragonSpawnTimer; var isDragoning = false; function triggerDragon() { if (dragonSpawnTimer) { LK.clearTimeout(dragonSpawnTimer); } if (!isDragoning && board && board.gems && board.gems.length > 0) { isDragoning = true; var randomIndex = Math.floor(Math.random() * board.gems.length); var gemToRemove = board.gems[randomIndex]; if (gemToRemove) { var dragon = new Dragon(gemToRemove); dragon.x = -100; // Ensure dragon starts off-screen to the left dragon.y = gemToRemove.y; // Random y position within game bounds game.addChild(dragon); dragon._move_migrated(); } } var nextSpawnTime = 5000 + Math.random() * 10000; // Random interval between 5 to 15 seconds dragonSpawnTimer = LK.setTimeout(triggerDragon, nextSpawnTime); } triggerDragon(); var goalGemType; var matchedGemCount = 0; var hintTimer; var currentGoalGemSprite = false; var goalLevel = 0; // Function to randomly set the goal gem type from the available gem colors function setRandomGoalGemType() { var gemColors = ['gemBlue', 'gemGreen', 'gemRed', 'gemPurple', 'gemYellow', 'gemOrange', 'gemCyan']; goalGemType = gemColors[Math.floor(Math.random() * gemColors.length)]; goalGemCount = 3 + Math.floor(Math.random() * goalLevel); matchedGemCount = 0; LK.setTimeout(function () { // Update the goal text with the chosen gem type goalTxt.setText(matchedGemCount + '/' + goalGemCount); // Add hourglass sprite next to the timer if (currentGoalGemSprite) { currentGoalGemSprite.destroy(); } currentGoalGemSprite = LK.getAsset(goalGemType, { x: 2048 - 100, // Position next to the timer y: 50, // Align with the timer's top margin anchorX: .5, // Anchor right for right alignment anchorY: .5 // Anchor top for top alignment }); currentGoalGemSprite.y = goalTxt.y; currentGoalGemSprite.x = goalBackground.x - 90; // Position next to the timer currentGoalGemSprite.anchor.set(0.5, 0.5); // Align with the timer's top margin currentGoalGemSprite.rotation = -.2; currentGoalGemSprite.scale.set(1.6); if (goalBackground.parent) { goalBackground.parent.removeChild(goalBackground); } if (goalTxt.parent) { goalTxt.parent.removeChild(goalTxt); } if (missionLabel.parent) { missionLabel.parent.removeChild(missionLabel); } if (currentGoalGemSprite.parent) { currentGoalGemSprite.parent.removeChild(currentGoalGemSprite); } LK.setTimeout(function () { board.addChild(goalBackground); game.addChild(goalBackground); game.addChild(goalTxt); game.addChild(missionLabel); missionLabel.visible = true; game.addChild(currentGoalGemSprite); }, 1000); }, 1000); } // setRandomGoalGemType(); // Initialize the goal gem type at the start of the game // This call has been moved to after the definition of goalTxt to fix the bug // Function to reset and start the hint timer function resetHintTimer() { if (hintTimer) { LK.clearTimeout(hintTimer); } hintTimer = LK.setTimeout(function () { board.showHint(); resetHintTimer(); }, 5000); // Show hint after 5 seconds of inactivity } resetHintTimer(); // Reset the hint timer whenever a move is made LK.on('tick', function () { // This is a placeholder for any game action, e.g., gem swap, that resets the hint timer // resetHintTimer(); }); function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) { return t; } var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) { return i; } throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } var welcomeText = new Text2("Magic Potions Match", { size: 110, fill: "#ffff00", x: 1024, // Center of the screen y: 1366, // Middle of the screen anchorX: 0.5, anchorY: 0.5, stroke: true, weight: 800, dropShadow: true, dropShadowDistance: 20, strokeColor: '#ff0000', strokeThickness: 14 }); welcomeText.anchor.set(.5); LK.gui.center.addChild(welcomeText); // Add countdown display to the center GUI layer welcomeText.y = -200; var countdownValue = 3; // Start countdown from 3 var countdownTxt = new Text2(countdownValue.toString(), { size: 300, fill: "#ffffff", x: 1024, // Center of the screen y: 1366, // Middle of the screen anchorX: 0.5, anchorY: 0.5, stroke: true, weight: 800, dropShadow: true, strokeThickness: 14 }); countdownTxt.anchor.set(.5); LK.gui.center.addChild(countdownTxt); // Add countdown display to the center GUI layer var countdownInterval = LK.setInterval(function () { countdownValue -= 1; if (countdownValue > 0) { countdownTxt.setText(countdownValue.toString()); // Bounce effect for countdown numbers var scaleUpDuration = 100; // Duration to scale up in milliseconds var scaleDownDuration = 100; // Duration to scale down in milliseconds var maxScale = 1.2; // Maximum scale factor var originalScale = 1; // Remember the original scale var scaleUp = function scaleUp() { var startTime = Date.now(); var scaleStep = function scaleStep() { var currentTime = Date.now(); var progress = Math.min(1, (currentTime - startTime) / scaleUpDuration); countdownTxt.scale.set(originalScale + (maxScale - originalScale) * progress); if (progress < 1) { LK.setTimeout(scaleStep, 16); } else { scaleDown(); } }; scaleStep(); }; var scaleDown = function scaleDown() { var startTime = Date.now(); var scaleStep = function scaleStep() { var currentTime = Date.now(); var progress = Math.min(1, (currentTime - startTime) / scaleDownDuration); countdownTxt.scale.set(maxScale - (maxScale - originalScale) * progress); if (progress < 1) { LK.setTimeout(scaleStep, 16); } }; scaleStep(); }; scaleUp(); } else if (countdownValue === 0) { var triggerFirework = function triggerFirework(fireworkDelay) { LK.setTimeout(function () { var x = -300 + Math.random() * 600; var y = -500 + Math.random() * 1000; var colors = [0xFFFFFF, 0xFF0000, 0x00FF00, 0xddddFF, 0xFFFF00, 0xFF00FF]; var color = colors[Math.floor(Math.random() * colors.length)]; var fireworkEffect = new FireworkEffect(x, y, 50, color); LK.gui.center.addChild(fireworkEffect); }, fireworkDelay); }; ; countdownTxt.setText('Welcome little witch!'); countdownTxt.y = -50; countdownTxt.setStyle({ size: 90, fill: "#ffffff", x: 1024, // Center of the screen y: 1366, // Middle of the screen anchorX: 0.5, anchorY: 0.5, stroke: true, weight: 800, dropShadow: true, dropShadowDistance: 20, strokeColor: '#ff0000', strokeThickness: 14 }); // Trigger firework effects at various places on the screen for (var i = 0; i < 16; i++) { triggerFirework(i * 100 + Math.random() * 500); } spinHourglass(); // Bounce effect var scaleUpDuration = 1200; // Duration to scale up in milliseconds var scaleDownDuration = 200; // Duration to scale down in milliseconds var maxScale = 2; // Maximum scale factor var originalScale = 1; // Remember the original scale var scaleUp = function scaleUp() { var startTime = Date.now(); var scaleStep = function scaleStep() { var currentTime = Date.now(); var progress = Math.min(1, (currentTime - startTime) / scaleUpDuration); countdownTxt.scale.set(originalScale + (maxScale - originalScale) * progress); if (progress < 1) { LK.setTimeout(scaleStep, 16); } else { //scaleDown(); } }; scaleStep(); }; var scaleDown = function scaleDown() { var fadeOutDuration = 1000; // Duration for the fade out in milliseconds var startTime = Date.now(); var fadeStep = function fadeStep() { var currentTime = Date.now(); var progress = Math.min(1, (currentTime - startTime) / fadeOutDuration); countdownTxt.alpha = 1 - progress; // Fade out welcomeText.alpha = 1 - progress; // Fade out if (progress < 1) { LK.setTimeout(fadeStep, 16); } else { welcomeText.destroy(); // Remove countdown text after animation countdownTxt.destroy(); // Remove countdown text after animation LK.clearInterval(countdownInterval); setRandomGoalGemType(); isPlaying = true; } }; fadeStep(); }; LK.setTimeout(scaleDown, 200); scaleUp(); } }, 1000); // Update countdown every second game.timer = 99; //120; // 2 minutes in seconds // Implement a three second delay before starting the timer text interval LK.setTimeout(function () { // Timer control is now handled inside the modal display logic to pause during the modal display. }, 3000); var score = 0; // Starting score var scoreBg; var scoreBgNode = LK.getAsset('scoreBg', { x: 1024 - 150, // Centered based on the background size y: 0, anchorX: 0.5, anchorY: 0 }); scoreBgNode.anchor.set(.5); scoreBgNode.y = 50; scoreBgNode.alpha = 1; // Set the background transparency to fully opaque to ensure visibility LK.gui.top.addChild(scoreBgNode); var scoreTxt = new Text2(score.toString(), _defineProperty(_defineProperty({ size: 110, weight: 500, fill: "#ffffff", x: 1024, // Center of the screen y: 50, // Adjusted to be within the background anchorX: 0.5, // Center horizontally anchorY: 0, // Anchor at the top dropShadow: true, dropShadowColor: '#000000', shadowBlur: 4, shadowOffsetX: 2, shadowOffsetY: 2, stroke: true, strokeColor: '#000000' }, "stroke", '#000000'), "strokeThickness", 7)); scoreTxt.anchor.set(.5, .5); scoreTxt.y = 60; LK.gui.top.addChild(scoreTxt); // Add score display to the top GUI layer // List of background images for different goal levels var backgroundImages = ['magicalBackground', 'enchantedForest', 'mysticCave', 'celestialRealm']; // Function to update the game background according to the current goal level function updateBackground() { var backgroundImageId = backgroundImages[goalLevel % backgroundImages.length]; var oldBackground = game.background; if (oldBackground) { LK.setTimeout(function () { oldBackground.destroy(); }, 1000); } var background = LK.getAsset(backgroundImageId, { anchorX: 0.5, anchorY: 0.5 }); background.x = game.width / 2; background.y = game.height / 2; var scaleFactor = Math.max(game.height / background.height, game.width / background.width); background.width = background.width * scaleFactor; background.height = background.height * scaleFactor; background.alpha = 0; // Start fully transparent //background.scale.set(Math.max(game.height / background.height, game.width / background.width)); var fadeInDuration = 1000; // Duration for the fade in milliseconds var fadeInStartTime = Date.now(); var fadeInStep = function fadeInStep() { var currentTime = Date.now(); var progress = (currentTime - fadeInStartTime) / fadeInDuration; background.alpha = progress; // Fade in if (progress < 1) { LK.setTimeout(fadeInStep, 16); } else { background.alpha = 1; if (oldBackground) {} } }; fadeInStep(); // This line is removed to prevent script errors related to incorrect usage of addChildAt. // Instead, we'll use addChild and manage layering through careful addition order. game.addChildAt(background, Math.min(1, game.children.length)); game.background = background; } // Initially set the background updateBackground(); // Add the game board background to the game var gameBoardBg = game.addChild(LK.getAsset('gameBoardBg', { x: 0, y: 0, anchorX: 0, anchorY: 0 })); gameBoardBg.width = game.width * 0.9; gameBoardBg.height = game.height * 0.9; gameBoardBg.x = (game.width - gameBoardBg.width) / 2; gameBoardBg.y = (game.height - gameBoardBg.height) / 2 + 80; gameBoardBg.alpha = 0.6; // Set the background transparency to make it slightly visible // Initialize the board // Define assets for the game var board = new Board(); game.addChild(board); board.initBoard(); function animateGemsInWave(board) { for (var i = 0; i < 8; i++) { for (var j = 0; j < 6; j++) { var gem = board.gems[i * 6 + j]; if (gem && typeof gem.scaleUpAndDown === 'function') { gem.scaleUpAndDown((i + j) * 50); } } } } animateGemsInWave(board); // Game logic LK.on('tick', function () { // Add game logic that needs to run every frame // For example, checking for matches, handling animations, etc. }); // Add hourglass sprite next to the timer var goalBackground = LK.getAsset('goalBackgroundSprite', { x: 2048 - 100, // Position next to the timer y: 50, // Align with the timer's top margin anchorX: .5, // Anchor right for right alignment anchorY: .5 // Anchor top for top alignment }); goalBackground.y = 110; goalBackground.x = 430; goalBackground.anchor.set(0.5, 0.5); // Align with the timer's top margin goalBackground.alpha = .6; // Add a label with the same styling as the timer text, but with the opposite x-coordinate var missionLabel = new Text2('Mission', { size: 50, weight: 500, fill: "#ffffff", x: 0, y: 50, anchorX: 0, anchorY: 0, dropShadow: true, dropShadowColor: '#000000', shadowBlur: 4, shadowOffsetX: 2, shadowOffsetY: 2, strokeThickness: 7 }); board.addChild(missionLabel); missionLabel.anchor.set(0, .5); missionLabel.y = 35; missionLabel.x = 355; missionLabel.visible = false; var goalTxt = new Text2('', { size: 100, weight: 500, fill: "#ffffff", x: 0, // Opposite x-coordinate y: 50, anchorX: 0, anchorY: 0, dropShadow: true, dropShadowColor: '#000000', shadowBlur: 4, shadowOffsetX: 2, shadowOffsetY: 2, strokeThickness: 7 }); board.addChild(goalTxt); goalTxt.anchor.set(0, .5); goalTxt.y = 130; goalTxt.x = 440; var timerTxt = new Text2(game.timer.toString(), { size: 100, // Made the text smaller weight: 500, fill: "#ffffff", x: 2048 - 200, y: 50, anchorX: 1, anchorY: 0, dropShadow: true, dropShadowColor: '#000000', shadowBlur: 4, shadowOffsetX: 2, shadowOffsetY: 2, strokeThickness: 7 }); // Add hourglass sprite next to the timer var hourglassSprite = LK.getAsset('hourglass', { x: 2048 - 100, // Position next to the timer y: 50, // Align with the timer's top margin anchorX: .5, // Anchor right for right alignment anchorY: .5 // Anchor top for top alignment }); function stopTimer() { if (board.timerInterval) { LK.clearInterval(board.timerInterval); } } function startTimer() { // Resume the game timer after the modal disappears stopTimer(); board.timerInterval = LK.setInterval(function () { game.timer -= 1; timerTxt.setText(game.timer.toString()); if (game.timer <= 0) { //LK.showGameOver('Final Score: ' + score); showScore(); } }, 1000); } // Logic to spin the hourglass var spinHourglass = function spinHourglass() { var rotationDuration = 500; // Duration of the spin in milliseconds var startTime = Date.now(); var spinStep = function spinStep() { var currentTime = Date.now(); var progress = (currentTime - startTime) / rotationDuration; hourglassSprite.rotation = progress * 2 * Math.PI; // Complete rotation if (progress < 1) { LK.setTimeout(spinStep, 16); // Aim for roughly 60fps } else { hourglassSprite.rotation = 0; startTimer(); } }; spinStep(); }; board.addChild(hourglassSprite); timerTxt.anchor.set(1, .5); timerTxt.y = 100; timerTxt.x = 2048 - 240; board.addChild(timerTxt); // Add timer display to the top GUI layer hourglassSprite.y = timerTxt.y; hourglassSprite.x = timerTxt.x + 70; // Position next to the timer hourglassSprite.anchor.set(0.5, 0.5); // Align with the timer's top margin
===================================================================
--- original.js
+++ change.js
@@ -1603,8 +1603,14 @@
}
});
}
function animateWitchSlideIn() {
+ // Browse gems to destroy them
+ board.gems.forEach(function (gem) {
+ if (gem) {
+ gem.destroy();
+ }
+ });
// Animate littleWitch sliding in after all gems are destroyed
var littleWitch = LK.getAsset('littleWitch', {
anchorX: 0.5,
anchorY: 0.5
glow. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Glow glare star. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Shiny red envelope bao, chinese new years. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Brilliant Gold Checkmark. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Mystic cavern. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
ponssion magique. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
potion magique orange. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
potion magique rouge. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
potion magique violette. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
potion magique blanche lumineuse. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
une sorciere mignone qui tape des mains. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
une étoile en cristal. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
une étoile en cristal blanc. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
bat flying.
atelier de sorciere. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
atelier de sorciere. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.