/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
bestScore: 0,
level: 1
});
/****
* Classes
****/
var Card = Container.expand(function (cardId, pairId) {
var self = Container.call(this);
self.cardId = cardId;
self.pairId = pairId;
self.isFlipped = false;
self.isMatched = false;
// Card back (shown when not flipped)
var cardBack = self.attachAsset('cardBack', {
anchorX: 0.5,
anchorY: 0.5
});
// Card front (the actual pattern/color)
var cardFront = self.attachAsset('pair' + pairId, {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
if (pairId === 'J') {
cardFront = self.attachAsset('pairJ', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
}
if (pairId === 'K') {
cardFront = self.attachAsset('pairK', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
}
if (pairId === 'L') {
cardFront = self.attachAsset('pairL', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
}
self.back = cardBack;
self.front = cardFront;
// Method to flip the card
self.flip = function () {
if (self.isMatched || self.isFlipped) {
return false;
}
LK.getSound('flip').play();
self.isFlipped = true;
// Animate the flip
tween(cardBack, {
scaleX: 0
}, {
duration: 150,
easing: tween.easeIn,
onFinish: function onFinish() {
cardBack.visible = false;
cardFront.visible = true;
tween(cardFront, {
scaleX: 1
}, {
duration: 150,
easing: tween.easeOut
});
}
});
return true;
};
// Method to flip back
self.flipBack = function () {
if (self.isMatched || !self.isFlipped) {
return;
}
self.isFlipped = false;
tween(cardFront, {
scaleX: 0
}, {
duration: 150,
easing: tween.easeIn,
onFinish: function onFinish() {
cardFront.visible = false;
cardBack.visible = true;
tween(cardBack, {
scaleX: 1
}, {
duration: 150,
easing: tween.easeOut
});
}
});
};
// Method to mark card as matched
self.setMatched = function () {
self.isMatched = true;
// Create a matched effect
var matchEffect = self.attachAsset('cardMatch', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
tween(matchEffect, {
alpha: 0.7
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
matchEffect.destroy(); // Remove the matched effect after animation
self.removeChild(matchEffect); // Ensure the effect is removed from the display list
}
});
};
// Handle card selection
self.down = function (x, y, obj) {
if (!gameActive || processingMatch || self.isMatched) {
return;
}
var flipped = self.flip();
if (flipped) {
checkForMatch(self);
}
};
return self;
});
var Clover = Container.expand(function (isFourLeaf) {
var self = Container.call(this);
self.isFourLeaf = isFourLeaf;
var cloverAsset;
if (!isFourLeaf) {
cloverAsset = self.attachAsset('threeLeafClover', {
anchorX: 0.5,
anchorY: 0.5
});
}
self.down = function (x, y, obj) {
if (!finderGameActive) {
return;
}
if (self.isFourLeaf) {
finderScore++;
finderCounterText.setText(' : ' + finderScore);
LK.getSound('match').play();
// Remove the four leaf clover after found
self.destroy();
} else {
finderThreeLeafCount++;
finderThreeLeafCounterText.setText(' : ' + finderThreeLeafCount);
LK.getSound('flip').play();
// Remove the three leaf clover after found
self.destroy();
}
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
self.speed = 5;
self.lastY = 0;
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 // Updated to use the latest LK engine default background color
});
/****
* Game Code
****/
// Game state variables
var cards = [];
var gridWidth = 4;
var gridHeight = 3;
var cardWidth = 180;
var cardHeight = 250;
var cardSpacing = 200; // Increased vertical spacing between cards
var flippedCards = [];
var gameActive = false;
var processingMatch = false;
var moves = 0;
var pairsFound = 0;
var level = 1;
var totalPairs = gridWidth * gridHeight / 2;
var gameStartTime;
var coins = [];
var clickerGameActive = false;
// UI Elements
var titleText = LK.getAsset('MainMenuTitle', {
anchorX: 0.5,
anchorY: 0
});
LK.gui.top.addChild(titleText);
titleText.y = 50 + 77;
var movesText = new Text2('Moves: 0', {
size: 60,
fill: 0xFFFFFF
});
movesText.anchor.set(0, 0);
LK.gui.topLeft.addChild(movesText);
movesText.x = 120;
movesText.y = 150;
movesText.visible = false;
var levelText = new Text2('Level: ' + level, {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(1, 0);
LK.gui.topRight.addChild(levelText);
levelText.x = -120;
levelText.y = 150;
levelText.visible = false;
var timerText = new Text2('Time: 0s', {
size: 60,
fill: 0xFFFFFF
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
timerText.y = 150;
timerText.visible = false;
// Mode Selector Menu
var modeMenu = new Container();
var mwBackground = modeMenu.attachAsset('MW', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 2048 / 2040,
scaleY: 2732 / 2800
});
game.addChild(modeMenu);
// Game selector title
var modeTitle = new Text2("Select Game", {
size: 80,
fill: 0xFFA500,
fontWeight: 'bolder'
});
modeTitle.anchor.set(0.5, 1);
modeMenu.addChild(modeTitle);
modeTitle.x = 2048 / 2;
modeTitle.y = 2732 - 100 - 77;
// Game selector buttons
var games = ['Memory Card Game', 'Clicker', 'Finder'];
var modeButtons = [];
var modeButtonY = 2732 / 2 - 300;
var modeButtonVerticalSpacing = 350;
var modeStartX = 2048 / 2;
var selectedMode = 'Memory Card Game';
var finderGameActive = false;
var finderScore = 0;
var finderCounterText;
var finderThreeLeafCount = 0;
var finderThreeLeafCounterText;
var finderSpawnInterval;
var finderCloversSpawned = 0;
var coinCatcherTimeRemaining = 60;
var coinCatcherTimerText;
var coinCatcherTimeInterval;
var clickerScoreText;
var coinSpawnInterval;
for (var modeIdx = 0; modeIdx < games.length; modeIdx++) {
var modeName = games[modeIdx];
var modeBtn = new Container();
var modeBtnBg;
if (modeName === 'Memory Card Game') {
modeBtnBg = modeBtn.attachAsset('MCGB', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
} else if (modeName === 'Memory Card Game') {
// Already handled above
} else if (modeName === 'Clicker') {
modeBtnBg = modeBtn.attachAsset('CCB', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1,
scaleY: 1
});
} else {
modeBtnBg = modeBtn.attachAsset('CHB', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.9,
scaleY: 0.75
});
}
if (modeName !== 'Memory Card Game' && modeName !== 'Clicker' && modeName !== 'Finder') {
var modeBtnText = new Text2(modeName, {
size: 50,
fill: 0xFFFFFF
});
modeBtnText.anchor.set(0.5, 0.5);
modeBtnText.x = 0;
modeBtnText.y = 0;
modeBtn.addChild(modeBtnText);
}
modeBtn.modeName = modeName;
modeBtn.x = modeStartX;
modeBtn.y = modeButtonY + modeIdx * modeButtonVerticalSpacing;
modeMenu.addChild(modeBtn);
modeButtons.push(modeBtn);
modeBtn.down = function (btnMode) {
return function (x, y, obj) {
selectedMode = btnMode;
confirmModeBtn.visible = true;
// Update visual feedback for selected mode
for (var updateModeBtn = 0; updateModeBtn < modeButtons.length; updateModeBtn++) {
var modeBtnBgChild = modeButtons[updateModeBtn].children[0];
if (modeButtons[updateModeBtn].modeName === btnMode) {
tween(modeBtnBgChild, {
tint: 0xFFCC00
}, {
duration: 300,
easing: tween.easeOut
});
} else {
tween(modeBtnBgChild, {
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
}
}
};
}(modeName);
}
// Confirm mode button
var confirmModeBtn = new Container();
var confirmModeBtnBg = confirmModeBtn.attachAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5
});
var confirmModeBtnText = new Text2('Confirm', {
size: 60,
fill: 0x000000,
fontWeight: 'bold',
stroke: 0x000000,
strokeThickness: 4 //{2T_new}
});
confirmModeBtnText.anchor.set(0.5, 0.5);
confirmModeBtn.addChild(confirmModeBtnText);
confirmModeBtn.x = 2048 / 2;
confirmModeBtn.y = modeButtonY + (games.length - 1) * modeButtonVerticalSpacing + 200 + 123;
confirmModeBtn.visible = false;
modeMenu.addChild(confirmModeBtn);
confirmModeBtn.down = function (x, y, obj) {
// Remove Mode Menu
game.removeChild(modeMenu);
// If Finder mode is selected, start Finder game directly
if (selectedMode === 'Finder') {
initializeFinderGame();
} else if (selectedMode === 'Clicker') {
// Clicker mode starts directly without level selector
initializeClickerGame();
} else {
// Otherwise show Card Game Menu for level selection
game.addChild(cardGameMenu);
}
};
// Card Game Menu
var cardGameMenu = new Container();
var mwBackgroundCardGame = cardGameMenu.attachAsset('MW', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 2048 / 2040,
scaleY: 2732 / 2800
});
// Do not add to game yet - will be added after mode selection
// Level selector buttons
var levelButtons = [];
var levelButtonY = 2732 / 2 - 250;
var buttonSpacing = 337.5;
var centerButtonIndex = 2; // Level 3 is at index 2 (0-indexed)
var totalButtons = 5;
var totalButtonWidth = totalButtons * 270 + (totalButtons - 1) * buttonSpacing; // 270 is approximate button width after scaling
var startX = 2048 / 2 - totalButtonWidth / 2 + 700 - 25;
for (var levelNum = 1; levelNum <= 5; levelNum++) {
var levelBtn = new Container();
var levelBtnBg = levelBtn.attachAsset('LB', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.9,
scaleY: 0.75
});
var levelBtnText = new Text2('Level ' + levelNum, {
size: 50,
fill: 0xFFFFFF
});
levelBtnText.anchor.set(0.5, 0.5);
levelBtnText.x = 0;
levelBtnText.y = 0;
levelBtn.addChild(levelBtnText);
levelBtn.levelNum = levelNum;
levelBtn.x = startX + (levelNum - 1) * buttonSpacing;
levelBtn.y = levelButtonY;
cardGameMenu.addChild(levelBtn);
levelButtons.push(levelBtn);
levelBtn.down = function (btnLevel) {
return function (x, y, obj) {
level = btnLevel;
startBtn.visible = true;
// Update visual feedback for selected level
for (var updateBtn = 0; updateBtn < levelButtons.length; updateBtn++) {
var btnBg = levelButtons[updateBtn].children[0];
if (levelButtons[updateBtn].levelNum === btnLevel) {
tween(btnBg, {
tint: 0xFFCC00
}, {
duration: 300,
easing: tween.easeOut
});
} else {
tween(btnBg, {
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
}
}
};
}(levelNum);
}
// Add cardGameMenu to game after mode selection confirmation
var startBtn = new Container();
var startBtnBg = startBtn.attachAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5
});
var startBtnText = new Text2('Start Game', {
size: 60,
fill: 0x000000,
fontWeight: 'bold',
stroke: 0x000000,
strokeThickness: 4 //{3B_new}
});
startBtnText.anchor.set(0.5, 0.5);
startBtn.addChild(startBtnText);
startBtn.x = 2048 / 2;
startBtn.y = 2732 / 2 + 150;
startBtn.visible = false;
cardGameMenu.addChild(startBtn);
// Back to menu button for level selector
var backToMenuBtnLevelSelector = new Container();
var backToMenuBtnLevelSelectorBg = backToMenuBtnLevelSelector.attachAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5
});
var backToMenuBtnLevelSelectorText = new Text2('Back', {
size: 60,
fill: 0x000000,
fontWeight: 'bold',
stroke: 0x000000,
strokeThickness: 4 //{3I_new}
});
backToMenuBtnLevelSelectorText.anchor.set(0.5, 0.5);
backToMenuBtnLevelSelector.addChild(backToMenuBtnLevelSelectorText);
backToMenuBtnLevelSelector.x = 2048 / 2;
backToMenuBtnLevelSelector.y = 2732 / 2 + 150 + 150 + 123;
cardGameMenu.addChild(backToMenuBtnLevelSelector);
// Back button handler for level selector
backToMenuBtnLevelSelector.down = function (x, y, obj) {
// Remove Card Game Menu from display
game.removeChild(cardGameMenu);
// Show mode menu again
game.addChild(modeMenu);
};
// Timer update
var timerInterval;
function startTimer() {
gameStartTime = Date.now();
timerInterval = LK.setInterval(function () {
var elapsed = Math.floor((Date.now() - gameStartTime) / 1000);
timerText.setText('Time: ' + elapsed + 's');
}, 1000);
}
// Initialize the Clicker game
function initializeClickerGame() {
// Hide title text for Clicker game
titleText.visible = false;
// Add CCW background
var grassBg = game.addChild(LK.getAsset('CCW', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 2048 / 2040,
scaleY: 2732 / 3000
}));
// Initialize clicker game state
coins = [];
var clickerScore = 0;
var potX = 2048 / 2;
var potY = 2600;
var potWidth = 250;
var potHeight = 200;
var coinSpawnRate = 500;
clickerGameActive = true;
// Create pot at bottom of screen
var pot = game.addChild(LK.getAsset('pot', {
anchorX: 0.5,
anchorY: 0.5,
x: potX,
y: potY
}));
// Create score display
if (!clickerScoreText) {
clickerScoreText = new Text2('Coins Caught: 0', {
size: 60,
fill: 0xFFD700
});
clickerScoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(clickerScoreText);
clickerScoreText.y = 150 - 123;
} else {
clickerScoreText.setText('Coins Caught: 0');
}
// Create time counter display
coinCatcherTimeRemaining = 60;
if (!coinCatcherTimerText) {
coinCatcherTimerText = new Text2('Time: 60s', {
size: 60,
fill: 0xFFD700
});
coinCatcherTimerText.anchor.set(0.5, 0);
LK.gui.top.addChild(coinCatcherTimerText);
coinCatcherTimerText.x = 0;
coinCatcherTimerText.y = 150 - 123 + 70;
} else {
coinCatcherTimerText.setText('Time: 60s');
}
// Handle pot movement
game.move = function (x, y, obj) {
pot.x = x;
};
// Spawn coins at regular intervals
var coinSpawnInterval = LK.setInterval(function () {
if (!clickerGameActive) {
return;
}
if (coins.length > 50) {
return;
}
var newCoin = new Coin();
var randomX = Math.random() * 2048;
newCoin.x = randomX;
newCoin.y = -50;
newCoin.lastY = newCoin.y;
coins.push(newCoin);
game.addChild(newCoin);
}, coinSpawnRate);
// Start countdown timer for Coin Catcher game
coinCatcherTimeInterval = LK.setInterval(function () {
if (!clickerGameActive) {
return;
}
coinCatcherTimeRemaining--;
coinCatcherTimerText.setText('Time: ' + coinCatcherTimeRemaining + 's');
if (coinCatcherTimeRemaining <= 0) {
clickerGameActive = false;
LK.clearInterval(coinSpawnInterval);
LK.clearInterval(coinCatcherTimeInterval);
// Display score when time reaches zero
var finalScore = clickerScore * 10;
LK.setScore(finalScore);
var scoreText = new Text2('Final Score: ' + finalScore, {
size: 80,
fill: 0xFFD700
});
scoreText.anchor.set(0.5, 0.5);
scoreText.x = 2048 / 2;
scoreText.y = 2732 / 2;
game.addChild(scoreText);
}
}, 1000);
// Update game state
var originalUpdate = game.update;
game.update = function () {
if (!clickerGameActive) {
return;
}
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (coin.lastY === undefined) coin.lastY = coin.y;
// Check if coin fell off screen
if (coin.lastY >= -50 && coin.y > 2732) {
coin.destroy();
coins.splice(i, 1);
continue;
}
// Check collision with pot
if (coin.intersects(pot)) {
clickerScore++;
clickerScoreText.setText('Coins Caught: ' + clickerScore);
LK.getSound('match').play();
coin.destroy();
coins.splice(i, 1);
// Change pot to potfull when 10 coins caught
if (clickerScore === 10) {
game.removeChild(pot);
pot = game.addChild(LK.getAsset('Potfull', {
anchorX: 0.5,
anchorY: 0.5,
x: potX,
y: potY
}));
} //{4A_new}
continue;
}
coin.lastY = coin.y;
}
};
// Show back button
backToMenuBtn.visible = true;
// Play background music
LK.playMusic('bgmusic');
}
// Initialize the Finder game
function initializeFinderGame() {
// Hide title text for Finder game
titleText.visible = false;
// Add grass background
var grassBg = game.addChild(LK.getAsset('grassBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Clear any existing clovers
for (var i = game.children.length - 1; i >= 0; i--) {
var child = game.children[i];
if (child instanceof Clover) {
child.destroy();
}
}
finderGameActive = true;
finderScore = 0;
finderCloversSpawned = 0;
// Create counter for four leaf clovers found with 4L asset
var finderCounterContainer = new Container();
var fourLeafAsset = finderCounterContainer.attachAsset('4L', {
anchorX: 0.5,
anchorY: 0.5 //{4n_new2}
}); //{4n_new3}
finderCounterText = new Text2(' : 0', {
size: 60,
fill: 0xFFFFFF
});
finderCounterText.anchor.set(0, 0.5);
finderCounterContainer.addChild(finderCounterText);
finderCounterText.x = 60;
finderCounterText.y = 0;
LK.gui.top.addChild(finderCounterContainer);
finderCounterContainer.y = 150 - 123;
finderCounterContainer.x = 1024 - 333 - 123 - 100 - 333 - 77 + 7 + 12 + 12;
// Create counter for three leaf clovers found with 3L asset
var finderThreeLeafCounterContainer = new Container();
var threeLeafAsset = finderThreeLeafCounterContainer.attachAsset('3L', {
anchorX: 0.5,
anchorY: 0.5 //{4q_new2}
}); //{4q_new3}
finderThreeLeafCounterText = new Text2(' : 0', {
size: 60,
fill: 0xFFFFFF
});
finderThreeLeafCounterText.anchor.set(0, 0.5);
finderThreeLeafCounterContainer.addChild(finderThreeLeafCounterText);
finderThreeLeafCounterText.x = 60;
finderThreeLeafCounterText.y = 0;
LK.gui.top.addChild(finderThreeLeafCounterContainer);
finderThreeLeafCounterContainer.y = 150 - 123;
finderThreeLeafCounterContainer.x = 333 - 33 - 100 - 333 - 77 + 7;
// Reset three leaf clover count
finderThreeLeafCount = 0;
// Start spawning clovers at random positions every second
finderSpawnInterval = LK.setInterval(function () {
if (!finderGameActive) {
return;
}
var isFourLeaf = (finderCloversSpawned + 1) % 7 === 0;
var clover = new Clover(isFourLeaf);
// Random position on screen (avoiding top area where UI is)
var randomX = Math.random() * (2048 - 200) + 100;
var randomY = Math.random() * (2732 - 600) + 300;
clover.x = randomX;
clover.y = randomY;
// Start with scale 0
clover.scaleX = 0;
clover.scaleY = 0;
// Create a 4leafclover container with alternating assets for every 7th clover
if (isFourLeaf) {
var fourLeafCloverContainer = new Container();
var isEvenSpecial = Math.floor(finderCloversSpawned / 7) % 2 === 0;
var assetToUse = isEvenSpecial ? 'fourLeafClover' : 'fourLeafClover4';
var fourLeafCloverAsset = fourLeafCloverContainer.attachAsset(assetToUse, {
anchorX: 0.5,
anchorY: 0.5 //{4w_new}
}); //{4x_new}
clover.addChild(fourLeafCloverContainer);
}
game.addChild(clover);
// Animate scale to 1
tween(clover, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeOut
});
finderCloversSpawned++;
}, 1000);
// Show back button
backToMenuBtn.visible = true;
// Play background music
LK.playMusic('bgmusic');
}
// Initialize the game board
function initializeBoard() {
// Hide title text for Memory Card Game
titleText.visible = false;
// Add MW background for memory card game
var mwBackgroundBoard = game.addChild(LK.getAsset('MW', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 2048 / 2040 * 1.4,
scaleY: 2732 / 2800 * 1.4
}));
// Clear existing cards
for (var i = 0; i < cards.length; i++) {
cards[i].destroy();
}
cards = [];
flippedCards = [];
pairsFound = 0;
moves = 0;
processingMatch = false;
gameActive = true;
movesText.setText('Moves: 0');
// Update level text display
levelText.setText('Level: ' + level);
// Show HUD elements when game starts
movesText.visible = true;
levelText.visible = true;
timerText.visible = true;
backToMenuBtn.visible = true;
// Set level-based grid size
if (level === 1) {
gridWidth = 3;
gridHeight = 3;
} else if (level === 2) {
gridWidth = 3;
gridHeight = 4;
} else if (level === 3) {
gridWidth = 4;
gridHeight = 4;
} else if (level === 4) {
gridWidth = 4;
gridHeight = 5;
} else if (level >= 5) {
gridWidth = 5;
gridHeight = 5;
}
// Calculate total cards accounting for skipped center card on level 1 and level 5
var totalCards = gridWidth * gridHeight;
if (level === 1 || level === 5) {
totalCards = totalCards - 1;
}
totalPairs = totalCards / 2;
// Create cards and assign pairs
var pairIds = [];
if (level >= 5) {
// Level 5: Create 12 pairs (A-L) each appearing exactly twice to fill 24 cards
// 12 pairs × 2 = 24 cards with perfect pairing
for (var p = 0; p < 12; p++) {
var pairLetter = String.fromCharCode(65 + p);
pairIds.push(pairLetter);
pairIds.push(pairLetter);
}
} else {
// Levels 1-4: Create exact pairs needed without repetition
for (var p = 0; p < totalPairs; p++) {
var pairLetter = String.fromCharCode(65 + p);
pairIds.push(pairLetter);
pairIds.push(pairLetter);
}
}
// Shuffle pairs
for (var s = pairIds.length - 1; s > 0; s--) {
var j = Math.floor(Math.random() * (s + 1));
var temp = pairIds[s];
pairIds[s] = pairIds[j];
pairIds[j] = temp;
}
// Determine the grid layout positioning
var gridTotalWidth = gridWidth * cardWidth + (gridWidth - 1) * cardSpacing;
var gridTotalHeight = gridHeight * cardHeight + (gridHeight - 1) * cardSpacing;
var startX = (2048 - gridTotalWidth) / 2;
var startY = (2732 - gridTotalHeight) / 2 + (level >= 5 ? 100 : 0);
// Move level 4 cards down by 123 units
if (level === 4) {
startY += 123;
}
// Create and position the cards
var cardIndex = 0;
for (var row = 0; row < gridHeight; row++) {
for (var col = 0; col < gridWidth; col++) {
// Skip center card for level 1 and level 5
if (level === 1 && row === 1 && col === 1 || level === 5 && row === 2 && col === 2) {
continue;
}
var x = startX + col * (cardWidth + cardSpacing) + cardWidth / 2;
var y = startY + row * (cardHeight + cardSpacing) + cardHeight / 2;
var card = new Card(cardIndex, pairIds[cardIndex]);
card.x = x;
card.y = y;
cards.push(card);
game.addChild(card);
cardIndex++;
}
}
// Start the timer
startTimer();
// Play background music
LK.playMusic('bgmusic');
}
// Check for matching cards
function checkForMatch(card) {
flippedCards.push(card);
if (flippedCards.length === 2) {
processingMatch = true;
moves++;
movesText.setText('Moves: ' + moves);
var card1 = flippedCards[0];
var card2 = flippedCards[1];
if (card1.pairId === card2.pairId) {
// Match found
LK.setTimeout(function () {
LK.getSound('match').play();
card1.setMatched();
card2.setMatched();
flippedCards = [];
processingMatch = false;
// Increment pairs found
pairsFound++;
// Check for win condition
if (pairsFound === totalPairs) {
gameWon();
}
}, 500);
} else {
// No match
LK.setTimeout(function () {
LK.getSound('nomatch').play();
card1.flipBack();
card2.flipBack();
flippedCards = [];
processingMatch = false;
}, 1000);
}
}
}
// Handle game win
function gameWon() {
gameActive = false;
// Calculate score based on moves and time
var timeElapsed = Math.floor((Date.now() - gameStartTime) / 1000);
LK.clearInterval(timerInterval);
// Calculate score (fewer moves and less time = higher score)
var baseScore = 1000;
var movePenalty = moves * 10;
var timePenalty = timeElapsed * 2;
var score = Math.max(100, baseScore - movePenalty - timePenalty);
// Update best score
if (score > storage.bestScore) {
storage.bestScore = score;
}
// Set the score
LK.setScore(score);
// Play win sound
LK.getSound('win').play();
// Show win message
LK.setTimeout(function () {
// Hide HUD elements
movesText.visible = false;
levelText.visible = false;
timerText.visible = false;
// Level up
level++;
storage.level = level;
// Show you win screen
LK.showYouWin();
// Load the next level after a short delay to ensure transition
LK.setTimeout(function () {
initializeBoard();
gameActive = true; // Reactivate the game
startTimer(); // Restart the timer for the new level
}, 2000); // Delay to allow the win screen to show
}, 1500);
}
// Start button interaction
startBtn.down = function (x, y, obj) {
// Remove Card Game Menu from display
game.removeChild(cardGameMenu);
// Initialize appropriate game based on selected mode
if (selectedMode === 'Memory Card Game') {
initializeBoard();
} else if (selectedMode === 'Finder') {
initializeFinderGame();
} else {
// Handle other game modes here in the future
console.log("Selected game: " + selectedMode);
}
};
// Create back to menu button
var backToMenuBtn = new Container();
var backToMenuBtnBg = backToMenuBtn.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
});
var backToMenuBtnText = new Text2('MENU', {
size: 40,
fill: 0xFFFFFF
});
backToMenuBtnText.anchor.set(0.5, 0.5);
backToMenuBtn.addChild(backToMenuBtnText);
backToMenuBtn.visible = false;
LK.gui.topRight.addChild(backToMenuBtn);
backToMenuBtn.x = -76;
backToMenuBtn.y = 74;
// Back button handler
backToMenuBtn.down = function (x, y, obj) {
// Immediately disable game logic to prevent any further updates
clickerGameActive = false;
gameActive = false;
finderGameActive = false;
// Stop all game-specific timers
if (timerInterval) {
LK.clearInterval(timerInterval);
}
if (coinCatcherTimeInterval) {
LK.clearInterval(coinCatcherTimeInterval);
}
// Clear coin spawn interval for Clicker game
if (coinSpawnInterval) {
LK.clearInterval(coinSpawnInterval);
}
coinSpawnInterval = undefined;
if (finderSpawnInterval) {
LK.clearInterval(finderSpawnInterval);
}
// Destroy all coins from the game and remove from display
for (var coinIdx = coins.length - 1; coinIdx >= 0; coinIdx--) {
if (coins[coinIdx].parent) {
game.removeChild(coins[coinIdx]);
}
coins[coinIdx].destroy();
}
coins = [];
// Stop music
LK.stopMusic();
// Reset game states
gameActive = false;
finderGameActive = false;
clickerGameActive = false;
// Clear game board
for (var clearIdx = game.children.length - 1; clearIdx >= 0; clearIdx--) {
var child = game.children[clearIdx];
child.destroy();
}
// Hide HUD elements
movesText.visible = false;
levelText.visible = false;
timerText.visible = false;
backToMenuBtn.visible = false;
titleText.visible = true;
// Remove UI text elements from GUI
if (clickerScoreText && clickerScoreText.parent) {
LK.gui.top.removeChild(clickerScoreText);
}
clickerScoreText = null;
if (coinCatcherTimerText && coinCatcherTimerText.parent) {
LK.gui.top.removeChild(coinCatcherTimerText);
}
coinCatcherTimerText = null;
if (finderCounterText && finderCounterText.parent) {
LK.gui.top.removeChild(finderCounterText.parent);
}
finderCounterText = null;
if (finderThreeLeafCounterText && finderThreeLeafCounterText.parent) {
LK.gui.top.removeChild(finderThreeLeafCounterText.parent);
}
finderThreeLeafCounterText = null;
// Clear game event handlers
game.move = undefined;
game.update = function () {
// Nothing needed here as the game logic is event-driven
};
// Reset coins array
coins = [];
// Show mode menu again
game.addChild(modeMenu);
};
// Handle game update
game.update = function () {
// Nothing needed here as the game logic is event-driven
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
bestScore: 0,
level: 1
});
/****
* Classes
****/
var Card = Container.expand(function (cardId, pairId) {
var self = Container.call(this);
self.cardId = cardId;
self.pairId = pairId;
self.isFlipped = false;
self.isMatched = false;
// Card back (shown when not flipped)
var cardBack = self.attachAsset('cardBack', {
anchorX: 0.5,
anchorY: 0.5
});
// Card front (the actual pattern/color)
var cardFront = self.attachAsset('pair' + pairId, {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
if (pairId === 'J') {
cardFront = self.attachAsset('pairJ', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
}
if (pairId === 'K') {
cardFront = self.attachAsset('pairK', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
}
if (pairId === 'L') {
cardFront = self.attachAsset('pairL', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
}
self.back = cardBack;
self.front = cardFront;
// Method to flip the card
self.flip = function () {
if (self.isMatched || self.isFlipped) {
return false;
}
LK.getSound('flip').play();
self.isFlipped = true;
// Animate the flip
tween(cardBack, {
scaleX: 0
}, {
duration: 150,
easing: tween.easeIn,
onFinish: function onFinish() {
cardBack.visible = false;
cardFront.visible = true;
tween(cardFront, {
scaleX: 1
}, {
duration: 150,
easing: tween.easeOut
});
}
});
return true;
};
// Method to flip back
self.flipBack = function () {
if (self.isMatched || !self.isFlipped) {
return;
}
self.isFlipped = false;
tween(cardFront, {
scaleX: 0
}, {
duration: 150,
easing: tween.easeIn,
onFinish: function onFinish() {
cardFront.visible = false;
cardBack.visible = true;
tween(cardBack, {
scaleX: 1
}, {
duration: 150,
easing: tween.easeOut
});
}
});
};
// Method to mark card as matched
self.setMatched = function () {
self.isMatched = true;
// Create a matched effect
var matchEffect = self.attachAsset('cardMatch', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
tween(matchEffect, {
alpha: 0.7
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
matchEffect.destroy(); // Remove the matched effect after animation
self.removeChild(matchEffect); // Ensure the effect is removed from the display list
}
});
};
// Handle card selection
self.down = function (x, y, obj) {
if (!gameActive || processingMatch || self.isMatched) {
return;
}
var flipped = self.flip();
if (flipped) {
checkForMatch(self);
}
};
return self;
});
var Clover = Container.expand(function (isFourLeaf) {
var self = Container.call(this);
self.isFourLeaf = isFourLeaf;
var cloverAsset;
if (!isFourLeaf) {
cloverAsset = self.attachAsset('threeLeafClover', {
anchorX: 0.5,
anchorY: 0.5
});
}
self.down = function (x, y, obj) {
if (!finderGameActive) {
return;
}
if (self.isFourLeaf) {
finderScore++;
finderCounterText.setText(' : ' + finderScore);
LK.getSound('match').play();
// Remove the four leaf clover after found
self.destroy();
} else {
finderThreeLeafCount++;
finderThreeLeafCounterText.setText(' : ' + finderThreeLeafCount);
LK.getSound('flip').play();
// Remove the three leaf clover after found
self.destroy();
}
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
self.speed = 5;
self.lastY = 0;
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 // Updated to use the latest LK engine default background color
});
/****
* Game Code
****/
// Game state variables
var cards = [];
var gridWidth = 4;
var gridHeight = 3;
var cardWidth = 180;
var cardHeight = 250;
var cardSpacing = 200; // Increased vertical spacing between cards
var flippedCards = [];
var gameActive = false;
var processingMatch = false;
var moves = 0;
var pairsFound = 0;
var level = 1;
var totalPairs = gridWidth * gridHeight / 2;
var gameStartTime;
var coins = [];
var clickerGameActive = false;
// UI Elements
var titleText = LK.getAsset('MainMenuTitle', {
anchorX: 0.5,
anchorY: 0
});
LK.gui.top.addChild(titleText);
titleText.y = 50 + 77;
var movesText = new Text2('Moves: 0', {
size: 60,
fill: 0xFFFFFF
});
movesText.anchor.set(0, 0);
LK.gui.topLeft.addChild(movesText);
movesText.x = 120;
movesText.y = 150;
movesText.visible = false;
var levelText = new Text2('Level: ' + level, {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(1, 0);
LK.gui.topRight.addChild(levelText);
levelText.x = -120;
levelText.y = 150;
levelText.visible = false;
var timerText = new Text2('Time: 0s', {
size: 60,
fill: 0xFFFFFF
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
timerText.y = 150;
timerText.visible = false;
// Mode Selector Menu
var modeMenu = new Container();
var mwBackground = modeMenu.attachAsset('MW', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 2048 / 2040,
scaleY: 2732 / 2800
});
game.addChild(modeMenu);
// Game selector title
var modeTitle = new Text2("Select Game", {
size: 80,
fill: 0xFFA500,
fontWeight: 'bolder'
});
modeTitle.anchor.set(0.5, 1);
modeMenu.addChild(modeTitle);
modeTitle.x = 2048 / 2;
modeTitle.y = 2732 - 100 - 77;
// Game selector buttons
var games = ['Memory Card Game', 'Clicker', 'Finder'];
var modeButtons = [];
var modeButtonY = 2732 / 2 - 300;
var modeButtonVerticalSpacing = 350;
var modeStartX = 2048 / 2;
var selectedMode = 'Memory Card Game';
var finderGameActive = false;
var finderScore = 0;
var finderCounterText;
var finderThreeLeafCount = 0;
var finderThreeLeafCounterText;
var finderSpawnInterval;
var finderCloversSpawned = 0;
var coinCatcherTimeRemaining = 60;
var coinCatcherTimerText;
var coinCatcherTimeInterval;
var clickerScoreText;
var coinSpawnInterval;
for (var modeIdx = 0; modeIdx < games.length; modeIdx++) {
var modeName = games[modeIdx];
var modeBtn = new Container();
var modeBtnBg;
if (modeName === 'Memory Card Game') {
modeBtnBg = modeBtn.attachAsset('MCGB', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
} else if (modeName === 'Memory Card Game') {
// Already handled above
} else if (modeName === 'Clicker') {
modeBtnBg = modeBtn.attachAsset('CCB', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1,
scaleY: 1
});
} else {
modeBtnBg = modeBtn.attachAsset('CHB', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.9,
scaleY: 0.75
});
}
if (modeName !== 'Memory Card Game' && modeName !== 'Clicker' && modeName !== 'Finder') {
var modeBtnText = new Text2(modeName, {
size: 50,
fill: 0xFFFFFF
});
modeBtnText.anchor.set(0.5, 0.5);
modeBtnText.x = 0;
modeBtnText.y = 0;
modeBtn.addChild(modeBtnText);
}
modeBtn.modeName = modeName;
modeBtn.x = modeStartX;
modeBtn.y = modeButtonY + modeIdx * modeButtonVerticalSpacing;
modeMenu.addChild(modeBtn);
modeButtons.push(modeBtn);
modeBtn.down = function (btnMode) {
return function (x, y, obj) {
selectedMode = btnMode;
confirmModeBtn.visible = true;
// Update visual feedback for selected mode
for (var updateModeBtn = 0; updateModeBtn < modeButtons.length; updateModeBtn++) {
var modeBtnBgChild = modeButtons[updateModeBtn].children[0];
if (modeButtons[updateModeBtn].modeName === btnMode) {
tween(modeBtnBgChild, {
tint: 0xFFCC00
}, {
duration: 300,
easing: tween.easeOut
});
} else {
tween(modeBtnBgChild, {
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
}
}
};
}(modeName);
}
// Confirm mode button
var confirmModeBtn = new Container();
var confirmModeBtnBg = confirmModeBtn.attachAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5
});
var confirmModeBtnText = new Text2('Confirm', {
size: 60,
fill: 0x000000,
fontWeight: 'bold',
stroke: 0x000000,
strokeThickness: 4 //{2T_new}
});
confirmModeBtnText.anchor.set(0.5, 0.5);
confirmModeBtn.addChild(confirmModeBtnText);
confirmModeBtn.x = 2048 / 2;
confirmModeBtn.y = modeButtonY + (games.length - 1) * modeButtonVerticalSpacing + 200 + 123;
confirmModeBtn.visible = false;
modeMenu.addChild(confirmModeBtn);
confirmModeBtn.down = function (x, y, obj) {
// Remove Mode Menu
game.removeChild(modeMenu);
// If Finder mode is selected, start Finder game directly
if (selectedMode === 'Finder') {
initializeFinderGame();
} else if (selectedMode === 'Clicker') {
// Clicker mode starts directly without level selector
initializeClickerGame();
} else {
// Otherwise show Card Game Menu for level selection
game.addChild(cardGameMenu);
}
};
// Card Game Menu
var cardGameMenu = new Container();
var mwBackgroundCardGame = cardGameMenu.attachAsset('MW', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 2048 / 2040,
scaleY: 2732 / 2800
});
// Do not add to game yet - will be added after mode selection
// Level selector buttons
var levelButtons = [];
var levelButtonY = 2732 / 2 - 250;
var buttonSpacing = 337.5;
var centerButtonIndex = 2; // Level 3 is at index 2 (0-indexed)
var totalButtons = 5;
var totalButtonWidth = totalButtons * 270 + (totalButtons - 1) * buttonSpacing; // 270 is approximate button width after scaling
var startX = 2048 / 2 - totalButtonWidth / 2 + 700 - 25;
for (var levelNum = 1; levelNum <= 5; levelNum++) {
var levelBtn = new Container();
var levelBtnBg = levelBtn.attachAsset('LB', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.9,
scaleY: 0.75
});
var levelBtnText = new Text2('Level ' + levelNum, {
size: 50,
fill: 0xFFFFFF
});
levelBtnText.anchor.set(0.5, 0.5);
levelBtnText.x = 0;
levelBtnText.y = 0;
levelBtn.addChild(levelBtnText);
levelBtn.levelNum = levelNum;
levelBtn.x = startX + (levelNum - 1) * buttonSpacing;
levelBtn.y = levelButtonY;
cardGameMenu.addChild(levelBtn);
levelButtons.push(levelBtn);
levelBtn.down = function (btnLevel) {
return function (x, y, obj) {
level = btnLevel;
startBtn.visible = true;
// Update visual feedback for selected level
for (var updateBtn = 0; updateBtn < levelButtons.length; updateBtn++) {
var btnBg = levelButtons[updateBtn].children[0];
if (levelButtons[updateBtn].levelNum === btnLevel) {
tween(btnBg, {
tint: 0xFFCC00
}, {
duration: 300,
easing: tween.easeOut
});
} else {
tween(btnBg, {
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
}
}
};
}(levelNum);
}
// Add cardGameMenu to game after mode selection confirmation
var startBtn = new Container();
var startBtnBg = startBtn.attachAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5
});
var startBtnText = new Text2('Start Game', {
size: 60,
fill: 0x000000,
fontWeight: 'bold',
stroke: 0x000000,
strokeThickness: 4 //{3B_new}
});
startBtnText.anchor.set(0.5, 0.5);
startBtn.addChild(startBtnText);
startBtn.x = 2048 / 2;
startBtn.y = 2732 / 2 + 150;
startBtn.visible = false;
cardGameMenu.addChild(startBtn);
// Back to menu button for level selector
var backToMenuBtnLevelSelector = new Container();
var backToMenuBtnLevelSelectorBg = backToMenuBtnLevelSelector.attachAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5
});
var backToMenuBtnLevelSelectorText = new Text2('Back', {
size: 60,
fill: 0x000000,
fontWeight: 'bold',
stroke: 0x000000,
strokeThickness: 4 //{3I_new}
});
backToMenuBtnLevelSelectorText.anchor.set(0.5, 0.5);
backToMenuBtnLevelSelector.addChild(backToMenuBtnLevelSelectorText);
backToMenuBtnLevelSelector.x = 2048 / 2;
backToMenuBtnLevelSelector.y = 2732 / 2 + 150 + 150 + 123;
cardGameMenu.addChild(backToMenuBtnLevelSelector);
// Back button handler for level selector
backToMenuBtnLevelSelector.down = function (x, y, obj) {
// Remove Card Game Menu from display
game.removeChild(cardGameMenu);
// Show mode menu again
game.addChild(modeMenu);
};
// Timer update
var timerInterval;
function startTimer() {
gameStartTime = Date.now();
timerInterval = LK.setInterval(function () {
var elapsed = Math.floor((Date.now() - gameStartTime) / 1000);
timerText.setText('Time: ' + elapsed + 's');
}, 1000);
}
// Initialize the Clicker game
function initializeClickerGame() {
// Hide title text for Clicker game
titleText.visible = false;
// Add CCW background
var grassBg = game.addChild(LK.getAsset('CCW', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 2048 / 2040,
scaleY: 2732 / 3000
}));
// Initialize clicker game state
coins = [];
var clickerScore = 0;
var potX = 2048 / 2;
var potY = 2600;
var potWidth = 250;
var potHeight = 200;
var coinSpawnRate = 500;
clickerGameActive = true;
// Create pot at bottom of screen
var pot = game.addChild(LK.getAsset('pot', {
anchorX: 0.5,
anchorY: 0.5,
x: potX,
y: potY
}));
// Create score display
if (!clickerScoreText) {
clickerScoreText = new Text2('Coins Caught: 0', {
size: 60,
fill: 0xFFD700
});
clickerScoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(clickerScoreText);
clickerScoreText.y = 150 - 123;
} else {
clickerScoreText.setText('Coins Caught: 0');
}
// Create time counter display
coinCatcherTimeRemaining = 60;
if (!coinCatcherTimerText) {
coinCatcherTimerText = new Text2('Time: 60s', {
size: 60,
fill: 0xFFD700
});
coinCatcherTimerText.anchor.set(0.5, 0);
LK.gui.top.addChild(coinCatcherTimerText);
coinCatcherTimerText.x = 0;
coinCatcherTimerText.y = 150 - 123 + 70;
} else {
coinCatcherTimerText.setText('Time: 60s');
}
// Handle pot movement
game.move = function (x, y, obj) {
pot.x = x;
};
// Spawn coins at regular intervals
var coinSpawnInterval = LK.setInterval(function () {
if (!clickerGameActive) {
return;
}
if (coins.length > 50) {
return;
}
var newCoin = new Coin();
var randomX = Math.random() * 2048;
newCoin.x = randomX;
newCoin.y = -50;
newCoin.lastY = newCoin.y;
coins.push(newCoin);
game.addChild(newCoin);
}, coinSpawnRate);
// Start countdown timer for Coin Catcher game
coinCatcherTimeInterval = LK.setInterval(function () {
if (!clickerGameActive) {
return;
}
coinCatcherTimeRemaining--;
coinCatcherTimerText.setText('Time: ' + coinCatcherTimeRemaining + 's');
if (coinCatcherTimeRemaining <= 0) {
clickerGameActive = false;
LK.clearInterval(coinSpawnInterval);
LK.clearInterval(coinCatcherTimeInterval);
// Display score when time reaches zero
var finalScore = clickerScore * 10;
LK.setScore(finalScore);
var scoreText = new Text2('Final Score: ' + finalScore, {
size: 80,
fill: 0xFFD700
});
scoreText.anchor.set(0.5, 0.5);
scoreText.x = 2048 / 2;
scoreText.y = 2732 / 2;
game.addChild(scoreText);
}
}, 1000);
// Update game state
var originalUpdate = game.update;
game.update = function () {
if (!clickerGameActive) {
return;
}
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (coin.lastY === undefined) coin.lastY = coin.y;
// Check if coin fell off screen
if (coin.lastY >= -50 && coin.y > 2732) {
coin.destroy();
coins.splice(i, 1);
continue;
}
// Check collision with pot
if (coin.intersects(pot)) {
clickerScore++;
clickerScoreText.setText('Coins Caught: ' + clickerScore);
LK.getSound('match').play();
coin.destroy();
coins.splice(i, 1);
// Change pot to potfull when 10 coins caught
if (clickerScore === 10) {
game.removeChild(pot);
pot = game.addChild(LK.getAsset('Potfull', {
anchorX: 0.5,
anchorY: 0.5,
x: potX,
y: potY
}));
} //{4A_new}
continue;
}
coin.lastY = coin.y;
}
};
// Show back button
backToMenuBtn.visible = true;
// Play background music
LK.playMusic('bgmusic');
}
// Initialize the Finder game
function initializeFinderGame() {
// Hide title text for Finder game
titleText.visible = false;
// Add grass background
var grassBg = game.addChild(LK.getAsset('grassBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Clear any existing clovers
for (var i = game.children.length - 1; i >= 0; i--) {
var child = game.children[i];
if (child instanceof Clover) {
child.destroy();
}
}
finderGameActive = true;
finderScore = 0;
finderCloversSpawned = 0;
// Create counter for four leaf clovers found with 4L asset
var finderCounterContainer = new Container();
var fourLeafAsset = finderCounterContainer.attachAsset('4L', {
anchorX: 0.5,
anchorY: 0.5 //{4n_new2}
}); //{4n_new3}
finderCounterText = new Text2(' : 0', {
size: 60,
fill: 0xFFFFFF
});
finderCounterText.anchor.set(0, 0.5);
finderCounterContainer.addChild(finderCounterText);
finderCounterText.x = 60;
finderCounterText.y = 0;
LK.gui.top.addChild(finderCounterContainer);
finderCounterContainer.y = 150 - 123;
finderCounterContainer.x = 1024 - 333 - 123 - 100 - 333 - 77 + 7 + 12 + 12;
// Create counter for three leaf clovers found with 3L asset
var finderThreeLeafCounterContainer = new Container();
var threeLeafAsset = finderThreeLeafCounterContainer.attachAsset('3L', {
anchorX: 0.5,
anchorY: 0.5 //{4q_new2}
}); //{4q_new3}
finderThreeLeafCounterText = new Text2(' : 0', {
size: 60,
fill: 0xFFFFFF
});
finderThreeLeafCounterText.anchor.set(0, 0.5);
finderThreeLeafCounterContainer.addChild(finderThreeLeafCounterText);
finderThreeLeafCounterText.x = 60;
finderThreeLeafCounterText.y = 0;
LK.gui.top.addChild(finderThreeLeafCounterContainer);
finderThreeLeafCounterContainer.y = 150 - 123;
finderThreeLeafCounterContainer.x = 333 - 33 - 100 - 333 - 77 + 7;
// Reset three leaf clover count
finderThreeLeafCount = 0;
// Start spawning clovers at random positions every second
finderSpawnInterval = LK.setInterval(function () {
if (!finderGameActive) {
return;
}
var isFourLeaf = (finderCloversSpawned + 1) % 7 === 0;
var clover = new Clover(isFourLeaf);
// Random position on screen (avoiding top area where UI is)
var randomX = Math.random() * (2048 - 200) + 100;
var randomY = Math.random() * (2732 - 600) + 300;
clover.x = randomX;
clover.y = randomY;
// Start with scale 0
clover.scaleX = 0;
clover.scaleY = 0;
// Create a 4leafclover container with alternating assets for every 7th clover
if (isFourLeaf) {
var fourLeafCloverContainer = new Container();
var isEvenSpecial = Math.floor(finderCloversSpawned / 7) % 2 === 0;
var assetToUse = isEvenSpecial ? 'fourLeafClover' : 'fourLeafClover4';
var fourLeafCloverAsset = fourLeafCloverContainer.attachAsset(assetToUse, {
anchorX: 0.5,
anchorY: 0.5 //{4w_new}
}); //{4x_new}
clover.addChild(fourLeafCloverContainer);
}
game.addChild(clover);
// Animate scale to 1
tween(clover, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeOut
});
finderCloversSpawned++;
}, 1000);
// Show back button
backToMenuBtn.visible = true;
// Play background music
LK.playMusic('bgmusic');
}
// Initialize the game board
function initializeBoard() {
// Hide title text for Memory Card Game
titleText.visible = false;
// Add MW background for memory card game
var mwBackgroundBoard = game.addChild(LK.getAsset('MW', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 2048 / 2040 * 1.4,
scaleY: 2732 / 2800 * 1.4
}));
// Clear existing cards
for (var i = 0; i < cards.length; i++) {
cards[i].destroy();
}
cards = [];
flippedCards = [];
pairsFound = 0;
moves = 0;
processingMatch = false;
gameActive = true;
movesText.setText('Moves: 0');
// Update level text display
levelText.setText('Level: ' + level);
// Show HUD elements when game starts
movesText.visible = true;
levelText.visible = true;
timerText.visible = true;
backToMenuBtn.visible = true;
// Set level-based grid size
if (level === 1) {
gridWidth = 3;
gridHeight = 3;
} else if (level === 2) {
gridWidth = 3;
gridHeight = 4;
} else if (level === 3) {
gridWidth = 4;
gridHeight = 4;
} else if (level === 4) {
gridWidth = 4;
gridHeight = 5;
} else if (level >= 5) {
gridWidth = 5;
gridHeight = 5;
}
// Calculate total cards accounting for skipped center card on level 1 and level 5
var totalCards = gridWidth * gridHeight;
if (level === 1 || level === 5) {
totalCards = totalCards - 1;
}
totalPairs = totalCards / 2;
// Create cards and assign pairs
var pairIds = [];
if (level >= 5) {
// Level 5: Create 12 pairs (A-L) each appearing exactly twice to fill 24 cards
// 12 pairs × 2 = 24 cards with perfect pairing
for (var p = 0; p < 12; p++) {
var pairLetter = String.fromCharCode(65 + p);
pairIds.push(pairLetter);
pairIds.push(pairLetter);
}
} else {
// Levels 1-4: Create exact pairs needed without repetition
for (var p = 0; p < totalPairs; p++) {
var pairLetter = String.fromCharCode(65 + p);
pairIds.push(pairLetter);
pairIds.push(pairLetter);
}
}
// Shuffle pairs
for (var s = pairIds.length - 1; s > 0; s--) {
var j = Math.floor(Math.random() * (s + 1));
var temp = pairIds[s];
pairIds[s] = pairIds[j];
pairIds[j] = temp;
}
// Determine the grid layout positioning
var gridTotalWidth = gridWidth * cardWidth + (gridWidth - 1) * cardSpacing;
var gridTotalHeight = gridHeight * cardHeight + (gridHeight - 1) * cardSpacing;
var startX = (2048 - gridTotalWidth) / 2;
var startY = (2732 - gridTotalHeight) / 2 + (level >= 5 ? 100 : 0);
// Move level 4 cards down by 123 units
if (level === 4) {
startY += 123;
}
// Create and position the cards
var cardIndex = 0;
for (var row = 0; row < gridHeight; row++) {
for (var col = 0; col < gridWidth; col++) {
// Skip center card for level 1 and level 5
if (level === 1 && row === 1 && col === 1 || level === 5 && row === 2 && col === 2) {
continue;
}
var x = startX + col * (cardWidth + cardSpacing) + cardWidth / 2;
var y = startY + row * (cardHeight + cardSpacing) + cardHeight / 2;
var card = new Card(cardIndex, pairIds[cardIndex]);
card.x = x;
card.y = y;
cards.push(card);
game.addChild(card);
cardIndex++;
}
}
// Start the timer
startTimer();
// Play background music
LK.playMusic('bgmusic');
}
// Check for matching cards
function checkForMatch(card) {
flippedCards.push(card);
if (flippedCards.length === 2) {
processingMatch = true;
moves++;
movesText.setText('Moves: ' + moves);
var card1 = flippedCards[0];
var card2 = flippedCards[1];
if (card1.pairId === card2.pairId) {
// Match found
LK.setTimeout(function () {
LK.getSound('match').play();
card1.setMatched();
card2.setMatched();
flippedCards = [];
processingMatch = false;
// Increment pairs found
pairsFound++;
// Check for win condition
if (pairsFound === totalPairs) {
gameWon();
}
}, 500);
} else {
// No match
LK.setTimeout(function () {
LK.getSound('nomatch').play();
card1.flipBack();
card2.flipBack();
flippedCards = [];
processingMatch = false;
}, 1000);
}
}
}
// Handle game win
function gameWon() {
gameActive = false;
// Calculate score based on moves and time
var timeElapsed = Math.floor((Date.now() - gameStartTime) / 1000);
LK.clearInterval(timerInterval);
// Calculate score (fewer moves and less time = higher score)
var baseScore = 1000;
var movePenalty = moves * 10;
var timePenalty = timeElapsed * 2;
var score = Math.max(100, baseScore - movePenalty - timePenalty);
// Update best score
if (score > storage.bestScore) {
storage.bestScore = score;
}
// Set the score
LK.setScore(score);
// Play win sound
LK.getSound('win').play();
// Show win message
LK.setTimeout(function () {
// Hide HUD elements
movesText.visible = false;
levelText.visible = false;
timerText.visible = false;
// Level up
level++;
storage.level = level;
// Show you win screen
LK.showYouWin();
// Load the next level after a short delay to ensure transition
LK.setTimeout(function () {
initializeBoard();
gameActive = true; // Reactivate the game
startTimer(); // Restart the timer for the new level
}, 2000); // Delay to allow the win screen to show
}, 1500);
}
// Start button interaction
startBtn.down = function (x, y, obj) {
// Remove Card Game Menu from display
game.removeChild(cardGameMenu);
// Initialize appropriate game based on selected mode
if (selectedMode === 'Memory Card Game') {
initializeBoard();
} else if (selectedMode === 'Finder') {
initializeFinderGame();
} else {
// Handle other game modes here in the future
console.log("Selected game: " + selectedMode);
}
};
// Create back to menu button
var backToMenuBtn = new Container();
var backToMenuBtnBg = backToMenuBtn.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
});
var backToMenuBtnText = new Text2('MENU', {
size: 40,
fill: 0xFFFFFF
});
backToMenuBtnText.anchor.set(0.5, 0.5);
backToMenuBtn.addChild(backToMenuBtnText);
backToMenuBtn.visible = false;
LK.gui.topRight.addChild(backToMenuBtn);
backToMenuBtn.x = -76;
backToMenuBtn.y = 74;
// Back button handler
backToMenuBtn.down = function (x, y, obj) {
// Immediately disable game logic to prevent any further updates
clickerGameActive = false;
gameActive = false;
finderGameActive = false;
// Stop all game-specific timers
if (timerInterval) {
LK.clearInterval(timerInterval);
}
if (coinCatcherTimeInterval) {
LK.clearInterval(coinCatcherTimeInterval);
}
// Clear coin spawn interval for Clicker game
if (coinSpawnInterval) {
LK.clearInterval(coinSpawnInterval);
}
coinSpawnInterval = undefined;
if (finderSpawnInterval) {
LK.clearInterval(finderSpawnInterval);
}
// Destroy all coins from the game and remove from display
for (var coinIdx = coins.length - 1; coinIdx >= 0; coinIdx--) {
if (coins[coinIdx].parent) {
game.removeChild(coins[coinIdx]);
}
coins[coinIdx].destroy();
}
coins = [];
// Stop music
LK.stopMusic();
// Reset game states
gameActive = false;
finderGameActive = false;
clickerGameActive = false;
// Clear game board
for (var clearIdx = game.children.length - 1; clearIdx >= 0; clearIdx--) {
var child = game.children[clearIdx];
child.destroy();
}
// Hide HUD elements
movesText.visible = false;
levelText.visible = false;
timerText.visible = false;
backToMenuBtn.visible = false;
titleText.visible = true;
// Remove UI text elements from GUI
if (clickerScoreText && clickerScoreText.parent) {
LK.gui.top.removeChild(clickerScoreText);
}
clickerScoreText = null;
if (coinCatcherTimerText && coinCatcherTimerText.parent) {
LK.gui.top.removeChild(coinCatcherTimerText);
}
coinCatcherTimerText = null;
if (finderCounterText && finderCounterText.parent) {
LK.gui.top.removeChild(finderCounterText.parent);
}
finderCounterText = null;
if (finderThreeLeafCounterText && finderThreeLeafCounterText.parent) {
LK.gui.top.removeChild(finderThreeLeafCounterText.parent);
}
finderThreeLeafCounterText = null;
// Clear game event handlers
game.move = undefined;
game.update = function () {
// Nothing needed here as the game logic is event-driven
};
// Reset coins array
coins = [];
// Show mode menu again
game.addChild(modeMenu);
};
// Handle game update
game.update = function () {
// Nothing needed here as the game logic is event-driven
};
yellow rectangle button
Leprechaun on a white papercard with rounded corners, front view.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Golden shamrock pendant. High contrast
3 leaf clover in a white paper card with rounded corners, front view.
Lucky star in a white paper-card with rounded corners, front view.. In-Game asset. 2d. No shadows
Green Hearth in a white paper-card with rounded corners, front view.. In-Game asset. 2d. High contrast. No shadows
Green ribbon with shamrock in a white paper-card with rounded corners, front view..