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: 0x000000 }); /**** * 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, 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 with ButtonBG var playBtnContainer = new Container(); var playBtn = new Text2('Play', { size: 140, fill: "#fff", font: "Impact" }); playBtn.anchor.set(0.5, 0.5); playBtn.y = 0; var playBtnBG = LK.getAsset('ButtonBG', { anchorX: 0.5, anchorY: 0.5 }); playBtnBG.width = playBtn.width + 80; playBtnBG.height = playBtn.height + 60; playBtnBG.x = 0; playBtnBG.y = 0; playBtnContainer.addChild(playBtnBG); playBtnContainer.addChild(playBtn); playBtnContainer.y = -120; menuContainer.addChild(playBtnContainer); // Settings button with ButtonBG var settingsBtnContainer = new Container(); var settingsBtn = new Text2('Settings', { size: 100, fill: "#fff", font: "Impact" }); settingsBtn.anchor.set(0.5, 0.5); settingsBtn.y = 0; var settingsBtnBG = LK.getAsset('ButtonBG', { anchorX: 0.5, anchorY: 0.5 }); settingsBtnBG.width = settingsBtn.width + 80; settingsBtnBG.height = settingsBtn.height + 60; settingsBtnBG.x = 0; settingsBtnBG.y = 0; settingsBtnContainer.addChild(settingsBtnBG); settingsBtnContainer.addChild(settingsBtn); settingsBtnContainer.y = 80; menuContainer.addChild(settingsBtnContainer); // Settings panel (hidden by default) var settingsPanel = new Container(); settingsPanel.visible = false; settingsPanel.y = 250; menuContainer.addChild(settingsPanel); // Sound toggle button with ButtonBG var soundOn = true; var soundBtnContainer = new Container(); var soundBtn = new Text2('Sound: On', { size: 80, fill: "#fff", font: "Impact" }); soundBtn.anchor.set(0.5, 0.5); soundBtn.y = 0; var soundBtnBG = LK.getAsset('ButtonBG', { anchorX: 0.5, anchorY: 0.5 }); soundBtnBG.width = soundBtn.width + 80; soundBtnBG.height = soundBtn.height + 60; soundBtnBG.x = 0; soundBtnBG.y = 0; soundBtnContainer.addChild(soundBtnBG); soundBtnContainer.addChild(soundBtn); soundBtnContainer.y = 0; settingsPanel.addChild(soundBtnContainer); // Music toggle button with ButtonBG var musicOn = true; var musicBtnContainer = new Container(); var musicBtn = new Text2('Music: On', { size: 80, fill: "#fff", font: "Impact" }); musicBtn.anchor.set(0.5, 0.5); musicBtn.y = 0; var musicBtnBG = LK.getAsset('ButtonBG', { anchorX: 0.5, anchorY: 0.5 }); musicBtnBG.width = musicBtn.width + 80; musicBtnBG.height = musicBtn.height + 60; musicBtnBG.x = 0; musicBtnBG.y = 0; musicBtnContainer.addChild(musicBtnBG); musicBtnContainer.addChild(musicBtn); musicBtnContainer.y = 120; settingsPanel.addChild(musicBtnContainer); // Menu logic var menuActive = true; function showMenu() { menuContainer.visible = true; levelText.visible = false; messageText.visible = false; pauseBtnContainer.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; pauseBtnContainer.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 playBtnContainer.down = function (x, y, obj) { if (soundOn) LK.getSound('Click').play(); hideMenu(); // Start/restart game startLevel(1); }; // Settings button handler settingsBtnContainer.down = function (x, y, obj) { if (soundOn) LK.getSound('Click').play(); settingsPanel.visible = !settingsPanel.visible; }; // Sound toggle handler soundBtnContainer.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 musicBtnContainer.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); // We'll position these below the cards after the board is created, so just add to game for now game.addChild(levelText); // 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 --- // Create a container for the pause button and its background var pauseBtnContainer = new Container(); // Add ButtonBG image as background var pauseBtnBG = LK.getAsset('ButtonBG', { anchorX: 0.5, anchorY: 0.5 }); pauseBtnContainer.addChild(pauseBtnBG); // Create the pause button text var pauseBtn = new Text2('Pause', { size: 80, fill: "#fff", font: "Impact" }); pauseBtn.anchor.set(0.5, 0.5); pauseBtnContainer.addChild(pauseBtn); // Place pause button just below the Level text, even further to the right of center pauseBtnContainer.x = 2048 / 2 + 260; // Move 260px to the right pauseBtnContainer.y = levelText.y + levelText.height + 10; // 10px below the Level text LK.gui.addChild(pauseBtnContainer); pauseBtnContainer.visible = false; // Pause menu container var pauseMenuContainer = new Container(); pauseMenuContainer.visible = false; LK.gui.center.addChild(pauseMenuContainer); // Resume button with ButtonBG var resumeBtnContainer = new Container(); var resumeBtn = new Text2('Resume', { size: 120, fill: "#fff", font: "Impact" }); resumeBtn.anchor.set(0.5, 0.5); resumeBtn.y = 0; var resumeBtnBG = LK.getAsset('ButtonBG', { anchorX: 0.5, anchorY: 0.5 }); resumeBtnBG.width = resumeBtn.width + 80; resumeBtnBG.height = resumeBtn.height + 60; resumeBtnBG.x = 0; resumeBtnBG.y = 0; resumeBtnContainer.addChild(resumeBtnBG); resumeBtnContainer.addChild(resumeBtn); resumeBtnContainer.y = -100; pauseMenuContainer.addChild(resumeBtnContainer); // Menu button (in pause menu) with ButtonBG var pauseMenuBtnContainer = new Container(); var pauseMenuBtn = new Text2('Menu', { size: 120, fill: "#fff", font: "Impact" }); pauseMenuBtn.anchor.set(0.5, 0.5); pauseMenuBtn.y = 0; var pauseMenuBtnBG = LK.getAsset('ButtonBG', { anchorX: 0.5, anchorY: 0.5 }); pauseMenuBtnBG.width = pauseMenuBtn.width + 80; pauseMenuBtnBG.height = pauseMenuBtn.height + 60; pauseMenuBtnBG.x = 0; pauseMenuBtnBG.y = 0; pauseMenuBtnContainer.addChild(pauseMenuBtnBG); pauseMenuBtnContainer.addChild(pauseMenuBtn); pauseMenuBtnContainer.y = 100; pauseMenuContainer.addChild(pauseMenuBtnContainer); // Pause button handler pauseBtn.down = function (x, y, obj) { if (soundOn) LK.getSound('Click').play(); pauseBtnContainer.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; messageText.visible = false; }; // Resume button handler resumeBtnContainer.down = function (x, y, obj) { if (soundOn) LK.getSound('Click').play(); pauseBtnContainer.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; messageText.visible = false; }; // Menu button in pause menu handler pauseMenuBtnContainer.down = function (x, y, obj) { if (soundOn) LK.getSound('Click').play(); pauseMenuContainer.visible = false; showMenu(); pauseBtnContainer.visible = false; }; // Show menu at start showMenu(); playNextMusic(); // 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); // 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; // Position levelText and livesText below the cards levelText.x = 2048 / 2; levelText.y = startY + boardH / 2 + cardH / 2 + 40; // 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; } // Move messageText below the cards, centered messageText.x = 2048 / 2; messageText.y = levelText.y + levelText.height + 40; 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--; // 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; // Defensive: check musicTracks is array and currentMusicIndex is valid if (!musicTracks || !Array.isArray(musicTracks) || musicTracks.length === 0) return; if (typeof currentMusicIndex !== "number" || currentMusicIndex < 0 || currentMusicIndex >= musicTracks.length) { currentMusicIndex = 0; } var track = musicTracks[currentMusicIndex]; if (!track) return; // 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 musicBtnContainer.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
@@ -144,9 +144,9 @@
/****
* Initialize Game
****/
var game = new LK.Game({
- backgroundColor: 0x1a1a1a
+ backgroundColor: 0x000000
});
/****
* Game Code
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