/**** * 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 () { 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 () { 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() { 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; // Assuming game height is 2732 var snapped = self.snapToGrid(xOffset + (scaledGemSize + margin) * j, yOffset + (scaledGemSize + margin) * i); newGem.x = snapped.x; // Calculate initial y position for animation start // 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 () { 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) { game.timer += 10; timerTxt.setText(game.timer.toString()); stopTimer(); // 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) { 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++; if (scoreTxt) { 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) { 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 (!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); } self.dragStartGem.alpha = 1; self.dragStartGem.scale.set(self.dragStartGem.baseScale * 1); self.dragStartGem = null; self.dragStartPos = null; } }); gem.on('up', function () { 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); // 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 ****/ game.width = 2048; game.height = 2732; // 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 board = new Board(); game.addChild(board); board.initBoard(); 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 goalTxt = new Text2('', { size: 100, weight: 500, fill: "#ffffff", x: 0, y: 50, anchorX: 0, anchorY: 0, dropShadow: true, dropShadowColor: '#000000', shadowBlur: 4, shadowOffsetX: 2, shadowOffsetY: 2, strokeThickness: 7 }); var goalBackground = LK.getAsset('goalBackgroundSprite', { x: 2048 - 100, y: 50, anchorX: .5, anchorY: .5 }); goalBackground.y = goalTxt.y; goalBackground.x = goalTxt.x - 100; goalBackground.anchor.set(0.5, 0.5); goalBackground.alpha = .6; board.addChild(goalTxt); goalTxt.anchor.set(0, .5); goalTxt.y = 100; goalTxt.x = 450; 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; // 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 (currentGoalGemSprite.parent) { currentGoalGemSprite.parent.removeChild(currentGoalGemSprite); } LK.setTimeout(function () { board.addChild(goalBackground); game.addChild(goalBackground); game.addChild(goalTxt); 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("Spooky 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('Trick or Treat!'); 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(); } }; fadeStep(); }; LK.setTimeout(scaleDown, 200); scaleUp(); } }, 1000); // Update countdown every second game.timer = 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 scoreTxt = new Text2(score.toString(), { size: 110, weight: 500, fill: "#ffffff", x: 1024, y: 0, anchorX: 0.5, anchorY: 0, dropShadow: true, dropShadowColor: '#000000', shadowBlur: 4, shadowOffsetX: 2, shadowOffsetY: 2, stroke: true, strokeColor: '#000000', strokeThickness: 7 }); scoreTxt.anchor.set(.5, .5); scoreTxt.y = 50; LK.gui.top.addChild(scoreTxt); 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); scoreTxt = new Text2(score.toString(), _defineProperty(_defineProperty({ size: 110, weight: 500, fill: "#ffffff", x: 1024, // Center of the screen y: 0, // 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 = 50; 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; background.scale.set(Math.max(game.height / background.height, game.width / background.width)); background.alpha = 0; // Start fully transparent 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 a label with the same styling as the timer text, but with the opposite x-coordinate 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 = 100; goalTxt.x = 450; // 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 = goalTxt.y; goalBackground.x = goalTxt.x - 100; // Position next to the timer goalBackground.anchor.set(0.5, 0.5); // Align with the timer's top margin goalBackground.alpha = .6; 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); } }, 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
/****
* 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 () {
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 () {
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() {
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; // Assuming game height is 2732
var snapped = self.snapToGrid(xOffset + (scaledGemSize + margin) * j, yOffset + (scaledGemSize + margin) * i);
newGem.x = snapped.x;
// Calculate initial y position for animation start
// 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 () {
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) {
game.timer += 10;
timerTxt.setText(game.timer.toString());
stopTimer();
// 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) {
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++;
if (scoreTxt) {
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) {
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 (!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);
}
self.dragStartGem.alpha = 1;
self.dragStartGem.scale.set(self.dragStartGem.baseScale * 1);
self.dragStartGem = null;
self.dragStartPos = null;
}
});
gem.on('up', function () {
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);
// 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
****/
game.width = 2048;
game.height = 2732;
// 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 board = new Board();
game.addChild(board);
board.initBoard();
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 goalTxt = new Text2('', {
size: 100,
weight: 500,
fill: "#ffffff",
x: 0,
y: 50,
anchorX: 0,
anchorY: 0,
dropShadow: true,
dropShadowColor: '#000000',
shadowBlur: 4,
shadowOffsetX: 2,
shadowOffsetY: 2,
strokeThickness: 7
});
var goalBackground = LK.getAsset('goalBackgroundSprite', {
x: 2048 - 100,
y: 50,
anchorX: .5,
anchorY: .5
});
goalBackground.y = goalTxt.y;
goalBackground.x = goalTxt.x - 100;
goalBackground.anchor.set(0.5, 0.5);
goalBackground.alpha = .6;
board.addChild(goalTxt);
goalTxt.anchor.set(0, .5);
goalTxt.y = 100;
goalTxt.x = 450;
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; // 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 (currentGoalGemSprite.parent) {
currentGoalGemSprite.parent.removeChild(currentGoalGemSprite);
}
LK.setTimeout(function () {
board.addChild(goalBackground);
game.addChild(goalBackground);
game.addChild(goalTxt);
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("Spooky 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('Trick or Treat!');
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();
}
};
fadeStep();
};
LK.setTimeout(scaleDown, 200);
scaleUp();
}
}, 1000); // Update countdown every second
game.timer = 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 scoreTxt = new Text2(score.toString(), {
size: 110,
weight: 500,
fill: "#ffffff",
x: 1024,
y: 0,
anchorX: 0.5,
anchorY: 0,
dropShadow: true,
dropShadowColor: '#000000',
shadowBlur: 4,
shadowOffsetX: 2,
shadowOffsetY: 2,
stroke: true,
strokeColor: '#000000',
strokeThickness: 7
});
scoreTxt.anchor.set(.5, .5);
scoreTxt.y = 50;
LK.gui.top.addChild(scoreTxt);
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);
scoreTxt = new Text2(score.toString(), _defineProperty(_defineProperty({
size: 110,
weight: 500,
fill: "#ffffff",
x: 1024,
// Center of the screen
y: 0,
// 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 = 50;
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;
background.scale.set(Math.max(game.height / background.height, game.width / background.width));
background.alpha = 0; // Start fully transparent
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 a label with the same styling as the timer text, but with the opposite x-coordinate
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 = 100;
goalTxt.x = 450;
// 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 = goalTxt.y;
goalBackground.x = goalTxt.x - 100; // Position next to the timer
goalBackground.anchor.set(0.5, 0.5); // Align with the timer's top margin
goalBackground.alpha = .6;
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);
}
}, 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
glow. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Hourglass icon white. 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.
Town of Halloween. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
blue bat. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
green bat. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
purple bat. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
yellow bat. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
spooky ghost. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
spooky halloween forest. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
dark magic particle. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
stylized vampire head. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
stylized halloween pumpkin. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
stylized orange pumpkin. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
stylized purple werwolf head. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
stylized wich head. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
white scull. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
old dark cemetery, 4k, high quality, landscape, digital art. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
abandoned manor, halloween, 4k, high quality, landscape, digital art. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
witch's cauldron. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
horror haloween Checkmark. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.