User prompt
Increase max level number to 50
User prompt
Use “cardback3” asset for cards after level10
User prompt
Add rveal button near to dev button. This button reveals all cards at the level
User prompt
Use “cardback2” asset for card after level5
User prompt
Remove moves gui
Code edit (13 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: null is not an object (evaluating 'firstCard.symbol')' in or related to this line: 'if (firstCard.symbol === secondCard.symbol) {' Line Number: 342
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
Add DEV button to the game. This button must be at center bottom and always visible. This button take you to next level immediately
User prompt
Next button always appear at bottom
User prompt
Add next button to the game. This button take you to next level
User prompt
After matching cards, matching cards must disappear
User prompt
Please fix the bug: 'TypeError: Cannot use 'in' operator to search for 'scaleX' in null' in or related to this line: 'tween(firstCard, {' Line Number: 356
User prompt
Please fix the bug: 'TypeError: Cannot use 'in' operator to search for 'scaleX' in null' in or related to this line: 'tween(firstCard, {' Line Number: 355
User prompt
Align level indicator to top middle
User prompt
There must be level system for the game. If you match all cards you will go next level. Maximum level number must be 25.
Code edit (1 edits merged)
Please save this source code
User prompt
Card Match Mania
Initial prompt
I want card match game
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Card class: represents a single card in the memory game
var Card = Container.expand(function () {
	var self = Container.call(this);
	// Card properties
	self.symbol = null; // Symbol or id for matching
	self.isFaceUp = false;
	self.isMatched = false;
	self.index = -1; // Position in the grid
	// Card dimensions (will be set in game code)
	self.cardWidth = 0;
	self.cardHeight = 0;
	// Face-down asset (back of card)
	var backAssetId;
	if (typeof currentLevel !== "undefined" && currentLevel > 10) {
		backAssetId = 'CardBack3';
	} else if (typeof currentLevel !== "undefined" && currentLevel > 5) {
		backAssetId = 'CardBack2';
	} else {
		backAssetId = 'cardBack';
	}
	var back = self.attachAsset(backAssetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Face-up asset (front of card, shows symbol)
	var front = self.attachAsset('cardFront', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Symbol text (shows symbol when face up)
	var symbolText = new Text2('', {
		size: 90,
		fill: 0x222222
	});
	symbolText.anchor.set(0.5, 0.5);
	front.addChild(symbolText);
	// Set card size
	self.setSize = function (w, h) {
		self.cardWidth = w;
		self.cardHeight = h;
		back.width = w;
		back.height = h;
		front.width = w;
		front.height = h;
	};
	// Set the symbol for this card
	self.setSymbol = function (symbol) {
		self.symbol = symbol;
		symbolText.setText(symbol);
	};
	// Flip the card to face up (with animation)
	self.flipUp = function (_onFinish) {
		if (self.isFaceUp || self.isMatched) {
			return;
		}
		self.isFaceUp = true;
		// Animate flip: scaleX 1 -> 0, swap, 0 -> 1
		tween(self, {
			scaleX: 0
		}, {
			duration: 120,
			easing: tween.cubicIn,
			onFinish: function onFinish() {
				back.visible = false;
				front.visible = true;
				tween(self, {
					scaleX: 1
				}, {
					duration: 120,
					easing: tween.cubicOut,
					onFinish: function onFinish() {
						if (_onFinish) {
							_onFinish();
						}
					}
				});
			}
		});
	};
	// Flip the card to face down (with animation)
	self.flipDown = function (_onFinish2) {
		if (!self.isFaceUp || self.isMatched) {
			return;
		}
		self.isFaceUp = false;
		// Animate flip: scaleX 1 -> 0, swap, 0 -> 1
		tween(self, {
			scaleX: 0
		}, {
			duration: 120,
			easing: tween.cubicIn,
			onFinish: function onFinish() {
				front.visible = false;
				back.visible = true;
				tween(self, {
					scaleX: 1
				}, {
					duration: 120,
					easing: tween.cubicOut,
					onFinish: function onFinish() {
						if (_onFinish2) {
							_onFinish2();
						}
					}
				});
			}
		});
	};
	// Instantly show face up (no animation)
	self.showFaceUp = function () {
		self.isFaceUp = true;
		self.scaleX = 1;
		back.visible = false;
		front.visible = true;
	};
	// Instantly show face down (no animation)
	self.showFaceDown = function () {
		self.isFaceUp = false;
		self.scaleX = 1;
		front.visible = false;
		back.visible = true;
	};
	// Mark as matched (disable interaction, highlight)
	self.setMatched = function () {
		self.isMatched = true;
		// Subtle highlight
		tween(self, {
			tint: 0xA0FFA0
		}, {
			duration: 300,
			easing: tween.linear
		});
	};
	// Handle tap/click
	self.down = function (x, y, obj) {
		if (self.isFaceUp || self.isMatched || game.lockInput) {
			return;
		}
		game.onCardTapped(self);
	};
	// Initialize: show face down
	self.showFaceDown();
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x2e3a4f // Deep blue background
});
/**** 
* Game Code
****/ 
// Tween plugin for card flip and reveal animations
// --- Card symbols (use simple emojis for MVP) ---
var cardSymbols = ["🍎", "🍌", "🍇", "🍉", "🍒", "🍋", "🍓", "🍍", "🥝", "🥑", "🍊", "🍐", "🍈", "🍑", "🥥", "🍅"];
// --- Game settings ---
var maxLevel = 25;
var currentLevel = 1;
// Level configuration: grid size per level (increase difficulty)
function getLevelConfig(level) {
	// Level 1-5: 4x4, 6-10: 5x4, 11-15: 6x5, 16-20: 6x6, 21-25: 7x6
	if (level <= 5) {
		return {
			cols: 4,
			rows: 4
		};
	}
	if (level <= 10) {
		return {
			cols: 5,
			rows: 4
		};
	}
	if (level <= 15) {
		return {
			cols: 6,
			rows: 5
		};
	}
	if (level <= 20) {
		return {
			cols: 6,
			rows: 6
		};
	}
	return {
		cols: 7,
		rows: 6
	};
}
var gridCols = getLevelConfig(currentLevel).cols;
var gridRows = getLevelConfig(currentLevel).rows;
var totalPairs = gridCols * gridRows / 2;
var cardSpacing = 36; // px between cards
// --- Card assets (simple colored rectangles) ---
// --- Game state ---
var cards = []; // All card objects
var firstCard = null;
var secondCard = null;
var lockInput = false; // Prevent input during animations
var moves = 0;
var matchesFound = 0;
var timer = null;
var elapsedTime = 0; // in seconds
var timerText = null;
var movesText = null;
// --- GUI: Moves, Timer, Level ---
var levelText = new Text2('Level: 1', {
	size: 80,
	fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
timerText = new Text2('Time: 0s', {
	size: 80,
	fill: 0xFFFFFF
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
// Position GUI elements (timer right, avoid top-left 100x100)
// Align level indicator to top middle using LK.gui.top
levelText.x = -10;
levelText.y = 20;
timerText.x = 500;
timerText.y = 20;
// --- Helper: Shuffle array (Fisher-Yates) ---
function shuffleArray(arr) {
	for (var i = arr.length - 1; i > 0; i--) {
		var j = Math.floor(Math.random() * (i + 1));
		var temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
}
// --- Layout cards ---
function layoutCards() {
	// Remove old cards if any
	for (var i = 0; i < cards.length; i++) {
		cards[i].destroy();
	}
	cards = [];
	// Prepare symbols (duplicate and shuffle)
	var symbols = [];
	for (var i = 0; i < totalPairs; i++) {
		symbols.push(cardSymbols[i]);
		symbols.push(cardSymbols[i]);
	}
	shuffleArray(symbols);
	// Card size: fit grid to 2048x2732 with spacing
	var availableWidth = 2048 - cardSpacing * (gridCols + 1);
	var availableHeight = 1800 - cardSpacing * (gridRows + 1); // leave space for GUI
	var cardWidth = Math.floor(availableWidth / gridCols);
	var cardHeight = Math.floor(availableHeight / gridRows);
	// Center grid
	var gridPixelWidth = cardWidth * gridCols + cardSpacing * (gridCols - 1);
	var gridPixelHeight = cardHeight * gridRows + cardSpacing * (gridRows - 1);
	var startX = Math.floor((2048 - gridPixelWidth) / 2) + cardWidth / 2;
	var startY = 350 + cardHeight / 2; // leave space for GUI
	// Create cards
	for (var row = 0; row < gridRows; row++) {
		for (var col = 0; col < gridCols; col++) {
			var idx = row * gridCols + col;
			var card = new Card();
			card.setSize(cardWidth, cardHeight);
			card.setSymbol(symbols[idx]);
			card.index = idx;
			card.x = startX + col * (cardWidth + cardSpacing);
			card.y = startY + row * (cardHeight + cardSpacing);
			card.showFaceDown();
			game.addChild(card);
			cards.push(card);
		}
	}
}
// --- Reset game state ---
function resetGame() {
	firstCard = null;
	secondCard = null;
	lockInput = false;
	moves = 0;
	matchesFound = 0;
	elapsedTime = 0;
	if (typeof levelText !== "undefined") {
		levelText.setText('Level: ' + currentLevel);
	}
	// Update grid size for this level
	var config = getLevelConfig(currentLevel);
	gridCols = config.cols;
	gridRows = config.rows;
	totalPairs = gridCols * gridRows / 2;
	timerText.setText('Time: 0s');
	layoutCards();
	if (timer) {
		LK.clearInterval(timer);
	}
	timer = LK.setInterval(function () {
		elapsedTime++;
		timerText.setText('Time: ' + elapsedTime + 's');
	}, 1000);
}
// --- Card tap handler ---
game.onCardTapped = function (card) {
	if (lockInput || card.isFaceUp || card.isMatched) {
		return;
	}
	if (!firstCard) {
		firstCard = card;
		card.flipUp();
	} else if (!secondCard && card !== firstCard) {
		secondCard = card;
		lockInput = true;
		card.flipUp(function () {
			// Check for match after both are face up
			LK.setTimeout(function () {
				checkMatch();
			}, 350);
		});
	}
};
// --- Check for match ---
function checkMatch() {
	moves++;
	if (firstCard && secondCard && firstCard.symbol === secondCard.symbol) {
		// Match!
		firstCard.setMatched();
		secondCard.setMatched();
		matchesFound++;
		// Subtle scale animation for matched cards, then disappear
		if (firstCard && secondCard) {
			var matched1 = firstCard;
			var matched2 = secondCard;
			if (matched1) {
				tween(matched1, {
					scaleX: 1.15,
					scaleY: 1.15
				}, {
					duration: 120,
					easing: tween.cubicOut,
					onFinish: function onFinish() {
						if (matched1) {
							tween(matched1, {
								scaleX: 0,
								scaleY: 0,
								alpha: 0
							}, {
								duration: 180,
								onFinish: function onFinish() {
									if (matched1) {
										matched1.destroy();
									}
								}
							});
						}
					}
				});
			}
			if (matched2) {
				tween(matched2, {
					scaleX: 1.15,
					scaleY: 1.15
				}, {
					duration: 120,
					easing: tween.cubicOut,
					onFinish: function onFinish() {
						if (matched2) {
							tween(matched2, {
								scaleX: 0,
								scaleY: 0,
								alpha: 0
							}, {
								duration: 180,
								onFinish: function onFinish() {
									if (matched2) {
										matched2.destroy();
									}
								}
							});
						}
					}
				});
			}
		}
		// Check for win
		if (matchesFound === totalPairs) {
			LK.clearInterval(timer);
			LK.setScore(moves); // Use moves as score (lower is better)
			if (currentLevel < maxLevel) {
				currentLevel++;
				// Short delay before next level
				LK.setTimeout(function () {
					resetGame();
				}, 1200);
			} else {
				LK.showYouWin();
			}
		}
		// Reset selection
		firstCard = null;
		secondCard = null;
		lockInput = false;
	} else {
		// Not a match: flip both back after short delay
		LK.setTimeout(function () {
			firstCard.flipDown();
			secondCard.flipDown(function () {
				firstCard = null;
				secondCard = null;
				lockInput = false;
			});
		}, 600);
	}
}
// --- Game update (not used for logic, but required) ---
game.update = function () {
	// No per-frame logic needed for MVP
};
// --- DEV Button: Center bottom, always visible, go to next level ---
var devBtn = new Text2('DEV', {
	size: 90,
	fill: 0xFF00FF,
	font: "Impact"
});
devBtn.anchor.set(0.5, 1);
// Place DEV button slightly left of center
devBtn.x = -120;
devBtn.y = -50;
LK.gui.bottom.addChild(devBtn);
// DEV button handler: go to next level immediately (max 25)
devBtn.down = function (x, y, obj) {
	if (currentLevel < maxLevel) {
		currentLevel++;
		resetGame();
	} else {
		LK.showYouWin();
	}
};
// --- Reveal Button: Center bottom, always visible, reveals all cards ---
var revealBtn = new Text2('Reveal', {
	size: 90,
	fill: 0x00CCFF,
	font: "Impact"
});
revealBtn.anchor.set(0.5, 1);
// Place Reveal button slightly right of center
revealBtn.x = 120;
revealBtn.y = -50;
LK.gui.bottom.addChild(revealBtn);
// Reveal button handler: flip all cards face up (if not matched)
revealBtn.down = function (x, y, obj) {
	for (var i = 0; i < cards.length; i++) {
		var card = cards[i];
		if (!card.isFaceUp && !card.isMatched) {
			card.flipUp();
		}
	}
};
// --- Start game ---
resetGame();
// --- Game over handler (reset on game over) ---
game.onGameOver = function () {
	if (timer) {
		LK.clearInterval(timer);
	}
	currentLevel = 1;
	resetGame();
};
// --- Win handler (reset on win) ---
game.onYouWin = function () {
	if (timer) {
		LK.clearInterval(timer);
	}
	currentLevel = 1;
	// Game will reset automatically by LK
}; ===================================================================
--- original.js
+++ change.js
@@ -17,9 +17,16 @@
 	// Card dimensions (will be set in game code)
 	self.cardWidth = 0;
 	self.cardHeight = 0;
 	// Face-down asset (back of card)
-	var backAssetId = typeof currentLevel !== "undefined" && currentLevel > 5 ? 'CardBack2' : 'cardBack';
+	var backAssetId;
+	if (typeof currentLevel !== "undefined" && currentLevel > 10) {
+		backAssetId = 'CardBack3';
+	} else if (typeof currentLevel !== "undefined" && currentLevel > 5) {
+		backAssetId = 'CardBack2';
+	} else {
+		backAssetId = 'cardBack';
+	}
 	var back = self.attachAsset(backAssetId, {
 		anchorX: 0.5,
 		anchorY: 0.5
 	});