User prompt
make the screen background dark black
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'undefined')' in or related to this line: 'var track = musicTracks[currentMusicIndex];' Line Number: 734
User prompt
auto-start the music's when game started
User prompt
remove the "Lives: (number)" text
User prompt
Show texts like "Level 1" and "Level Complete" under the cards instead of above them
User prompt
add it to the all buttons and make it fit with the text's
User prompt
add a button bg to the button (use my image "ButtonBG")
User prompt
put it a little more to the right
User prompt
right again
User prompt
a little bit right again
User prompt
a little bit right
User prompt
Place the pause key just below the Level text
User prompt
put the pause button right above the hearts
User prompt
move the pause button a litte up to the hearts
User prompt
move the pause button up to the heartsi
User prompt
move the pause button to the up to cards
User prompt
move the pause button up side
User prompt
move the pause button to the left side (down)
User prompt
move the pause button to the left side
User prompt
Show the "Pause" button in the game (Right up)
User prompt
add a pause button so players can go back to the menu when they start the game and when they click the menu button, the "Resume" and "Menu" options appear
User prompt
While in the game, play "BGMusic1" and "BGMusic2" music in order and repeat in a loop
User prompt
Use the sound file named "Click" when any button is clicked in the menu.
User prompt
Don't start the game without clicking the play button
User prompt
make a menu, add a Play button, a settings button to the menu, when the settings button is clicked, a sound and music on/off button will appear
/**** * 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 states: 'hidden', 'revealed', 'matched' self.state = 'hidden'; self.fruitId = null; // Will be set on creation // Card back (hidden state) var back = self.attachAsset('cardBack', { anchorX: 0.5, anchorY: 0.5 }); self.back = back; // Card front (fruit image, revealed state) // Default to watermelon image, will be replaced by setFruit var front = self.attachAsset('Watermelon', { anchorX: 0.5, anchorY: 0.5 }); self.front = front; self.front.visible = false; // Set fruit image for this card self.setFruit = function (fruitId) { self.fruitId = fruitId; // Map fruitId to asset name in assets section var assetMap = { 'banana': 'Banana', 'cherry': 'Cherry', 'orange': 'Orange', 'grape': 'grape', 'lemon': 'lemon', 'peach': 'Peach', 'strawberry': 'strawberry', 'watermelon': 'Watermelon', 'Coconut': 'Coconut', 'Kiwi': 'Kiwi', 'apple': 'apple', 'Pear': 'Pear', 'Pineapple': 'Pineapple', 'Avocado': 'Avocado', 'Daisy': 'Daisy', 'Rock': 'Rock', 'Water': 'Water' }; var assetName = assetMap[fruitId] || 'fruit'; var fruitAsset = LK.getAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); // Remove old front if present if (self.front && self.front.parent) self.removeChild(self.front); self.front = fruitAsset; self.addChild(self.front); self.front.visible = false; self.front.x = 0; self.front.y = 0; self.back.x = 0; self.back.y = 0; }; // Reveal the card (show fruit) self.reveal = function () { if (self.state !== 'hidden') return; self.state = 'revealed'; self.back.visible = false; self.front.visible = true; // Optional: flip animation tween(self, { scaleX: 0 }, { duration: 80, easing: tween.cubicIn, onFinish: function onFinish() { self.back.visible = false; self.front.visible = true; tween(self, { scaleX: 1 }, { duration: 80, easing: tween.cubicOut }); } }); }; // Hide the card (show back) self.hide = function () { if (self.state !== 'revealed') return; self.state = 'hidden'; // Optional: flip animation tween(self, { scaleX: 0 }, { duration: 80, easing: tween.cubicIn, onFinish: function onFinish() { self.front.visible = false; self.back.visible = true; tween(self, { scaleX: 1 }, { duration: 80, easing: tween.cubicOut }); } }); }; // Mark as matched (permanently revealed) self.match = function () { self.state = 'matched'; self.back.visible = false; self.front.visible = true; // Optional: small scale bounce tween(self, { scaleX: 1.15, scaleY: 1.15 }, { duration: 100, easing: tween.bounceOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); }; // Handle tap self.down = function (x, y, obj) { if (self.state === 'hidden' && !game.lockInput) { game.onCardTapped(self); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a1a }); /**** * Game Code ****/ // Fruit pool (all fruits with images in assets) var fruitIds = ['banana', 'cherry', 'orange', 'grape', 'lemon', 'peach', 'strawberry', 'watermelon', 'Coconut', 'Kiwi', 'apple', 'Pear', 'Pineapple', 'Avocado', 'Daisy', 'Rock', 'Water']; // No need to dynamically create fruit image assets, all are defined in assets section // Game variables var level = 1; var maxLevel = 10; var cards = []; var revealedCards = []; var matchedPairs = 0; var totalPairs = 0; var lives = 0; var maxLives = 0; var lockInput = false; var levelText, livesText, messageText; // Heart/lives display var heartNodes = []; var heartAssetName = 'heart'; // Use a heart image asset (add to assets if not present) var heartSize = 80; var heartSpacing = 20; var heartMargin = 30; // --- MENU SYSTEM --- // Menu container var menuContainer = new Container(); LK.gui.center.addChild(menuContainer); // Play button var playBtn = new Text2('Play', { size: 140, fill: "#fff", font: "Impact" }); playBtn.anchor.set(0.5, 0.5); playBtn.y = -120; menuContainer.addChild(playBtn); // Settings button var settingsBtn = new Text2('Settings', { size: 100, fill: "#fff", font: "Impact" }); settingsBtn.anchor.set(0.5, 0.5); settingsBtn.y = 80; menuContainer.addChild(settingsBtn); // Settings panel (hidden by default) var settingsPanel = new Container(); settingsPanel.visible = false; settingsPanel.y = 250; menuContainer.addChild(settingsPanel); // Sound toggle button var soundOn = true; var soundBtn = new Text2('Sound: On', { size: 80, fill: "#fff", font: "Impact" }); soundBtn.anchor.set(0.5, 0.5); soundBtn.y = 0; settingsPanel.addChild(soundBtn); // Music toggle button var musicOn = true; var musicBtn = new Text2('Music: On', { size: 80, fill: "#fff", font: "Impact" }); musicBtn.anchor.set(0.5, 0.5); musicBtn.y = 120; settingsPanel.addChild(musicBtn); // Menu logic var menuActive = true; function showMenu() { menuContainer.visible = true; levelText.visible = false; livesText.visible = false; messageText.visible = false; pauseBtn.visible = false; pauseMenuContainer.visible = false; // Hide all cards and hearts if present for (var i = 0; i < cards.length; i++) { cards[i].visible = false; } for (var i = 0; i < heartNodes.length; i++) { heartNodes[i].visible = false; } menuActive = true; lockInput = true; game.lockInput = true; } function hideMenu() { menuContainer.visible = false; levelText.visible = true; livesText.visible = true; pauseBtn.visible = true; pauseMenuContainer.visible = false; for (var i = 0; i < cards.length; i++) { cards[i].visible = true; } for (var i = 0; i < heartNodes.length; i++) { heartNodes[i].visible = true; } menuActive = false; lockInput = false; game.lockInput = false; } // Play button handler playBtn.down = function (x, y, obj) { if (soundOn) LK.getSound('Click').play(); hideMenu(); // Start/restart game startLevel(1); }; // Settings button handler settingsBtn.down = function (x, y, obj) { if (soundOn) LK.getSound('Click').play(); settingsPanel.visible = !settingsPanel.visible; }; // Sound toggle handler soundBtn.down = function (x, y, obj) { if (soundOn) LK.getSound('Click').play(); soundOn = !soundOn; soundBtn.setText('Sound: ' + (soundOn ? 'On' : 'Off')); LK.setSoundEnabled && LK.setSoundEnabled(soundOn); }; // Music toggle handler musicBtn.down = function (x, y, obj) { if (soundOn) LK.getSound('Click').play(); musicOn = !musicOn; musicBtn.setText('Music: ' + (musicOn ? 'On' : 'Off')); LK.setMusicEnabled && LK.setMusicEnabled(musicOn); }; // --- END MENU SYSTEM --- // GUI setup levelText = new Text2('Level 1', { size: 90, fill: "#fff" }); levelText.anchor.set(0.5, 0); LK.gui.top.addChild(levelText); livesText = new Text2('Lives: 3', { size: 90, fill: "#fff" }); livesText.anchor.set(0.5, 0); LK.gui.top.addChild(livesText); livesText.y = 100; livesText.x = 2048 / 2; // Message text (centered, for "Level X", "You Win", etc) messageText = new Text2('', { size: 140, fill: "#fff" }); messageText.anchor.set(0.5, 0.5); LK.gui.center.addChild(messageText); messageText.visible = false; // --- PAUSE BUTTON & PAUSE MENU --- var pauseBtn = new Text2('Pause', { size: 80, fill: "#fff", font: "Impact" }); pauseBtn.anchor.set(0.5, 0.5); // Place pause button at top right, but not in the top 100px (menu icon area) pauseBtn.x = 2048 - 180; pauseBtn.y = 100; LK.gui.top.addChild(pauseBtn); pauseBtn.visible = false; // Pause menu container var pauseMenuContainer = new Container(); pauseMenuContainer.visible = false; LK.gui.center.addChild(pauseMenuContainer); // Resume button var resumeBtn = new Text2('Resume', { size: 120, fill: "#fff", font: "Impact" }); resumeBtn.anchor.set(0.5, 0.5); resumeBtn.y = -100; pauseMenuContainer.addChild(resumeBtn); // Menu button (in pause menu) var pauseMenuBtn = new Text2('Menu', { size: 120, fill: "#fff", font: "Impact" }); pauseMenuBtn.anchor.set(0.5, 0.5); pauseMenuBtn.y = 100; pauseMenuContainer.addChild(pauseMenuBtn); // Pause button handler pauseBtn.down = function (x, y, obj) { if (soundOn) LK.getSound('Click').play(); pauseBtn.visible = false; pauseMenuContainer.visible = true; lockInput = true; game.lockInput = true; // Hide cards and hearts visually, but keep state for (var i = 0; i < cards.length; i++) { cards[i].visible = false; } for (var i = 0; i < heartNodes.length; i++) { heartNodes[i].visible = false; } levelText.visible = false; livesText.visible = false; messageText.visible = false; }; // Resume button handler resumeBtn.down = function (x, y, obj) { if (soundOn) LK.getSound('Click').play(); pauseBtn.visible = true; pauseMenuContainer.visible = false; lockInput = false; game.lockInput = false; for (var i = 0; i < cards.length; i++) { cards[i].visible = true; } for (var i = 0; i < heartNodes.length; i++) { heartNodes[i].visible = true; } levelText.visible = true; livesText.visible = true; messageText.visible = false; }; // Menu button in pause menu handler pauseMenuBtn.down = function (x, y, obj) { if (soundOn) LK.getSound('Click').play(); pauseMenuContainer.visible = false; showMenu(); pauseBtn.visible = false; }; // Show menu at start showMenu(); // Layout parameters var boardMargin = 80; var cardSpacingX = 40; var cardSpacingY = 40; // Helper: shuffle array function shuffle(array) { for (var i = array.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var t = array[i]; array[i] = array[j]; array[j] = t; } return array; } // Helper: get grid size for level function getGridForLevel(lvl) { // Level 1: 2x2 (4 cards, 2 pairs) // Level 2: 2x3 (6 cards, 3 pairs) // Level 3: 2x4 (8 cards, 4 pairs) // Level 4: 3x4 (12 cards, 6 pairs) // Level 5: 4x4 (16 cards, 8 pairs) // Level 6: 4x5 (20 cards, 10 pairs) // Level 7: 5x6 (30 cards, 15 pairs) // Level 8: 6x6 (36 cards, 18 pairs) // Level 9: 6x7 (42 cards, 21 pairs) // Level 10: 7x8 (56 cards, 28 pairs) var grids = [[2, 2], [2, 3], [2, 4], [3, 4], [4, 4], [4, 5], [5, 6], [6, 6], [6, 7], [7, 8]]; return grids[Math.min(lvl - 1, grids.length - 1)]; } // Helper: get lives for level function getLivesForLevel(lvl) { // Start with 3, increase by 1 every 2 levels, max 10 return Math.min(10, 3 + Math.floor((lvl - 1) / 2)); } // Start a new level function startLevel(lvl) { // Clean up for (var i = 0; i < cards.length; i++) { cards[i].destroy(); } cards = []; revealedCards = []; matchedPairs = 0; lockInput = true; game.lockInput = true; // Set level/lives level = lvl; var grid = getGridForLevel(level); var rows = grid[0], cols = grid[1]; totalPairs = Math.floor(rows * cols / 2); maxLives = getLivesForLevel(level); lives = maxLives; // Update GUI levelText.setText('Level ' + level); livesText.setText('Lives: ' + lives); // Remove old hearts for (var i = 0; i < heartNodes.length; i++) { if (heartNodes[i].parent) heartNodes[i].parent.removeChild(heartNodes[i]); heartNodes[i].destroy && heartNodes[i].destroy(); } heartNodes = []; // Draw new hearts for current lives for (var i = 0; i < lives; i++) { var heart = LK.getAsset(heartAssetName, { anchorX: 0, anchorY: 1 }); // Place hearts at the bottom left, leaving a margin from the left and bottom heart.x = heartMargin + i * (heartSize + heartSpacing); heart.y = 2732 - heartMargin; // Add directly to the game (not GUI overlay) so it stays at the bottom left of the play area game.addChild(heart); heartNodes.push(heart); } // Prepare fruit pairs var fruitPool = []; for (var i = 0; i < totalPairs; i++) { var fruit = fruitIds[i % fruitIds.length]; fruitPool.push(fruit, fruit); } shuffle(fruitPool); // Card size var cardW = LK.getAsset('cardBack', {}).width; var cardH = LK.getAsset('cardBack', {}).height; // Board size var boardW = cols * cardW + (cols - 1) * cardSpacingX; var boardH = rows * cardH + (rows - 1) * cardSpacingY; var startX = (2048 - boardW) / 2 + cardW / 2; var startY = (2732 - boardH) / 2 + cardH / 2 + 60; // Create cards var idx = 0; for (var r = 0; r < rows; r++) { for (var c = 0; c < cols; c++) { if (idx >= fruitPool.length) continue; var card = new Card(); card.setFruit(fruitPool[idx]); card.x = startX + c * (cardW + cardSpacingX); card.y = startY + r * (cardH + cardSpacingY); card.scaleX = 1; card.scaleY = 1; game.addChild(card); cards.push(card); idx++; } } // Show all cards for a few seconds, increasing with level var showDuration = 1200 + (level - 1) * 500; // e.g. 1.2s + 0.5s per level for (var i = 0; i < cards.length; i++) { cards[i].front.visible = true; cards[i].back.visible = false; cards[i].state = 'revealed'; cards[i].scaleX = 1; cards[i].scaleY = 1; } messageText.setText('Level ' + level); messageText.visible = true; lockInput = true; game.lockInput = true; // After showDuration, hide all cards and allow input LK.setTimeout(function () { for (var i = 0; i < cards.length; i++) { cards[i].front.visible = false; cards[i].back.visible = true; cards[i].state = 'hidden'; cards[i].scaleX = 1; cards[i].scaleY = 1; } messageText.visible = false; lockInput = false; game.lockInput = false; }, showDuration); } // Card tap handler game.onCardTapped = function (card) { if (lockInput || card.state !== 'hidden') return; card.reveal(); revealedCards.push(card); if (revealedCards.length === 2) { lockInput = true; game.lockInput = true; var c1 = revealedCards[0], c2 = revealedCards[1]; if (c1.fruitId === c2.fruitId) { // Match! LK.setTimeout(function () { c1.match(); c2.match(); matchedPairs++; revealedCards = []; lockInput = false; game.lockInput = false; // Check win if (matchedPairs === totalPairs) { if (level === maxLevel) { // Game completed! messageText.setText('You Win!'); messageText.visible = true; LK.setTimeout(function () { messageText.visible = false; LK.showYouWin(); }, 1200); } else { // Next level messageText.setText('Level Complete!'); messageText.visible = true; LK.setTimeout(function () { messageText.visible = false; startLevel(level + 1); }, 1200); } } }, 350); } else { // Not a match LK.setTimeout(function () { c1.hide(); c2.hide(); revealedCards = []; lives--; livesText.setText('Lives: ' + lives); // Update hearts: hide one for each lost life for (var i = 0; i < heartNodes.length; i++) { heartNodes[i].visible = i < lives; } lockInput = false; game.lockInput = false; if (lives <= 0) { // Game over messageText.setText('Game Over'); messageText.visible = true; LK.setTimeout(function () { messageText.visible = false; LK.showGameOver(); }, 1200); } }, 650); } } }; // Prevent interaction when locked game.down = function (x, y, obj) { // No-op: all input handled by Card.down }; game.move = function (x, y, obj) {}; game.up = function (x, y, obj) {}; // Start first level only after Play is clicked // (Do not start here; handled by playBtn.down) // No need for game.update, all logic is event-driven; // --- MUSIC LOOP LOGIC --- var musicTracks = ['BGMusic1', 'BGMusic2']; var currentMusicIndex = 0; var musicLoopTimeout = null; // Play the next music track in the sequence, looping back to start function playNextMusic() { if (!musicOn) return; var track = musicTracks[currentMusicIndex]; // Stop any currently playing music LK.stopMusic && LK.stopMusic(); // Play the current track, not looping LK.playMusic(track, { loop: false }); // Get duration in ms (LK.init.music uses start/end as 0-1, so we can't get duration directly, so hardcode fallback) // If you have access to duration, use it. Otherwise, use a safe default (e.g. 60000ms) var durations = { 'BGMusic1': 60000, 'BGMusic2': 60000 }; var duration = durations[track] || 60000; // Schedule next track musicLoopTimeout = LK.setTimeout(function () { currentMusicIndex = (currentMusicIndex + 1) % musicTracks.length; playNextMusic(); }, duration - 100); // Start next track just before current ends } // Stop the music loop and any scheduled next track function stopMusicLoop() { if (musicLoopTimeout) { LK.clearTimeout(musicLoopTimeout); musicLoopTimeout = null; } LK.stopMusic && LK.stopMusic(); } // When music is toggled, start/stop music loop accordingly musicBtn.down = function (x, y, obj) { if (soundOn) LK.getSound('Click').play(); musicOn = !musicOn; musicBtn.setText('Music: ' + (musicOn ? 'On' : 'Off')); LK.setMusicEnabled && LK.setMusicEnabled(musicOn); if (musicOn) { playNextMusic(); } else { stopMusicLoop(); } }; // When menu is shown, stop music loop
===================================================================
--- original.js
+++ change.js
watermelon. In-Game asset. 2d. High contrast. No shadows
strawberry. In-Game asset. 2d. High contrast. No shadows
banana. In-Game asset. 2d. High contrast. No shadows
lemon. In-Game asset. 2d. High contrast. No shadows
Orange. In-Game asset. 2d. High contrast. No shadows
grape. In-Game asset. 2d. High contrast. No shadows
peach. In-Game asset. 2d. High contrast. No shadows
Cherry. In-Game asset. 2d. High contrast. No shadows
Heart. In-Game asset. 2d. High contrast. No shadows
avocado. In-Game asset. 2d. High contrast. No shadows
Coconut. In-Game asset. 2d. High contrast. No shadows
Pineapple. In-Game asset. 2d. High contrast. No shadows
Kiwi. In-Game asset. 2d. High contrast. No shadows
Apple. In-Game asset. 2d. High contrast. No shadows
Pear. In-Game asset. 2d. High contrast. No shadows
Daisy. In-Game asset. 2d. High contrast. No shadows
Bottle a water. In-Game asset. 2d. High contrast. No shadows
Rock (Gray). In-Game asset. 2d. High contrast. No shadows
Let it be a pink card, the corners are dark pink, getting lighter towards the middle. In-Game asset. 2d. High contrast. No shadows