| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Sea Creatures Memory Match</title> |
| <style> |
| * { |
| margin: 0; |
| padding: 0; |
| box-sizing: border-box; |
| } |
| |
| body { |
| font-family: 'Arial', sans-serif; |
| background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%); |
| min-height: 100vh; |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| justify-content: center; |
| color: white; |
| padding: 20px; |
| } |
| |
| .game-header { |
| text-align: center; |
| margin-bottom: 30px; |
| } |
| |
| .game-title { |
| font-size: 2.5rem; |
| margin-bottom: 10px; |
| text-shadow: 2px 2px 4px rgba(0,0,0,0.3); |
| background: linear-gradient(45deg, #00d4ff, #ffffff); |
| -webkit-background-clip: text; |
| -webkit-text-fill-color: transparent; |
| background-clip: text; |
| } |
| |
| .game-stats { |
| display: flex; |
| gap: 30px; |
| justify-content: center; |
| margin-bottom: 20px; |
| font-size: 1.2rem; |
| } |
| |
| .stat-item { |
| background: rgba(255,255,255,0.1); |
| padding: 10px 20px; |
| border-radius: 25px; |
| backdrop-filter: blur(10px); |
| border: 1px solid rgba(255,255,255,0.2); |
| } |
| |
| .game-board { |
| display: grid; |
| grid-template-columns: repeat(4, 1fr); |
| gap: 15px; |
| max-width: 600px; |
| margin: 0 auto; |
| } |
| |
| .card { |
| width: 120px; |
| height: 120px; |
| background: linear-gradient(145deg, #3498db, #2980b9); |
| border-radius: 15px; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| transform-style: preserve-3d; |
| position: relative; |
| box-shadow: 0 8px 20px rgba(0,0,0,0.2); |
| border: 2px solid rgba(255,255,255,0.1); |
| } |
| |
| .card:hover { |
| transform: translateY(-5px) scale(1.02); |
| box-shadow: 0 12px 25px rgba(0,0,0,0.3); |
| } |
| |
| .card.flipped { |
| background: linear-gradient(145deg, #ffffff, #f0f0f0); |
| color: #2c3e50; |
| transform: rotateY(180deg); |
| } |
| |
| .card.matched { |
| background: linear-gradient(145deg, #2ecc71, #27ae60); |
| color: white; |
| animation: matchPulse 0.6s ease; |
| } |
| |
| .card-content { |
| font-size: 3rem; |
| transition: opacity 0.3s ease; |
| } |
| |
| .card:not(.flipped) .card-content { |
| opacity: 0; |
| } |
| |
| .card.flipped .card-content, |
| .card.matched .card-content { |
| opacity: 1; |
| } |
| |
| .card-back { |
| position: absolute; |
| inset: 0; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| font-size: 2rem; |
| color: rgba(255,255,255,0.8); |
| transition: opacity 0.3s ease; |
| } |
| |
| .card.flipped .card-back, |
| .card.matched .card-back { |
| opacity: 0; |
| } |
| |
| @keyframes matchPulse { |
| 0%, 100% { transform: scale(1); } |
| 50% { transform: scale(1.1); } |
| } |
| |
| .controls { |
| margin-top: 30px; |
| text-align: center; |
| } |
| |
| .btn { |
| background: linear-gradient(145deg, #e74c3c, #c0392b); |
| color: white; |
| border: none; |
| padding: 12px 30px; |
| border-radius: 25px; |
| font-size: 1.1rem; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| box-shadow: 0 4px 15px rgba(231, 76, 60, 0.3); |
| } |
| |
| .btn:hover { |
| transform: translateY(-2px); |
| box-shadow: 0 6px 20px rgba(231, 76, 60, 0.4); |
| } |
| |
| .victory-message, .level-complete-message { |
| position: fixed; |
| top: 50%; |
| left: 50%; |
| transform: translate(-50%, -50%); |
| background: linear-gradient(145deg, #2ecc71, #27ae60); |
| color: white; |
| padding: 30px; |
| border-radius: 20px; |
| text-align: center; |
| font-size: 1.5rem; |
| box-shadow: 0 20px 40px rgba(0,0,0,0.3); |
| opacity: 0; |
| visibility: hidden; |
| transition: all 0.5s ease; |
| z-index: 1000; |
| } |
| |
| .level-complete-message { |
| background: linear-gradient(145deg, #3498db, #2980b9); |
| } |
| |
| .victory-message.show, .level-complete-message.show { |
| opacity: 1; |
| visibility: visible; |
| animation: victoryBounce 0.6s ease; |
| } |
| |
| .next-level-btn { |
| background: linear-gradient(145deg, #f39c12, #e67e22); |
| color: white; |
| border: none; |
| padding: 12px 30px; |
| border-radius: 25px; |
| font-size: 1.1rem; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| margin-top: 15px; |
| } |
| |
| .next-level-btn:hover { |
| transform: translateY(-2px); |
| box-shadow: 0 6px 20px rgba(243, 156, 18, 0.4); |
| } |
| |
| .how-to-play { |
| background: rgba(255,255,255,0.1); |
| backdrop-filter: blur(15px); |
| border: 1px solid rgba(255,255,255,0.2); |
| border-radius: 20px; |
| padding: 25px; |
| margin: 20px auto; |
| max-width: 600px; |
| text-align: left; |
| transition: all 0.5s ease; |
| } |
| |
| .how-to-play.hidden { |
| opacity: 0; |
| visibility: hidden; |
| transform: translateY(-20px); |
| } |
| |
| .how-to-play h3 { |
| text-align: center; |
| margin-bottom: 20px; |
| font-size: 1.5rem; |
| color: #00d4ff; |
| } |
| |
| .how-to-play ul { |
| list-style: none; |
| padding: 0; |
| } |
| |
| .how-to-play li { |
| margin: 12px 0; |
| padding: 8px 0; |
| font-size: 1.1rem; |
| line-height: 1.4; |
| } |
| |
| .close-guide { |
| background: linear-gradient(145deg, #00d4ff, #0099cc); |
| color: white; |
| border: none; |
| padding: 10px 25px; |
| border-radius: 20px; |
| font-size: 1rem; |
| cursor: pointer; |
| display: block; |
| margin: 20px auto 0; |
| transition: all 0.3s ease; |
| } |
| |
| .close-guide:hover { |
| transform: translateY(-2px); |
| box-shadow: 0 6px 20px rgba(0, 153, 204, 0.4); |
| } |
| |
| .sound-controls { |
| margin: 20px 0; |
| } |
| |
| .sound-panel { |
| background: rgba(255,255,255,0.1); |
| backdrop-filter: blur(10px); |
| border: 1px solid rgba(255,255,255,0.2); |
| border-radius: 15px; |
| padding: 20px; |
| display: flex; |
| gap: 20px; |
| align-items: center; |
| justify-content: center; |
| flex-wrap: wrap; |
| } |
| |
| .sound-item { |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| gap: 8px; |
| min-width: 120px; |
| } |
| |
| .sound-item label { |
| font-size: 0.9rem; |
| font-weight: bold; |
| text-align: center; |
| } |
| |
| .sound-toggle { |
| background: linear-gradient(145deg, #2ecc71, #27ae60); |
| color: white; |
| border: none; |
| padding: 6px 16px; |
| border-radius: 15px; |
| font-size: 0.8rem; |
| font-weight: bold; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| min-width: 50px; |
| } |
| |
| .sound-toggle.off { |
| background: linear-gradient(145deg, #e74c3c, #c0392b); |
| } |
| |
| .sound-toggle:hover { |
| transform: translateY(-1px); |
| } |
| |
| .sound-item input[type="range"] { |
| width: 80px; |
| height: 6px; |
| border-radius: 3px; |
| background: rgba(255,255,255,0.3); |
| outline: none; |
| cursor: pointer; |
| } |
| |
| .sound-item input[type="range"]::-webkit-slider-thumb { |
| appearance: none; |
| width: 16px; |
| height: 16px; |
| border-radius: 50%; |
| background: #00d4ff; |
| cursor: pointer; |
| box-shadow: 0 2px 6px rgba(0,0,0,0.3); |
| } |
| |
| .sound-item select { |
| background: rgba(255,255,255,0.1); |
| color: white; |
| border: 1px solid rgba(255,255,255,0.3); |
| border-radius: 8px; |
| padding: 6px 12px; |
| font-size: 0.9rem; |
| cursor: pointer; |
| } |
| |
| .sound-item select option { |
| background: #2980b9; |
| color: white; |
| } |
| |
| .guide-btn { |
| background: linear-gradient(145deg, #9b59b6, #8e44ad); |
| margin-left: 15px; |
| } |
| |
| .guide-btn:hover { |
| box-shadow: 0 6px 20px rgba(155, 89, 182, 0.4); |
| } |
| |
| @keyframes victoryBounce { |
| 0%, 100% { transform: translate(-50%, -50%) scale(1); } |
| 50% { transform: translate(-50%, -50%) scale(1.05); } |
| } |
| |
| @media (max-width: 768px) { |
| .game-board { |
| grid-template-columns: repeat(3, 1fr); |
| gap: 10px; |
| } |
| |
| .card { |
| width: 90px; |
| height: 90px; |
| } |
| |
| .card-content { |
| font-size: 2rem; |
| } |
| |
| .game-title { |
| font-size: 2rem; |
| } |
| |
| .game-stats { |
| flex-direction: column; |
| gap: 10px; |
| } |
| |
| .sound-panel { |
| flex-direction: column; |
| gap: 15px; |
| } |
| |
| .how-to-play { |
| margin: 10px; |
| padding: 20px; |
| } |
| |
| .how-to-play li { |
| font-size: 1rem; |
| } |
| |
| .controls { |
| flex-direction: column; |
| gap: 10px; |
| } |
| |
| .guide-btn { |
| margin-left: 0; |
| } |
| } |
| </style> |
| </head> |
| <body> |
| <div class="game-header"> |
| <h1 class="game-title">๐ Sea Creatures Memory Match ๐</h1> |
| |
| |
| <div class="how-to-play" id="howToPlay"> |
| <h3>๐ฏ How to Play</h3> |
| <ul> |
| <li>๐ฑ๏ธ Click any card to flip it and reveal a sea creature</li> |
| <li>๐ Click a second card to find its matching pair</li> |
| <li>โ
If they match, they stay revealed with a green glow!</li> |
| <li>โ If they don't match, they flip back - remember their positions!</li> |
| <li>๐ Find all 8 pairs to win the game</li> |
| <li>โก Try to complete it in the fewest moves and fastest time!</li> |
| </ul> |
| <button class="close-guide" onclick="toggleGuide()">Got it! ๐</button> |
| </div> |
| |
| <div class="game-stats"> |
| <div class="stat-item"> |
| <span>Level: </span><span id="level">1</span> |
| </div> |
| <div class="stat-item"> |
| <span>Moves: </span><span id="moves">0</span> |
| </div> |
| <div class="stat-item"> |
| <span>Matches: </span><span id="matches">0</span> |
| </div> |
| <div class="stat-item"> |
| <span>Time: </span><span id="timer">00:00</span> |
| </div> |
| </div> |
| |
| |
| <div class="sound-controls"> |
| <div class="sound-panel"> |
| <div class="sound-item"> |
| <label>๐ต Background Music</label> |
| <button class="sound-toggle" id="musicToggle" onclick="toggleMusic()">ON</button> |
| <input type="range" id="musicVolume" min="0" max="100" value="30" onchange="setMusicVolume(this.value)"> |
| </div> |
| <div class="sound-item"> |
| <label>๐ Sound Effects</label> |
| <button class="sound-toggle" id="sfxToggle" onclick="toggleSFX()">ON</button> |
| <input type="range" id="sfxVolume" min="0" max="100" value="50" onchange="setSFXVolume(this.value)"> |
| </div> |
| <div class="sound-item"> |
| <label>โก Game Speed</label> |
| <select id="gameSpeed" onchange="setGameSpeed(this.value)"> |
| <option value="fast">Fast</option> |
| <option value="normal" selected>Normal</option> |
| <option value="slow">Slow</option> |
| </select> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="game-board" id="gameBoard"></div> |
|
|
| <div class="controls"> |
| <button class="btn" onclick="resetGame()">๐ New Game</button> |
| <button class="btn guide-btn" onclick="toggleGuide()">โ How to Play</button> |
| </div> |
|
|
| <div class="victory-message" id="victoryMessage"> |
| <h2>๐ Congratulations! ๐</h2> |
| <p>You found all the sea creature pairs!</p> |
| <p id="finalStats"></p> |
| </div> |
|
|
| <div class="level-complete-message" id="levelCompleteMessage"> |
| <h2>๐ Level Complete! ๐</h2> |
| <p>Amazing! You've completed this level!</p> |
| <p id="levelStats"></p> |
| <button class="btn next-level-btn" onclick="nextLevel()">๐ Next Level</button> |
| </div> |
|
|
| <script> |
| const seaCreatures = [ |
| '๐ ', '๐', '๐ก', '๐ฆ', |
| '๐', '๐ฆ', '๐', '๐ฆ', |
| '๐', '๐ณ', '๐ฆ', '๐ข', |
| '๐ฌ', '๐ฆญ', '๐ง', 'โญ' |
| ]; |
| |
| let gameBoard = []; |
| let flippedCards = []; |
| let matchedPairs = 0; |
| let moves = 0; |
| let startTime = null; |
| let timerInterval = null; |
| let gameActive = false; |
| let gameSpeed = 'normal'; |
| let musicEnabled = true; |
| let sfxEnabled = true; |
| let musicVolume = 0.3; |
| let sfxVolume = 0.5; |
| let currentLevel = 1; |
| let totalMatches = 0; |
| |
| |
| let audioContext; |
| let backgroundMusic; |
| let matchSound; |
| let flipSound; |
| |
| |
| function initAudio() { |
| try { |
| audioContext = new (window.AudioContext || window.webkitAudioContext)(); |
| createBackgroundMusic(); |
| createSoundEffects(); |
| } catch (e) { |
| console.log('Audio not supported'); |
| } |
| } |
| |
| function createBackgroundMusic() { |
| if (!audioContext) return; |
| |
| |
| if (backgroundMusic && backgroundMusic.oscillators) { |
| backgroundMusic.oscillators.forEach(osc => { |
| try { osc.stop(); } catch (e) {} |
| }); |
| } |
| |
| |
| const masterGain = audioContext.createGain(); |
| masterGain.gain.setValueAtTime(musicVolume * 0.15, audioContext.currentTime); |
| masterGain.connect(audioContext.destination); |
| |
| const oscillators = []; |
| |
| |
| const bass = audioContext.createOscillator(); |
| const bassGain = audioContext.createGain(); |
| bass.type = 'sine'; |
| bass.frequency.setValueAtTime(55, audioContext.currentTime); |
| bassGain.gain.setValueAtTime(0.3, audioContext.currentTime); |
| bass.connect(bassGain); |
| bassGain.connect(masterGain); |
| oscillators.push(bass); |
| |
| |
| const harmonics = [110, 165, 220, 330]; |
| harmonics.forEach((freq, i) => { |
| const osc = audioContext.createOscillator(); |
| const gain = audioContext.createGain(); |
| osc.type = 'triangle'; |
| osc.frequency.setValueAtTime(freq, audioContext.currentTime); |
| gain.gain.setValueAtTime(0.1 / (i + 1), audioContext.currentTime); |
| osc.connect(gain); |
| gain.connect(masterGain); |
| oscillators.push(osc); |
| }); |
| |
| |
| const waveLFO = audioContext.createOscillator(); |
| const waveGain = audioContext.createGain(); |
| waveLFO.type = 'sine'; |
| waveLFO.frequency.setValueAtTime(0.3, audioContext.currentTime); |
| waveGain.gain.setValueAtTime(8, audioContext.currentTime); |
| waveLFO.connect(waveGain); |
| waveGain.connect(bass.frequency); |
| oscillators.push(waveLFO); |
| |
| |
| const bubbles = audioContext.createOscillator(); |
| const bubblesGain = audioContext.createGain(); |
| const bubblesLFO = audioContext.createOscillator(); |
| const bubblesLFOGain = audioContext.createGain(); |
| |
| bubbles.type = 'sine'; |
| bubbles.frequency.setValueAtTime(1760, audioContext.currentTime); |
| bubblesGain.gain.setValueAtTime(0.02, audioContext.currentTime); |
| |
| bubblesLFO.type = 'sine'; |
| bubblesLFO.frequency.setValueAtTime(0.7, audioContext.currentTime); |
| bubblesLFOGain.gain.setValueAtTime(200, audioContext.currentTime); |
| |
| bubblesLFO.connect(bubblesLFOGain); |
| bubblesLFOGain.connect(bubbles.frequency); |
| bubbles.connect(bubblesGain); |
| bubblesGain.connect(masterGain); |
| |
| oscillators.push(bubbles, bubblesLFO); |
| |
| |
| const whale = audioContext.createOscillator(); |
| const whaleGain = audioContext.createGain(); |
| const whaleLFO = audioContext.createOscillator(); |
| const whaleLFOGain = audioContext.createGain(); |
| |
| whale.type = 'sawtooth'; |
| whale.frequency.setValueAtTime(80, audioContext.currentTime); |
| whaleGain.gain.setValueAtTime(0.05, audioContext.currentTime); |
| |
| whaleLFO.type = 'sine'; |
| whaleLFO.frequency.setValueAtTime(0.1, audioContext.currentTime); |
| whaleLFOGain.gain.setValueAtTime(20, audioContext.currentTime); |
| |
| whaleLFO.connect(whaleLFOGain); |
| whaleLFOGain.connect(whale.frequency); |
| whale.connect(whaleGain); |
| whaleGain.connect(masterGain); |
| |
| oscillators.push(whale, whaleLFO); |
| |
| backgroundMusic = { oscillators, masterGain }; |
| |
| if (musicEnabled) { |
| try { |
| oscillators.forEach(osc => osc.start()); |
| } catch (e) { |
| console.log('Could not start background music'); |
| } |
| } |
| } |
| |
| function createSoundEffects() { |
| |
| matchSound = () => { |
| if (!audioContext || !sfxEnabled) return; |
| |
| const oscillator = audioContext.createOscillator(); |
| const gainNode = audioContext.createGain(); |
| |
| oscillator.connect(gainNode); |
| gainNode.connect(audioContext.destination); |
| |
| oscillator.type = 'triangle'; |
| oscillator.frequency.setValueAtTime(523.25, audioContext.currentTime); |
| oscillator.frequency.setValueAtTime(659.25, audioContext.currentTime + 0.1); |
| oscillator.frequency.setValueAtTime(783.99, audioContext.currentTime + 0.2); |
| |
| gainNode.gain.setValueAtTime(sfxVolume * 0.3, audioContext.currentTime); |
| gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.5); |
| |
| oscillator.start(audioContext.currentTime); |
| oscillator.stop(audioContext.currentTime + 0.5); |
| }; |
| |
| |
| flipSound = () => { |
| if (!audioContext || !sfxEnabled) return; |
| |
| const oscillator = audioContext.createOscillator(); |
| const gainNode = audioContext.createGain(); |
| |
| oscillator.connect(gainNode); |
| gainNode.connect(audioContext.destination); |
| |
| oscillator.type = 'square'; |
| oscillator.frequency.setValueAtTime(800, audioContext.currentTime); |
| |
| gainNode.gain.setValueAtTime(sfxVolume * 0.1, audioContext.currentTime); |
| gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1); |
| |
| oscillator.start(audioContext.currentTime); |
| oscillator.stop(audioContext.currentTime + 0.1); |
| }; |
| } |
| |
| function getSpeedDelay() { |
| const speeds = { |
| fast: { match: 300, flip: 600 }, |
| normal: { match: 500, flip: 1000 }, |
| slow: { match: 800, flip: 1500 } |
| }; |
| return speeds[gameSpeed]; |
| } |
| |
| function initGame() { |
| |
| gameBoard = []; |
| flippedCards = []; |
| matchedPairs = 0; |
| moves = 0; |
| startTime = null; |
| gameActive = true; |
| |
| if (timerInterval) { |
| clearInterval(timerInterval); |
| } |
| |
| |
| const creatures = seaCreatures.slice(0, 8); |
| const pairs = [...creatures, ...creatures]; |
| gameBoard = shuffle(pairs); |
| |
| |
| updateStats(); |
| createBoard(); |
| document.getElementById('victoryMessage').classList.remove('show'); |
| document.getElementById('levelCompleteMessage').classList.remove('show'); |
| } |
| |
| function shuffle(array) { |
| const shuffled = [...array]; |
| for (let i = shuffled.length - 1; i > 0; i--) { |
| const j = Math.floor(Math.random() * (i + 1)); |
| [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; |
| } |
| return shuffled; |
| } |
| |
| function createBoard() { |
| const board = document.getElementById('gameBoard'); |
| board.innerHTML = ''; |
| |
| gameBoard.forEach((creature, index) => { |
| const card = document.createElement('div'); |
| card.className = 'card'; |
| card.dataset.index = index; |
| card.innerHTML = ` |
| <div class="card-back">๐</div> |
| <div class="card-content">${creature}</div> |
| `; |
| card.addEventListener('click', () => flipCard(index)); |
| board.appendChild(card); |
| }); |
| } |
| |
| function flipCard(index) { |
| if (!gameActive) return; |
| |
| const card = document.querySelector(`[data-index="${index}"]`); |
| |
| |
| if (card.classList.contains('flipped') || card.classList.contains('matched')) { |
| return; |
| } |
| |
| |
| if (!startTime) { |
| startTimer(); |
| |
| if (!audioContext) { |
| initAudio(); |
| } |
| } |
| |
| |
| if (flipSound) flipSound(); |
| |
| |
| card.classList.add('flipped'); |
| flippedCards.push(index); |
| |
| |
| if (flippedCards.length === 2) { |
| moves++; |
| updateStats(); |
| checkForMatch(); |
| } |
| } |
| |
| function checkForMatch() { |
| const [first, second] = flippedCards; |
| const firstCard = document.querySelector(`[data-index="${first}"]`); |
| const secondCard = document.querySelector(`[data-index="${second}"]`); |
| const delays = getSpeedDelay(); |
| |
| if (gameBoard[first] === gameBoard[second]) { |
| |
| setTimeout(() => { |
| |
| if (matchSound) matchSound(); |
| |
| firstCard.classList.add('matched'); |
| secondCard.classList.add('matched'); |
| firstCard.classList.remove('flipped'); |
| secondCard.classList.remove('flipped'); |
| matchedPairs++; |
| totalMatches++; |
| updateStats(); |
| flippedCards = []; |
| |
| |
| if (matchedPairs === 8) { |
| if (totalMatches >= 14) { |
| gameWon(); |
| } else { |
| levelComplete(); |
| } |
| } |
| }, delays.match); |
| } else { |
| |
| setTimeout(() => { |
| firstCard.classList.remove('flipped'); |
| secondCard.classList.remove('flipped'); |
| flippedCards = []; |
| }, delays.flip); |
| } |
| } |
| |
| function startTimer() { |
| startTime = Date.now(); |
| timerInterval = setInterval(updateTimer, 1000); |
| } |
| |
| function updateTimer() { |
| if (!startTime) return; |
| |
| const elapsed = Math.floor((Date.now() - startTime) / 1000); |
| const minutes = Math.floor(elapsed / 60).toString().padStart(2, '0'); |
| const seconds = (elapsed % 60).toString().padStart(2, '0'); |
| document.getElementById('timer').textContent = `${minutes}:${seconds}`; |
| } |
| |
| function updateStats() { |
| document.getElementById('level').textContent = currentLevel; |
| document.getElementById('moves').textContent = moves; |
| document.getElementById('matches').textContent = `${totalMatches}`; |
| } |
| |
| function levelComplete() { |
| gameActive = false; |
| clearInterval(timerInterval); |
| |
| const finalTime = document.getElementById('timer').textContent; |
| document.getElementById('levelStats').innerHTML = |
| `Level ${currentLevel} Complete!<br>Time: ${finalTime}<br>Moves: ${moves}<br>Total Matches: ${totalMatches}`; |
| |
| setTimeout(() => { |
| document.getElementById('levelCompleteMessage').classList.add('show'); |
| }, 500); |
| } |
| |
| function nextLevel() { |
| currentLevel++; |
| document.getElementById('levelCompleteMessage').classList.remove('show'); |
| initGame(); |
| } |
| |
| function gameWon() { |
| gameActive = false; |
| clearInterval(timerInterval); |
| |
| const finalTime = document.getElementById('timer').textContent; |
| document.getElementById('finalStats').innerHTML = |
| `๐ Game Complete! ๐<br>Total Levels: ${currentLevel}<br>Final Time: ${finalTime}<br>Total Moves: ${moves}<br>Total Matches: ${totalMatches}`; |
| |
| setTimeout(() => { |
| document.getElementById('victoryMessage').classList.add('show'); |
| }, 500); |
| } |
| |
| function resetGame() { |
| currentLevel = 1; |
| totalMatches = 0; |
| initGame(); |
| } |
| |
| |
| function toggleGuide() { |
| const guide = document.getElementById('howToPlay'); |
| guide.classList.toggle('hidden'); |
| } |
| |
| function toggleMusic() { |
| musicEnabled = !musicEnabled; |
| const toggle = document.getElementById('musicToggle'); |
| toggle.textContent = musicEnabled ? 'ON' : 'OFF'; |
| toggle.classList.toggle('off', !musicEnabled); |
| |
| if (backgroundMusic && musicEnabled) { |
| backgroundMusic.masterGain.gain.setValueAtTime( |
| musicEnabled ? musicVolume * 0.15 : 0, |
| audioContext.currentTime |
| ); |
| } |
| } |
| |
| function toggleSFX() { |
| sfxEnabled = !sfxEnabled; |
| const toggle = document.getElementById('sfxToggle'); |
| toggle.textContent = sfxEnabled ? 'ON' : 'OFF'; |
| toggle.classList.toggle('off', !sfxEnabled); |
| } |
| |
| function setMusicVolume(value) { |
| musicVolume = value / 100; |
| if (backgroundMusic && musicEnabled) { |
| backgroundMusic.masterGain.gain.setValueAtTime( |
| musicVolume * 0.15, |
| audioContext.currentTime |
| ); |
| } |
| } |
| |
| function setSFXVolume(value) { |
| sfxVolume = value / 100; |
| } |
| |
| function setGameSpeed(speed) { |
| gameSpeed = speed; |
| } |
| |
| |
| document.addEventListener('DOMContentLoaded', () => { |
| initGame(); |
| |
| document.getElementById('howToPlay').classList.add('hidden'); |
| }); |
| </script> |
| </body> |
| </html> |