/** * Pexeso hra s integráciou do level systému * Obsahuje rečové cvičenia, systém hodnotenia a navigáciu * Autor: Adam Reňak */ // =============================================== // GLOBÁLNE PREMENNÉ PRE PEXESO HRU // =============================================== let currentLevelConfig = null; // Konfigurácia aktuálneho levelu let isCustomLevel = false; // Či je to custom level // Herné premenné let gameCards = []; // Pole všetkých kariet v hre let flippedCards = []; // Aktuálne otočené karty (max 2) let matchedPairs = 0; // Počet nájdených párov let totalPairs = 0; // Celkový počet párov v hre let gameAttempts = 0; // Počet pokusov let gameStartTime = null; // Čas začatku hry let gameTimer = null; // Timer pre hru let currentTime = 0; // Aktuálny čas v sekundách // Hráči let players = []; // Pole hráčov let currentPlayer = 0; // Index aktuálneho hráča // Rečové cvičenie let speechRecognition = null; // Web Speech API let isListening = false; // Či práve počúvame let currentWord = ''; // Aktuálne slovo na vyslovenie let speechAttempts = 0; // Počet pokusov pre rečové cvičenie let maxSpeechAttempts = 3; // Maximálny počet pokusov // Audio elementy let sounds = { cardFlip: null, correct: null, wrong: null, victory: null }; // =============================================== // INICIALIZÁCIA HRY // =============================================== /** * Hlavná inicializačná funkcia * Spúšťa sa pri načítaní stránky */ function initializePexesoGame() { console.log('Inicializujem pexeso hru...'); // Načítaj level konfiguráciu z URL loadLevelFromURL(); // Inicializuj audio initializeAudio(); // Inicializuj rečové rozpoznávanie initializeSpeechRecognition(); // Nastav pozadie sveta setWorldBackground(); // Skry loading screen hideLoadingScreen(); // Spusti hru startGame(); } /** * Načítanie level konfigurácie z URL parametrov */ function loadLevelFromURL() { const urlParams = new URLSearchParams(window.location.search); const worldId = urlParams.get('worldId'); const levelId = urlParams.get('levelId'); const training = urlParams.get('training') === 'true'; console.log('URL parametre:', { worldId, levelId, training }); if (training) { // Pre tréningové levely - zatiaľ základná konfigurácia isCustomLevel = true; currentLevelConfig = { id: 'training_pexeso', worldId: worldId || 'world_r', name: 'Tréningové pexeso', gameType: 'pexeso', words: ['rak', 'ryba', 'ruka', 'ruža'], gameConfig: { pairs: 4, timeLimit: null } }; } else if (levelId && window.getLevelConfig) { // Načítaj konfiguráciu z levels.js currentLevelConfig = window.getLevelConfig(levelId); isCustomLevel = false; } else { // Predvolená konfigurácia console.warn('Žiadna level konfigurácia, používam predvolenú'); currentLevelConfig = { id: 'default_pexeso', worldId: 'world_r', name: 'Základné pexeso', gameType: 'pexeso', words: ['rak', 'ryba', 'ruka', 'ruža'], gameConfig: { pairs: 4, timeLimit: null } }; isCustomLevel = true; } console.log('Načítaná level konfigurácia:', currentLevelConfig); } /** * Nastavenie pozadia sveta */ function setWorldBackground() { const gameCanvas = document.getElementById('gameCanvas'); if (!gameCanvas || !currentLevelConfig) return; const worldId = currentLevelConfig.worldId; // Mapa pozadí pre jednotlivé svety const worldBackgrounds = { 'world_z': '../images/worlds/world_z.jpg', 'world_s': '../images/worlds/world_s.png', 'world_r': '../images/worlds/world_r.png', 'world_l': '../images/worlds/world_l.png', 'world_c': '../images/worlds/world_c.png', 'world_š': '../images/worlds/world_sh.png', 'world_ž': '../images/worlds/world_zh.png', 'world_č': '../images/worlds/world_ch.png', 'world_d': '../images/worlds/world_d.png', 'world_t': '../images/worlds/world_t.png', 'world_n': '../images/worlds/world_n.png', 'world_k': '../images/worlds/world_k.png', 'world_g': '../images/worlds/world_g.png' }; const backgroundImage = worldBackgrounds[worldId] || '../images/pozadie.jpg'; gameCanvas.style.backgroundImage = `url('${backgroundImage}')`; console.log(`Nastavené pozadie pre svet ${worldId}: ${backgroundImage}`); } /** * Inicializácia audio elementov */ function initializeAudio() { sounds.cardFlip = document.getElementById('cardFlipSound') || new Audio('zvuky/effects/kopanie.wav'); sounds.correct = document.getElementById('correctSound') || new Audio('zvuky/effects/spravne.mp3'); sounds.wrong = document.getElementById('wrongSound') || new Audio('zvuky/effects/zle.mp3'); sounds.victory = document.getElementById('victorySound') || new Audio('zvuky/effects/vyhra.mp3'); // Nastav hlasitosť Object.values(sounds).forEach(sound => { if (sound) sound.volume = 0.7; }); } /** * Skrytie loading screen */ function hideLoadingScreen() { setTimeout(() => { const loadingScreen = document.getElementById('loading-screen'); if (loadingScreen) { loadingScreen.style.opacity = '0'; setTimeout(() => { loadingScreen.style.display = 'none'; }, 500); } }, 1500); } // =============================================== // SPUSTENIE HRY // =============================================== /** * Spustenie novej hry */ function startGame() { console.log('Spúšťam novú hru pexesa...'); if (!currentLevelConfig) { console.error('Žiadna level konfigurácia!'); return; } // Reset herných premenných resetGameVariables(); // Inicializuj hráčov initializePlayers(); // Vytvor karty createGameCards(); // Vygeneruj karty na obrazovke generateCardsHTML(); // Spusti časomeru startGameTimer(); console.log('Hra spustená!'); } /** * Reset herných premenných */ function resetGameVariables() { gameCards = []; flippedCards = []; matchedPairs = 0; gameAttempts = 0; currentTime = 0; currentPlayer = 0; // Aktualizuj UI updateAttemptsDisplay(); updateTimeDisplay(); } /** * Inicializácia hráčov */ function initializePlayers() { // Pre teraz jeden hráč, neskôr môžeme pridať multiplayer players = [ { name: 'Hráč', score: 0, color: 'player-1' } ]; // Aktualizuj UI hráčov updatePlayersDisplay(); } /** * Vytvorenie kariet pre hru */ function createGameCards() { const words = currentLevelConfig.words; const pairsCount = currentLevelConfig.gameConfig.pairs || Math.min(words.length, 8); // Vyber slová pre hru const selectedWords = words.slice(0, pairsCount); totalPairs = selectedWords.length; // Vytvor páry kariet gameCards = []; selectedWords.forEach((word, index) => { // Prvá karta páru gameCards.push({ id: `card_${index}_1`, word: word, image: `images/slova/${word}.png`, pairId: index, isFlipped: false, isMatched: false }); // Druhá karta páru gameCards.push({ id: `card_${index}_2`, word: word, image: `images/slova/${word}.png`, pairId: index, isFlipped: false, isMatched: false }); }); // Zamiešaj karty shuffleArray(gameCards); console.log(`Vytvorených ${gameCards.length} kariet (${totalPairs} párov)`); } /** * Zamiešanie poľa */ function shuffleArray(array) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } } /** * Generovanie HTML pre karty */ function generateCardsHTML() { const gameCanvas = document.getElementById('gameCanvas'); if (!gameCanvas) return; // Nastav CSS triedu pre responzívnosť const cardCount = gameCards.length; gameCanvas.className = `cards-${cardCount}`; // Vymaž existujúci obsah gameCanvas.innerHTML = ''; // Vygeneruj karty gameCards.forEach((card, index) => { const cardElement = createCardElement(card, index); gameCanvas.appendChild(cardElement); }); console.log(`Vygenerovaných ${gameCards.length} kariet v HTML`); } /** * Vytvorenie HTML elementu karty */ function createCardElement(card, index) { const cardDiv = document.createElement('div'); cardDiv.className = 'card-container'; cardDiv.dataset.cardId = card.id; cardDiv.dataset.cardIndex = index; // Obrázok (skrytý na začiatku) const img = document.createElement('img'); img.src = card.image; img.alt = card.word; img.style.display = 'none'; // Text const span = document.createElement('span'); span.textContent = 'PEXESO'; cardDiv.appendChild(img); cardDiv.appendChild(span); // Event listener pre kliknutie cardDiv.addEventListener('click', () => handleCardClick(index)); return cardDiv; } // =============================================== // LOGIKA KARIET // =============================================== /** * Spracovanie kliknutia na kartu */ function handleCardClick(cardIndex) { const card = gameCards[cardIndex]; const cardElement = document.querySelector(`[data-card-index="${cardIndex}"]`); // Kontroly - karta už otočená, matchovaná alebo príliš veľa otočených kariet if (card.isFlipped || card.isMatched || flippedCards.length >= 2) { return; } console.log(`Kliknutie na kartu: ${card.word}`); // Otočenie karty flipCard(cardIndex, cardElement); // Pridaj do otočených kariet flippedCards.push({ index: cardIndex, card: card, element: cardElement }); // Ak sú otočené 2 karty, skontroluj pár if (flippedCards.length === 2) { gameAttempts++; updateAttemptsDisplay(); setTimeout(() => { checkForMatch(); }, 1000); } } /** * Otočenie karty */ function flipCard(cardIndex, cardElement) { const card = gameCards[cardIndex]; // Nastav stav karty card.isFlipped = true; // Vizuálne otočenie cardElement.classList.add('flipped'); // Zobraz obrázok a aktualizuj text const img = cardElement.querySelector('img'); const span = cardElement.querySelector('span'); if (img) img.style.display = 'block'; if (span) span.textContent = card.word; // Zahraj zvuk if (sounds.cardFlip) { sounds.cardFlip.play().catch(e => console.log('Audio chyba:', e)); } console.log(`Karta otočená: ${card.word}`); } /** * Kontrola páru */ function checkForMatch() { if (flippedCards.length !== 2) return; const [first, second] = flippedCards; const isMatch = first.card.pairId === second.card.pairId; console.log(`Kontrola páru: ${first.card.word} vs ${second.card.word} = ${isMatch ? 'MATCH' : 'NO MATCH'}`); if (isMatch) { handleSuccessfulMatch(first, second); } else { handleFailedMatch(first, second); } // Vymaž otočené karty flippedCards = []; } /** * Spracovanie úspešného páru */ function handleSuccessfulMatch(first, second) { console.log('Úspešný pár!'); // Označenie kariet ako matchované first.card.isMatched = true; second.card.isMatched = true; first.element.classList.add('matched'); second.element.classList.add('matched'); // Aktualizuj skóre players[currentPlayer].score++; updatePlayersDisplay(); matchedPairs++; // Zahraj úspešný zvuk if (sounds.correct) { sounds.correct.play().catch(e => console.log('Audio chyba:', e)); } // Spusti rečové cvičenie startSpeechExercise(first.card.word); } /** * Spracovanie neúspešného páru */ function handleFailedMatch(first, second) { console.log('Neúspešný pár!'); // Otočenie kariet späť setTimeout(() => { flipCardBack(first.index, first.element); flipCardBack(second.index, second.element); }, 500); // Zahraj neúspešný zvuk if (sounds.wrong) { sounds.wrong.play().catch(e => console.log('Audio chyba:', e)); } } /** * Otočenie karty späť */ function flipCardBack(cardIndex, cardElement) { const card = gameCards[cardIndex]; // Nastav stav karty card.isFlipped = false; // Vizuálne otočenie späť cardElement.classList.remove('flipped'); // Skry obrázok a obnov text const img = cardElement.querySelector('img'); const span = cardElement.querySelector('span'); if (img) img.style.display = 'none'; if (span) span.textContent = 'PEXESO'; console.log(`Karta otočená späť: ${card.word}`); } // =============================================== // REČOVÉ CVIČENIE // =============================================== /** * Spustenie rečového cvičenia */ function startSpeechExercise(word) { console.log(`Spúšťam rečové cvičenie pre slovo: ${word}`); currentWord = word; speechAttempts = 0; // Zobraz modal showSpeechModal(word); } /** * Zobrazenie modalu pre rečové cvičenie */ function showSpeechModal(word) { const modal = document.getElementById('cvicenie'); const wordDisplay = document.getElementById('word-display'); const wordImage = document.getElementById('cvicenie-image'); if (modal) { // Nastav slovo a obrázok if (wordDisplay) wordDisplay.textContent = word.toUpperCase(); if (wordImage) { wordImage.src = `images/slova/${word}.png`; wordImage.alt = word; } modal.style.display = 'block'; modal.classList.add('modal-open'); console.log(`Modal zobrazený pre slovo: ${word}`); } } /** * Inicializácia rečového rozpoznávania */ function initializeSpeechRecognition() { if (!('webkitSpeechRecognition' in window) && !('SpeechRecognition' in window)) { console.warn('Rečové rozpoznávanie nie je podporované v tomto prehliadači'); return; } const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; speechRecognition = new SpeechRecognition(); speechRecognition.lang = 'sk-SK'; speechRecognition.continuous = false; speechRecognition.interimResults = false; speechRecognition.maxAlternatives = 3; speechRecognition.onstart = function() { console.log('Rečové rozpoznávanie spustené'); isListening = true; updateSpeechButton(); }; speechRecognition.onresult = function(event) { console.log('Výsledok rečového rozpoznávania:', event); const result = event.results[0][0].transcript.toLowerCase().trim(); const confidence = event.results[0][0].confidence; console.log(`Rozpoznané: "${result}" (spoľahlivosť: ${confidence})`); processSpeechResult(result, confidence); }; speechRecognition.onerror = function(event) { console.error('Chyba rečového rozpoznávania:', event.error); isListening = false; updateSpeechButton(); showSpeechError(event.error); }; speechRecognition.onend = function() { console.log('Rečové rozpoznávanie ukončené'); isListening = false; updateSpeechButton(); }; // Event listener pre tlačidlo mikrofónu const micButton = document.getElementById('rozpoznanie'); if (micButton) { micButton.addEventListener('click', toggleSpeechRecognition); } } /** * Zapnutie/vypnutie rečového rozpoznávania */ function toggleSpeechRecognition() { if (!speechRecognition) { console.warn('Rečové rozpoznávanie nie je dostupné'); return; } if (isListening) { speechRecognition.stop(); } else { speechAttempts++; speechRecognition.start(); } } /** * Aktualizácia tlačidla mikrofónu */ function updateSpeechButton() { const button = document.getElementById('rozpoznanie'); const buttonContainer = button?.parentElement; const buttonText = button?.querySelector('a'); if (!button || !buttonContainer || !buttonText) return; if (isListening) { buttonContainer.classList.add('recording'); buttonText.textContent = 'POČÚVAM...'; } else { buttonContainer.classList.remove('recording'); buttonText.textContent = 'HOVORIŤ'; } } /** * Spracovanie výsledku rečového rozpoznávania */ function processSpeechResult(recognized, confidence) { const targetWord = currentWord.toLowerCase(); const isCorrect = recognized.includes(targetWord) || targetWord.includes(recognized) || calculateSimilarity(recognized, targetWord) > 0.7; console.log(`Porovnanie: "${recognized}" vs "${targetWord}" = ${isCorrect ? 'SPRÁVNE' : 'NESPRÁVNE'}`); if (isCorrect || confidence > 0.8) { handleSpeechSuccess(); } else { handleSpeechFailure(); } } /** * Spracovanie úspešného rečového cvičenia */ function handleSpeechSuccess() { console.log('Rečové cvičenie úspešné!'); showSpeechResult(true, 'Výborne! Správne si vyslovil slovo.'); setTimeout(() => { closeSpeechModal(); checkGameEnd(); }, 2000); } /** * Spracovanie neúspešného rečového cvičenia */ function handleSpeechFailure() { console.log('Rečové cvičenie neúspešné'); if (speechAttempts >= maxSpeechAttempts) { showSpeechResult(false, 'Skús to ešte raz neskôr.'); setTimeout(() => { closeSpeechModal(); checkGameEnd(); }, 2000); } else { const remainingAttempts = maxSpeechAttempts - speechAttempts; showSpeechResult(false, `Skús to znova. Zostáva ti ${remainingAttempts} pokusov.`); } } /** * Zobrazenie výsledku rečového cvičenia */ function showSpeechResult(success, message) { const resultDiv = document.getElementById('vysledok'); if (!resultDiv) return; const imageSrc = success ? 'images/spravne.png' : 'images/nespravne.png'; resultDiv.innerHTML = `