/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0, currentLevel: 1 }); /**** * Classes ****/ var Card = Container.expand(function (cardValue) { var self = Container.call(this); // The card's value (which determines its matching pair) self.cardValue = cardValue; // Card state self.isFlipped = false; self.isMatched = false; // Create card back (visible when card is face down) var back = self.attachAsset('cardBack', { anchorX: 0.5, anchorY: 0.5 }); // Create card front (visible when card is face up) var front = self.attachAsset('cardFront', { anchorX: 0.5, anchorY: 0.5, visible: false }); // Create card symbol (identifies the card) var symbol = self.attachAsset('cardMatch' + (cardValue % 10 + 1), { anchorX: 0.5, anchorY: 0.5, visible: false }); // Center the symbol on the card symbol.x = 0; symbol.y = 0; // Method to flip card face up self.flipUp = function () { if (self.isFlipped || self.isMatched) { return false; } LK.getSound('flip').play(); self.isFlipped = true; // Hide back, show front and symbol tween(back, { scaleX: 0 }, { duration: 150, onFinish: function onFinish() { back.visible = false; front.visible = true; symbol.visible = true; tween(front, { scaleX: 1 }, { duration: 150 }); tween(symbol, { scaleX: 1 }, { duration: 150 }); } }); return true; }; // Method to flip card face down self.flipDown = function () { if (!self.isFlipped || self.isMatched) { return; } self.isFlipped = false; // Hide front and symbol, show back tween(front, { scaleX: 0 }, { duration: 150, onFinish: function onFinish() { front.visible = false; symbol.visible = false; back.visible = true; tween(back, { scaleX: 1 }, { duration: 150 }); } }); }; // Method to mark card as matched self.setMatched = function () { self.isMatched = true; tween(self, { alpha: 0.7 }, { duration: 300 }); }; // Event handler for card click/tap self.down = function (x, y, obj) { if (!gameActive || self.isMatched || self.isFlipped) { return; } var flipped = self.flipUp(); if (flipped) { cardsFlipped.push(self); checkForMatch(); } }; // Pre-scale the back to ensure proper initial state front.scaleX = 0; symbol.scaleX = 0; return self; }); var Timer = Container.expand(function (duration) { var self = Container.call(this); self.duration = duration || 60000; // Default 60 seconds self.timeRemaining = self.duration; self.isRunning = false; // Create timer background var background = self.attachAsset('timerBarBg', { anchorX: 0, anchorY: 0.5 }); // Create timer bar that will shrink var bar = self.attachAsset('timerBar', { anchorX: 0, anchorY: 0.5 }); // Method to start the timer self.start = function () { self.timeRemaining = self.duration; self.isRunning = true; self.updateDisplay(); }; // Method to stop the timer self.stop = function () { self.isRunning = false; }; // Method to reset the timer self.reset = function (newDuration) { if (newDuration) { self.duration = newDuration; } self.timeRemaining = self.duration; self.updateDisplay(); }; // Update timer display based on time remaining self.updateDisplay = function () { var percentRemaining = self.timeRemaining / self.duration; bar.scale.x = Math.max(0, percentRemaining); }; // Method to update timer each frame self.update = function () { if (!self.isRunning) { return; } self.timeRemaining -= 16.67; // Approximate ms per frame at 60fps if (self.timeRemaining <= 0) { self.timeRemaining = 0; self.isRunning = false; if (gameActive) { gameActive = false; LK.showGameOver(); } } self.updateDisplay(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x34495e }); /**** * Game Code ****/ // Game state variables var gameActive = false; var cards = []; var cardsFlipped = []; var pairsFound = 0; var totalPairs = 0; var currentLevel = storage.currentLevel || 1; var score = 0; var moves = 0; var gridSize = 4; // Initial grid size (4x4) var previewTime = 3000; // Initial preview time in ms // UI elements var timer; var scoreTxt; var levelTxt; var movesTxt; // Initialize the game function initGame() { // Play background music LK.playMusic('gameMusic'); // Set up UI elements setupUI(); // Determine level settings calculateLevelSettings(); // Create card grid createCardGrid(); // Start the level with preview phase startLevel(); } // Set up UI elements function setupUI() { // Create timer timer = new Timer(60000); // 60 seconds timer.x = 2048 / 2 - 900; // Center timer horizontally timer.y = 100; game.addChild(timer); // Create score text scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(1, 0); LK.gui.topRight.addChild(scoreTxt); // Create level text levelTxt = new Text2('Level: ' + currentLevel, { size: 60, fill: 0xFFFFFF }); levelTxt.anchor.set(0, 0); LK.gui.topRight.addChild(levelTxt); levelTxt.y = 70; // Create moves text movesTxt = new Text2('Moves: 0', { size: 60, fill: 0xFFFFFF }); movesTxt.anchor.set(0, 0); LK.gui.topRight.addChild(movesTxt); movesTxt.y = 140; } // Calculate settings based on current level function calculateLevelSettings() { // Increase grid size every 3 levels if (currentLevel <= 3) { gridSize = 4; // 4x4 grid (16 cards, 8 pairs) } else if (currentLevel <= 6) { gridSize = 6; // 6x6 grid (36 cards, 18 pairs) } else { gridSize = 8; // 8x8 grid (64 cards, 32 pairs) } // Decrease preview time as levels increase previewTime = Math.max(1000, 3000 - (currentLevel - 1) * 300); // Adjust timer based on grid size var timerDuration = 30000 + gridSize * gridSize * 500; timer.reset(timerDuration); // Reset moves counter moves = 0; updateMovesText(); } // Create the grid of cards for the current level function createCardGrid() { // Clear any existing cards for (var i = 0; i < cards.length; i++) { if (cards[i].parent) { cards[i].parent.removeChild(cards[i]); } } cards = []; cardsFlipped = []; pairsFound = 0; // Calculate total pairs based on grid size totalPairs = gridSize * gridSize / 2; // Create array of card values (pairs) var cardValues = []; for (var i = 0; i < totalPairs; i++) { cardValues.push(i); cardValues.push(i); } // Shuffle the card values shuffleArray(cardValues); // Calculate card size and spacing based on grid size var cardSpacing = 20; var cardWidth = 200; var cardHeight = 280; // Calculate total grid width and height var gridWidth = gridSize * cardWidth + (gridSize - 1) * cardSpacing; var gridHeight = gridSize * cardHeight + (gridSize - 1) * cardSpacing; // Starting position for the grid (centered on screen) var startX = (2048 - gridWidth) / 2 + cardWidth / 2; var startY = (2732 - gridHeight) / 2 + cardHeight / 2; // Create and position cards var index = 0; for (var row = 0; row < gridSize; row++) { for (var col = 0; col < gridSize; col++) { // Ensure we don't try to create more cards than we have values if (index < cardValues.length) { var card = new Card(cardValues[index]); card.x = startX + col * (cardWidth + cardSpacing); card.y = startY + row * (cardHeight + cardSpacing); game.addChild(card); cards.push(card); index++; } } } } // Start a new level function startLevel() { // Reset state cardsFlipped = []; pairsFound = 0; // Update level text levelTxt.setText('Level: ' + currentLevel); // Preview phase - show all cards briefly for (var i = 0; i < cards.length; i++) { cards[i].flipUp(); } // After preview, flip all cards face down and start gameplay LK.setTimeout(function () { for (var i = 0; i < cards.length; i++) { cards[i].flipDown(); } // Start the timer timer.start(); // Activate gameplay gameActive = true; }, previewTime); } // Check if the two flipped cards match function checkForMatch() { if (cardsFlipped.length !== 2) { return; } // Increment moves moves++; updateMovesText(); // Get the two flipped cards var card1 = cardsFlipped[0]; var card2 = cardsFlipped[1]; // Disable further interactions temporarily gameActive = false; // Check if cards match if (card1.cardValue === card2.cardValue) { // Cards match! LK.getSound('match').play(); // Mark both cards as matched card1.setMatched(); card2.setMatched(); // Increment pairs found pairsFound++; // Add score score += 100 + Math.floor(timer.timeRemaining / 100); updateScoreText(); // Check if level is complete if (pairsFound >= totalPairs) { levelComplete(); } else { // Re-enable gameplay for next move cardsFlipped = []; gameActive = true; } } else { // Cards don't match, flip them back LK.getSound('noMatch').play(); LK.setTimeout(function () { card1.flipDown(); card2.flipDown(); cardsFlipped = []; gameActive = true; }, 1000); } } // Handle level completion function levelComplete() { // Stop the timer timer.stop(); // Play level complete sound LK.getSound('levelComplete').play(); // Add time bonus var timeBonus = Math.floor(timer.timeRemaining / 10); score += timeBonus; updateScoreText(); // Update high score if needed if (score > storage.highScore) { storage.highScore = score; } // Increment level currentLevel++; storage.currentLevel = currentLevel; // Show you win screen or proceed to next level LK.setTimeout(function () { if (currentLevel > 10) { // Player completed all levels LK.showYouWin(); } else { // Set up next level calculateLevelSettings(); createCardGrid(); startLevel(); } }, 1500); } // Update the score text function updateScoreText() { scoreTxt.setText('Score: ' + score); } // Update the moves text function updateMovesText() { movesTxt.setText('Moves: ' + moves); } // Utility function to shuffle an array function shuffleArray(array) { for (var i = array.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = array[i]; array[i] = array[j]; array[j] = temp; } return array; } // Game update function game.update = function () { // Update timer if it exists if (timer) { timer.update(); } }; // Initialize game when loaded initGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
currentLevel: 1
});
/****
* Classes
****/
var Card = Container.expand(function (cardValue) {
var self = Container.call(this);
// The card's value (which determines its matching pair)
self.cardValue = cardValue;
// Card state
self.isFlipped = false;
self.isMatched = false;
// Create card back (visible when card is face down)
var back = self.attachAsset('cardBack', {
anchorX: 0.5,
anchorY: 0.5
});
// Create card front (visible when card is face up)
var front = self.attachAsset('cardFront', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
// Create card symbol (identifies the card)
var symbol = self.attachAsset('cardMatch' + (cardValue % 10 + 1), {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
// Center the symbol on the card
symbol.x = 0;
symbol.y = 0;
// Method to flip card face up
self.flipUp = function () {
if (self.isFlipped || self.isMatched) {
return false;
}
LK.getSound('flip').play();
self.isFlipped = true;
// Hide back, show front and symbol
tween(back, {
scaleX: 0
}, {
duration: 150,
onFinish: function onFinish() {
back.visible = false;
front.visible = true;
symbol.visible = true;
tween(front, {
scaleX: 1
}, {
duration: 150
});
tween(symbol, {
scaleX: 1
}, {
duration: 150
});
}
});
return true;
};
// Method to flip card face down
self.flipDown = function () {
if (!self.isFlipped || self.isMatched) {
return;
}
self.isFlipped = false;
// Hide front and symbol, show back
tween(front, {
scaleX: 0
}, {
duration: 150,
onFinish: function onFinish() {
front.visible = false;
symbol.visible = false;
back.visible = true;
tween(back, {
scaleX: 1
}, {
duration: 150
});
}
});
};
// Method to mark card as matched
self.setMatched = function () {
self.isMatched = true;
tween(self, {
alpha: 0.7
}, {
duration: 300
});
};
// Event handler for card click/tap
self.down = function (x, y, obj) {
if (!gameActive || self.isMatched || self.isFlipped) {
return;
}
var flipped = self.flipUp();
if (flipped) {
cardsFlipped.push(self);
checkForMatch();
}
};
// Pre-scale the back to ensure proper initial state
front.scaleX = 0;
symbol.scaleX = 0;
return self;
});
var Timer = Container.expand(function (duration) {
var self = Container.call(this);
self.duration = duration || 60000; // Default 60 seconds
self.timeRemaining = self.duration;
self.isRunning = false;
// Create timer background
var background = self.attachAsset('timerBarBg', {
anchorX: 0,
anchorY: 0.5
});
// Create timer bar that will shrink
var bar = self.attachAsset('timerBar', {
anchorX: 0,
anchorY: 0.5
});
// Method to start the timer
self.start = function () {
self.timeRemaining = self.duration;
self.isRunning = true;
self.updateDisplay();
};
// Method to stop the timer
self.stop = function () {
self.isRunning = false;
};
// Method to reset the timer
self.reset = function (newDuration) {
if (newDuration) {
self.duration = newDuration;
}
self.timeRemaining = self.duration;
self.updateDisplay();
};
// Update timer display based on time remaining
self.updateDisplay = function () {
var percentRemaining = self.timeRemaining / self.duration;
bar.scale.x = Math.max(0, percentRemaining);
};
// Method to update timer each frame
self.update = function () {
if (!self.isRunning) {
return;
}
self.timeRemaining -= 16.67; // Approximate ms per frame at 60fps
if (self.timeRemaining <= 0) {
self.timeRemaining = 0;
self.isRunning = false;
if (gameActive) {
gameActive = false;
LK.showGameOver();
}
}
self.updateDisplay();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x34495e
});
/****
* Game Code
****/
// Game state variables
var gameActive = false;
var cards = [];
var cardsFlipped = [];
var pairsFound = 0;
var totalPairs = 0;
var currentLevel = storage.currentLevel || 1;
var score = 0;
var moves = 0;
var gridSize = 4; // Initial grid size (4x4)
var previewTime = 3000; // Initial preview time in ms
// UI elements
var timer;
var scoreTxt;
var levelTxt;
var movesTxt;
// Initialize the game
function initGame() {
// Play background music
LK.playMusic('gameMusic');
// Set up UI elements
setupUI();
// Determine level settings
calculateLevelSettings();
// Create card grid
createCardGrid();
// Start the level with preview phase
startLevel();
}
// Set up UI elements
function setupUI() {
// Create timer
timer = new Timer(60000); // 60 seconds
timer.x = 2048 / 2 - 900; // Center timer horizontally
timer.y = 100;
game.addChild(timer);
// Create score text
scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(scoreTxt);
// Create level text
levelTxt = new Text2('Level: ' + currentLevel, {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(levelTxt);
levelTxt.y = 70;
// Create moves text
movesTxt = new Text2('Moves: 0', {
size: 60,
fill: 0xFFFFFF
});
movesTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(movesTxt);
movesTxt.y = 140;
}
// Calculate settings based on current level
function calculateLevelSettings() {
// Increase grid size every 3 levels
if (currentLevel <= 3) {
gridSize = 4; // 4x4 grid (16 cards, 8 pairs)
} else if (currentLevel <= 6) {
gridSize = 6; // 6x6 grid (36 cards, 18 pairs)
} else {
gridSize = 8; // 8x8 grid (64 cards, 32 pairs)
}
// Decrease preview time as levels increase
previewTime = Math.max(1000, 3000 - (currentLevel - 1) * 300);
// Adjust timer based on grid size
var timerDuration = 30000 + gridSize * gridSize * 500;
timer.reset(timerDuration);
// Reset moves counter
moves = 0;
updateMovesText();
}
// Create the grid of cards for the current level
function createCardGrid() {
// Clear any existing cards
for (var i = 0; i < cards.length; i++) {
if (cards[i].parent) {
cards[i].parent.removeChild(cards[i]);
}
}
cards = [];
cardsFlipped = [];
pairsFound = 0;
// Calculate total pairs based on grid size
totalPairs = gridSize * gridSize / 2;
// Create array of card values (pairs)
var cardValues = [];
for (var i = 0; i < totalPairs; i++) {
cardValues.push(i);
cardValues.push(i);
}
// Shuffle the card values
shuffleArray(cardValues);
// Calculate card size and spacing based on grid size
var cardSpacing = 20;
var cardWidth = 200;
var cardHeight = 280;
// Calculate total grid width and height
var gridWidth = gridSize * cardWidth + (gridSize - 1) * cardSpacing;
var gridHeight = gridSize * cardHeight + (gridSize - 1) * cardSpacing;
// Starting position for the grid (centered on screen)
var startX = (2048 - gridWidth) / 2 + cardWidth / 2;
var startY = (2732 - gridHeight) / 2 + cardHeight / 2;
// Create and position cards
var index = 0;
for (var row = 0; row < gridSize; row++) {
for (var col = 0; col < gridSize; col++) {
// Ensure we don't try to create more cards than we have values
if (index < cardValues.length) {
var card = new Card(cardValues[index]);
card.x = startX + col * (cardWidth + cardSpacing);
card.y = startY + row * (cardHeight + cardSpacing);
game.addChild(card);
cards.push(card);
index++;
}
}
}
}
// Start a new level
function startLevel() {
// Reset state
cardsFlipped = [];
pairsFound = 0;
// Update level text
levelTxt.setText('Level: ' + currentLevel);
// Preview phase - show all cards briefly
for (var i = 0; i < cards.length; i++) {
cards[i].flipUp();
}
// After preview, flip all cards face down and start gameplay
LK.setTimeout(function () {
for (var i = 0; i < cards.length; i++) {
cards[i].flipDown();
}
// Start the timer
timer.start();
// Activate gameplay
gameActive = true;
}, previewTime);
}
// Check if the two flipped cards match
function checkForMatch() {
if (cardsFlipped.length !== 2) {
return;
}
// Increment moves
moves++;
updateMovesText();
// Get the two flipped cards
var card1 = cardsFlipped[0];
var card2 = cardsFlipped[1];
// Disable further interactions temporarily
gameActive = false;
// Check if cards match
if (card1.cardValue === card2.cardValue) {
// Cards match!
LK.getSound('match').play();
// Mark both cards as matched
card1.setMatched();
card2.setMatched();
// Increment pairs found
pairsFound++;
// Add score
score += 100 + Math.floor(timer.timeRemaining / 100);
updateScoreText();
// Check if level is complete
if (pairsFound >= totalPairs) {
levelComplete();
} else {
// Re-enable gameplay for next move
cardsFlipped = [];
gameActive = true;
}
} else {
// Cards don't match, flip them back
LK.getSound('noMatch').play();
LK.setTimeout(function () {
card1.flipDown();
card2.flipDown();
cardsFlipped = [];
gameActive = true;
}, 1000);
}
}
// Handle level completion
function levelComplete() {
// Stop the timer
timer.stop();
// Play level complete sound
LK.getSound('levelComplete').play();
// Add time bonus
var timeBonus = Math.floor(timer.timeRemaining / 10);
score += timeBonus;
updateScoreText();
// Update high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
// Increment level
currentLevel++;
storage.currentLevel = currentLevel;
// Show you win screen or proceed to next level
LK.setTimeout(function () {
if (currentLevel > 10) {
// Player completed all levels
LK.showYouWin();
} else {
// Set up next level
calculateLevelSettings();
createCardGrid();
startLevel();
}
}, 1500);
}
// Update the score text
function updateScoreText() {
scoreTxt.setText('Score: ' + score);
}
// Update the moves text
function updateMovesText() {
movesTxt.setText('Moves: ' + moves);
}
// Utility function to shuffle an array
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
// Game update function
game.update = function () {
// Update timer if it exists
if (timer) {
timer.update();
}
};
// Initialize game when loaded
initGame();
mg. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
cardfront mg. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
mg. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
cardback mg. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows