User prompt
Implement a special row blaster gem that appears after matching more than three gems.
User prompt
Please fix the bug: 'Timeout.tick error: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var goalGemSpriteScale = currentGoalGemSprite.scale.x;' Line Number: 832
Code edit (2 edits merged)
Please save this source code
User prompt
in fillemptyspaces when checking to create a new gem - ensure Only proceed if theres no gems in any position in the gems array which is above the empty space array position
Code edit (3 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: requestAnimationFrame is not a function' in or related to this line: 'requestAnimationFrame(animateScale);' Line Number: 1615
User prompt
When starting the initial countdown interval (3-2-1-GO), while doing that, scale the board smoothly from 0.8 to 1.
Code edit (6 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: Cannot read properties of null (reading 'y')' in or related to this line: 'dragon.y = gemToRemove.y; // Random y position within game bounds' Line Number: 1462
User prompt
Uncomment addchild of Thumbs up 2
Code edit (5 edits merged)
Please save this source code
User prompt
In the dragon trail particles affect, before destroying each particle, rather fade each particle out smoothly
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: p.destroy is not a function. (In 'p.destroy()', 'p.destroy' is undefined)' in or related to this line: 'p.destroy();' Line Number: 1158
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: Can't find variable: particle' in or related to this line: 'particle.init(self.x, self.y);' Line Number: 1141
User prompt
Please fix the bug: 'Timeout.tick error: Can't find variable: GlowingParticlesForRedEnvelope' in or related to this line: 'var particle = new GlowingParticlesForRedEnvelope();' Line Number: 1141
Code edit (1 edits merged)
Please save this source code
User prompt
In the dragon particle trail cut in half the number of particles involved
User prompt
I reduce the number of particles in the dragons particles trailer
User prompt
Further reduce the rate of particles in the dragons particle trail
User prompt
Reduce the number of particles in the dragon particle trail
User prompt
Implement a particle trail to the dragon
Initial prompt
Copy Magic Mach 3
/****
* 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;
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);
// 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);
// 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;
var goalGemSpriteScale = currentGoalGemSprite.scale.x;
var moveDuration = 500 + matchesHandled * 100; // Duration in milliseconds
var startTime = Date.now();
var animateMove = function animateMove() {
var currentTime = Date.now();
var progress = Math.min(1, (currentTime - startTime) / moveDuration);
var newX = gem.x + (goalGemSpriteX - gem.x) * progress;
var newY = gem.y + (goalGemSpriteY - gem.y) * progress;
var newScale = gem.scale.x + (goalGemSpriteScale - gem.scale.x) * progress;
gem.x = newX;
gem.y = newY;
gem.scale.set(newScale);
if (progress < 1) {
LK.setTimeout(animateMove, 16); // Aim for roughly 60fps
} else {
gem.destroy(); // Destroy gem after reaching the goal
}
};
animateMove();
}, matchesHandled * 100);
};
moveGemToGoal(gem);
} else {
self.handleGemMatched(gem);
gem.scaleUpAndDisappear();
// Trigger glowing particles effect at the gem's position
var glowingParticles = new GlowingParticles();
glowingParticles.init(gem.x, gem.y);
self.addChild(glowingParticles);
}
var index = self.gems.indexOf(gem);
if (index > -1) {
self.gems[index] = false;
// Increase score based on combo multiplier
var pointsAwarded = 10 * self.comboMultiplier;
score += pointsAwarded; // Update score with points awarded based on combo multiplier
LK.setScore(score);
// Display points at the gem's location with animation
var pointsText = new Text2(pointsAwarded.toString(), {
size: 80,
weight: 600,
fill: "#ffffff",
anchorX: 0.5,
anchorY: 0.5,
dropShadow: true,
dropShadowColor: '#000000',
dropShadowBlur: 8,
dropShadowOffsetX: 4,
dropShadowOffsetY: 4,
outline: true,
outlineColor: '#000000',
outlineThickness: 5
});
pointsText.y -= 20; // Make it a little bit higher
pointsText.anchor.set(.5);
pointsText.x = gem.x;
pointsText.y = gem.y;
game.addChild(pointsText);
// Animate points text: scale up and fade out
var scaleUpDuration = 500; // Duration to scale up in milliseconds
var fadeOutDuration = 500; // Duration to fade out in milliseconds
var maxScale = 1.5; // Maximum scale factor
var originalScale = 1; // Original scale
var startTime = Date.now();
var animate = function animate() {
var currentTime = Date.now();
var progress = Math.min(1, (currentTime - startTime) / scaleUpDuration);
pointsText.scale.set(originalScale + (maxScale - originalScale) * progress);
pointsText.alpha = 1 - progress; // Fade out
if (progress < 1) {
LK.setTimeout(animate, 16); // Aim for roughly 60fps
} else {
pointsText.destroy(); // Destroy text after animation
}
};
animate();
// Increase combo multiplier for each consecutive match
self.comboMultiplier++;
scoreTxt.setText(score.toString()); // Update score display
}
});
if (matchFound) {
// If no match was found previously and it's not the first check, reset the combo multiplier
if (!matchFoundPreviously && matchFound) {
self.comboMultiplier = 1;
} else if (matchFound) {
// Increase combo multiplier for each consecutive match
self.comboMultiplier++;
}
self.checkForMatches(true);
} else if (matchFoundPreviously) {
LK.setTimeout(function () {
this.handleFallingGems();
}.bind(this), 500);
}
return matchFound;
};
self.handleGemClick = function (gem) {
gem.on('down', function (obj) {
self.dragStartGem = gem;
self.dragStartGemStartPosition = {
x: gem.x,
y: gem.y
};
var currentPos = obj.event.getLocalPosition(game);
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 (obj) {
if (!self.dragStartGem) {
return;
}
var currentPos = obj.event.getLocalPosition(game);
//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 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.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 = 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();
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);
gem.scale.set(gem.baseScale * .8);
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();
}, 400);
}
if (hasTakenGem) {
self.addChild(gem);
gem.scale.set(gem.baseScale * .8);
gem.x = 50;
gem.y = 0;
}
if (progress < 1) {
LK.setTimeout(animate, 16); // Aim for roughly 60fps
} else {
// Spawn a red envelope at a random position
//var envelope = new ChineseRedEnvelope();
//envelope.init(Math.random() * game.width, self.y);
//game.addChild(envelope);
self.destroy(); // Destroy the dragon instance once it crosses the screen
isDragoning = false;
}
}
animate();
};
});
// 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
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() * 100;
particle.y += Math.sin(particle.angle) * Math.random() * 100;
_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;
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 // Init game with black background
});
/****
* Game Code
****/
// 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
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];
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();
}
var nextSpawnTime = 5000 + Math.random() * 10000; // Random interval between 5 to 15 seconds
dragonSpawnTimer = LK.setTimeout(triggerDragon, nextSpawnTime);
}
triggerDragon();
var goalGemType;
var matchedGemCount = 0;
var hintTimer;
var currentGoalGemSprite = false;
var goalLevel = 0;
// Function to randomly set the goal gem type from the available gem colors
function setRandomGoalGemType() {
var gemColors = ['gemBlue', 'gemGreen', 'gemRed', 'gemPurple', 'gemYellow', 'gemOrange', 'gemCyan'];
goalGemType = gemColors[Math.floor(Math.random() * gemColors.length)];
goalGemCount = 3 + Math.floor(Math.random() * goalLevel);
matchedGemCount = 0;
LK.setTimeout(function () {
// Update the goal text with the chosen gem type
goalTxt.setText(matchedGemCount + '/' + goalGemCount);
// Add hourglass sprite next to the timer
if (currentGoalGemSprite) {
currentGoalGemSprite.destroy();
}
currentGoalGemSprite = LK.getAsset(goalGemType, {
x: 2048 - 100,
// Position next to the timer
y: 50,
// Align with the timer's top margin
anchorX: .5,
// Anchor right for right alignment
anchorY: .5 // Anchor top for top alignment
});
currentGoalGemSprite.y = goalTxt.y;
currentGoalGemSprite.x = goalBackground.x; // 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 () {
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 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
});
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) {
countdownTxt.setText('GO!');
spinHourglass();
// Bounce effect
var scaleUpDuration = 200; // Duration to scale up in milliseconds
var scaleDownDuration = 200; // Duration to scale down in milliseconds
var maxScale = 1.5; // 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 = 500; // 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
if (progress < 1) {
LK.setTimeout(fadeStep, 16);
} else {
countdownTxt.destroy(); // Remove countdown text after animation
LK.clearInterval(countdownInterval);
}
};
fadeStep();
};
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 scoreBg;
var scoreBgNode = LK.getAsset('scoreBg', {
x: 1024 - 150,
// Centered based on the background size
y: 0,
anchorX: 0.5,
anchorY: 0
});
scoreBgNode.anchor.set(.5);
scoreBgNode.y = 50;
scoreBgNode.alpha = 1; // Set the background transparency to fully opaque to ensure visibility
LK.gui.top.addChild(scoreBgNode);
var scoreTxt = new Text2(score.toString(), _defineProperty(_defineProperty({
size: 110,
weight: 500,
fill: "#ffffff",
x: 1024,
// Center of the screen
y: 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 background;
if (background && game.contains(background)) {
game.removeChild(background);
}
background = game.addChildAt(LK.getAsset(backgroundImageId, {
x: 0,
y: 0,
scaleX: game.width / 2048,
scaleY: game.height / 2732,
anchorX: 0,
anchorY: 0
}), 0);
background.scale.set(game.width / background.width, game.height / background.height);
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();
setRandomGoalGemType();
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
board.addChild(goalBackground);
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
a magical landscape of wonder and joy. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Magic, purple gem. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
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.
Shiny red envelope bao, chinese new years. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Magic greem gem in odd shape. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Flying unicorn fullbody sideview. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Magic Orange Gem. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Magic Blue Drop Shaped Gem. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
remove
Brilliant Gold Checkmark. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Magic diamond. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Enchanted forest. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Celestial reAlm. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Mystic cavern. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.