Spaces:
Running
Running
| document.addEventListener('DOMContentLoaded', function() { | |
| // 檢查是否有玩家資料 | |
| const currentPlayerId = localStorage.getItem('currentPlayerId'); | |
| const playerName = localStorage.getItem('playerName'); | |
| const playerProfession = localStorage.getItem('playerProfession'); | |
| // 如果沒有玩家資料,重定向到首頁 | |
| if (!currentPlayerId || !playerName || !playerProfession) { | |
| alert('請先登入遊戲!'); | |
| window.location.href = 'index.html'; | |
| return; | |
| } | |
| // 獲取DOM元素 | |
| const startChallengeBtn = document.getElementById('start-challenge'); | |
| const quizContainer = document.getElementById('quiz-container'); | |
| const resultContainer = document.getElementById('result-container'); | |
| const questionTitle = document.getElementById('question-title'); | |
| const formulaDisplay = document.getElementById('formula-display'); | |
| const formulaTemplate = document.getElementById('formula-template'); | |
| const dragItems = document.getElementById('drag-items'); | |
| const stage1Btn = document.getElementById('stage-1-btn'); | |
| const stage2Btn = document.getElementById('stage-2-btn'); | |
| const checkAnswerBtn = document.getElementById('check-answer'); | |
| const nextQuestionBtn = document.getElementById('next-question'); | |
| const currentQuestionSpan = document.getElementById('current-question'); | |
| const feedbackContainer = document.getElementById('feedback-container'); | |
| const resultTitle = document.getElementById('result-title'); | |
| const resultMessage = document.getElementById('result-message'); | |
| const retryBtn = document.getElementById('retry-challenge'); | |
| const backToMapBtn = document.getElementById('back-to-map'); | |
| const nextTrialBtn = document.getElementById('next-trial'); | |
| const doorsProgress = document.getElementById('doors-progress').children; | |
| const successButtons = document.getElementById('success-buttons'); | |
| const failButtons = document.getElementById('fail-buttons'); | |
| const bgmAudio = document.getElementById('bgm'); | |
| const correctSound = document.getElementById('correct-sound'); | |
| const wrongSound = document.getElementById('wrong-sound'); | |
| const toggleBgmBtn = document.getElementById('toggle-bgm'); | |
| const starResults = [ | |
| document.getElementById('star-1'), | |
| document.getElementById('star-2'), | |
| document.getElementById('star-3') | |
| ]; | |
| // 音樂控制 | |
| let isBgmPlaying = false; | |
| // 播放背景音樂 | |
| function playBgm() { | |
| bgmAudio.volume = 0.3; // 設置音量 | |
| bgmAudio.play().catch(e => console.log('自動播放被阻止:', e)); | |
| isBgmPlaying = true; | |
| toggleBgmBtn.textContent = '音樂關'; | |
| } | |
| // 嘗試自動播放背景音樂(大多數瀏覽器會阻止) | |
| playBgm(); | |
| // 音樂開關按鈕 | |
| toggleBgmBtn.addEventListener('click', function() { | |
| if (isBgmPlaying) { | |
| bgmAudio.pause(); | |
| isBgmPlaying = false; | |
| toggleBgmBtn.textContent = '音樂開'; | |
| localStorage.setItem('towerMusicPlaying', 'false'); | |
| } else { | |
| bgmAudio.play(); | |
| isBgmPlaying = true; | |
| toggleBgmBtn.textContent = '音樂關'; | |
| localStorage.setItem('towerMusicPlaying', 'true'); | |
| } | |
| }); | |
| // 問題資料 | |
| const questions = [ | |
| { | |
| title: "101² = (100 + 1)² = (100+1) × (100+1)", | |
| stage1: { | |
| template: "100² + ___ × ___ + ___ × ___ + 1²", | |
| dragItems: ["100", "99", "200", "1", "2"], | |
| answers: [["1", "100"], ["1", "100"]], // 順序不限 | |
| correctAnswer: "100² + 100 × 1 + 1 × 100 + 1²" | |
| }, | |
| stage2: { | |
| template: "100² + ___ × ___ × ___ + 1²", | |
| dragItems: ["100", "99", "200", "1", "2"], | |
| answers: [["2", "100", "1"]] // 除了2之外,順序不限 | |
| } | |
| }, | |
| { | |
| title: "99² = (100 - 1)² = (100-1) × (100-1)", | |
| stage1: { | |
| template: "100² - ___ × ___ - ___ × ___ + 1²", | |
| dragItems: ["1", "2", "100", "98", "200"], | |
| answers: [["1", "100"], ["1", "100"]], // 順序不限 | |
| correctAnswer: "100² - 100 × 1 - 1 × 100 + 1²" | |
| }, | |
| stage2: { | |
| template: "100² - ___ × ___ × ___ + 1²", | |
| dragItems: ["1", "2", "100", "98", "200"], | |
| answers: [["2", "100", "1"]] // 除了2之外,順序不限 | |
| } | |
| }, | |
| { | |
| title: "23² = (20 + 3)² = (20+3) × (20+3)", | |
| stage1: { | |
| template: "20² + ___ × ___ + ___ × ___ + 3²", | |
| dragItems: ["2", "20", "3", "23", "17"], | |
| answers: [["20", "3"], ["3", "20"]], // 順序不限 | |
| correctAnswer: "20² + 20 × 3 + 3 × 20 + 3²" | |
| }, | |
| stage2: { | |
| template: "20² + ___ × ___ × ___ + 3²", | |
| dragItems: ["2", "20", "3", "23", "17"], | |
| answers: [["2", "20", "3"]] // 除了2之外,順序不限 | |
| } | |
| }, | |
| { | |
| title: "38² = (40 - 2)² = (40-2) × (40-2)", | |
| stage1: { | |
| template: "40² - ___ × ___ - ___ × ___ + 2²", | |
| dragItems: ["1", "2", "40", "38", "42"], | |
| answers: [["2", "40"], ["40", "2"]], // 順序不限 | |
| correctAnswer: "40² - 40 × 2 - 2 × 40 + 2²" | |
| }, | |
| stage2: { | |
| template: "40² - ___ × ___ × ___ + 2²", | |
| dragItems: ["1", "2", "40", "38", "42"], | |
| answers: [["2", "40", "2"]] // 除了第一個2之外,順序不限 | |
| } | |
| }, | |
| { | |
| title: "203² = (200 + 3)² = (200 + 3) × (200 + 3)", | |
| stage1: { | |
| template: "200² + ___ × ___ + ___ × ___ + 3²", | |
| dragItems: ["2", "3", "200", "203", "197"], | |
| answers: [["3", "200"], ["200", "3"]], // 順序不限 | |
| correctAnswer: "200² + 200 × 3 + 3 × 200 + 3²" | |
| }, | |
| stage2: { | |
| template: "200² + ___ × ___ × ___ + 3²", | |
| dragItems: ["2", "3", "200", "203", "197"], | |
| answers: [["2", "200", "3"]] // 除了2之外,順序不限 | |
| } | |
| }, | |
| { | |
| title: "297² = (300 - 3)² = (300 - 3) × (300 - 3)", | |
| stage1: { | |
| template: "300² - ___ × ___ - ___ × ___ + 3²", | |
| dragItems: ["2", "300", "3", "297", "303"], | |
| answers: [["300", "3"], ["3", "300"]], // 順序不限 | |
| correctAnswer: "300² - 300 × 3 - 3 × 300 + 3²" | |
| }, | |
| stage2: { | |
| template: "300² - ___ × ___ × ___ + 3²", | |
| dragItems: ["2", "300", "3", "297", "303"], | |
| answers: [["2", "300", "3"]] // 除了2之外,順序不限 | |
| } | |
| } | |
| ]; | |
| // 遊戲狀態 | |
| let currentQuestionIndex = 0; | |
| let currentStage = 1; | |
| let correctAnswers = 0; | |
| let userAnswers = []; // 記錄用戶答案 | |
| let dropZones = []; // 當前問題的所有拖放區 | |
| let dragItemElements = []; // 當前問題的所有拖拽項 | |
| let wrongAttempts = 0; // 記錄當前問題錯誤嘗試次數 | |
| let sortableInstances = []; // 儲存所有Sortable實例 | |
| // 獲取遊戲進度 | |
| const gameProgress = JSON.parse(localStorage.getItem(`gameProgress_${currentPlayerId}`)) || { | |
| completedTrials: { | |
| "平方之泉": { completed: false, score: 0, challengesCompleted: [false, false, false, false, false, false] }, | |
| "變換山谷": { completed: false, score: 0, challengesCompleted: [false, false, false, false, false, false] }, | |
| "展開之塔": { completed: false, score: 0, challengesCompleted: [false, false, false, false, false, false] } | |
| }, | |
| currentLocation: "展開之塔", | |
| lastSaved: new Date().toISOString() | |
| }; | |
| // 開始挑戰按鈕點擊事件 | |
| startChallengeBtn.addEventListener('click', function() { | |
| startChallengeBtn.style.display = 'none'; | |
| quizContainer.style.display = 'block'; | |
| loadQuestion(0, 1); | |
| }); | |
| // 儲存每個階段的答案 | |
| let stage1Answers = Array(questions.length).fill(null).map(() => []); | |
| let stage2Answers = Array(questions.length).fill(null).map(() => []); | |
| // 載入問題 | |
| function loadQuestion(questionIndex, stageIndex) { | |
| currentQuestionIndex = questionIndex; | |
| currentStage = stageIndex; | |
| wrongAttempts = 0; // 重置錯誤嘗試次數 | |
| // 清除所有Sortable實例 | |
| sortableInstances.forEach(instance => { | |
| if (instance && typeof instance.destroy === 'function') { | |
| instance.destroy(); | |
| } | |
| }); | |
| sortableInstances = []; | |
| // 更新問題標題和進度 | |
| currentQuestionSpan.textContent = questionIndex + 1; | |
| questionTitle.textContent = `問題 ${questionIndex + 1}`; | |
| // 顯示題目,將標題分成兩行,並讓等號垂直對齊 | |
| const titleParts = questions[questionIndex].title.split('='); | |
| if (titleParts.length >= 3) { | |
| formulaDisplay.innerHTML = `${titleParts[0]} = ${titleParts[1]}<br><span style="display: inline-block; width: 8px;"></span>= ${titleParts[2]}`; | |
| } else { | |
| formulaDisplay.textContent = questions[questionIndex].title; | |
| } | |
| // 更新階段按鈕狀態 | |
| stage1Btn.classList.toggle('active', stageIndex === 1); | |
| stage2Btn.classList.toggle('active', stageIndex === 2); | |
| // 清空公式模板和拖拽項 | |
| formulaTemplate.innerHTML = ''; | |
| dragItems.innerHTML = ''; | |
| dropZones = []; | |
| // 移除所有現有的參考區域 | |
| const existingReferences = document.querySelectorAll('.stage1-reference'); | |
| existingReferences.forEach(ref => ref.remove()); | |
| // 移除提示圖片和提示容器 | |
| const existingHintContainers = document.querySelectorAll('.hint-container'); | |
| existingHintContainers.forEach(container => container.remove()); | |
| // 移除所有無作用的小框框 | |
| const emptyBoxes = document.querySelectorAll('.empty-box'); | |
| emptyBoxes.forEach(box => box.remove()); | |
| // 如果是第二階段,顯示第一階段的答案作為參考 | |
| if (stageIndex === 2 && stage1Answers[questionIndex].length > 0) { | |
| // 創建參考區域 | |
| const referenceDiv = document.createElement('div'); | |
| referenceDiv.className = 'stage1-reference'; | |
| referenceDiv.style.marginBottom = '15px'; | |
| referenceDiv.style.padding = '10px'; | |
| referenceDiv.style.backgroundColor = 'rgba(60, 60, 60, 0.7)'; | |
| referenceDiv.style.borderRadius = '8px'; | |
| referenceDiv.style.border = '1px solid rgba(255, 140, 0, 0.5)'; | |
| // 創建參考標題 | |
| const referenceTitle = document.createElement('div'); | |
| referenceTitle.textContent = '第一階段答案參考:'; | |
| referenceTitle.style.color = 'rgba(255, 165, 0, 0.9)'; | |
| referenceTitle.style.marginBottom = '5px'; | |
| referenceDiv.appendChild(referenceTitle); | |
| // 獲取第一階段的模板和答案 | |
| const stage1Template = questions[questionIndex].stage1.template; | |
| const stage1Values = stage1Answers[questionIndex]; | |
| // 創建完整算式 | |
| let fullFormula = stage1Template; | |
| stage1Values.forEach((value, index) => { | |
| fullFormula = fullFormula.replace('___', value); | |
| }); | |
| // 顯示完整算式 | |
| const formulaText = document.createElement('div'); | |
| formulaText.textContent = fullFormula; | |
| formulaText.style.color = 'white'; | |
| formulaText.style.fontSize = '1.1rem'; | |
| referenceDiv.appendChild(formulaText); | |
| // 插入到公式模板前面 | |
| formulaTemplate.parentNode.insertBefore(referenceDiv, formulaTemplate); | |
| } | |
| // 獲取當前階段的問題數據 | |
| const stageData = stageIndex === 1 ? questions[questionIndex].stage1 : questions[questionIndex].stage2; | |
| // 獲取已保存的答案 | |
| const savedAnswers = stageIndex === 1 ? stage1Answers[questionIndex] : stage2Answers[questionIndex]; | |
| // 創建公式模板 | |
| const templateParts = stageData.template.split('___'); | |
| for (let i = 0; i < templateParts.length; i++) { | |
| // 添加文本部分 | |
| const textSpan = document.createElement('span'); | |
| textSpan.textContent = templateParts[i]; | |
| textSpan.style.display = 'inline-block'; | |
| textSpan.style.verticalAlign = 'middle'; | |
| formulaTemplate.appendChild(textSpan); | |
| // 如果不是最後一部分,添加拖放區 | |
| if (i < templateParts.length - 1) { | |
| const dropZone = document.createElement('span'); | |
| dropZone.className = 'drop-zone sortable-container'; | |
| dropZone.dataset.index = i; | |
| dropZone.style.display = 'inline-flex'; | |
| dropZone.style.justifyContent = 'center'; | |
| dropZone.style.alignItems = 'center'; | |
| dropZone.style.verticalAlign = 'middle'; | |
| dropZone.style.height = '40px'; | |
| formulaTemplate.appendChild(dropZone); | |
| dropZones.push(dropZone); | |
| // 防止觸控滾動 | |
| dropZone.addEventListener('touchmove', function(e) { | |
| e.preventDefault(); | |
| }, { passive: false }); | |
| // 初始化每個拖放區的Sortable | |
| const dropZoneSortable = new Sortable(dropZone, { | |
| group: { | |
| name: 'formula', | |
| pull: 'clone', // 允許從答案區拖出,但會被移除 | |
| put: true | |
| }, | |
| animation: 100, | |
| delay: 0, | |
| touchStartThreshold: 5, | |
| ghostClass: "drag-ghost", | |
| forceFallback: true, | |
| fallbackTolerance: 3, | |
| sort: false, // 禁止在拖放區內排序 | |
| filter: '.disabled', // 禁止拖拽的元素 | |
| onAdd: function(evt) { | |
| const item = evt.item; | |
| // 如果拖放區已有內容,先清空 | |
| if (evt.to.children.length > 1) { | |
| // 保留最新添加的元素,移除其他元素 | |
| Array.from(evt.to.children).forEach(child => { | |
| if (child !== item) { | |
| evt.to.removeChild(child); | |
| } | |
| }); | |
| } | |
| // 設置樣式 | |
| evt.to.classList.add('filled'); | |
| evt.to.style.backgroundColor = 'rgba(255, 140, 0, 0.3)'; | |
| // 更新保存的答案 | |
| updateSavedAnswers(); | |
| }, | |
| onRemove: function(evt) { | |
| // 當元素被移出時,移除filled類 | |
| evt.from.classList.remove('filled'); | |
| evt.from.style.backgroundColor = 'rgba(100, 100, 100, 0.5)'; | |
| // 從答案格拖出的方塊直接移除,不回到拖拉區 | |
| if (evt.item && evt.item.parentNode) { | |
| evt.item.remove(); | |
| } | |
| // 更新保存的答案 | |
| updateSavedAnswers(); | |
| } | |
| }); | |
| sortableInstances.push(dropZoneSortable); | |
| } | |
| } | |
| // 創建拖拽項容器 | |
| const dragItemsContainer = document.createElement('div'); | |
| dragItemsContainer.className = 'sortable-container'; | |
| dragItemsContainer.style.display = 'flex'; | |
| dragItemsContainer.style.flexWrap = 'wrap'; | |
| dragItemsContainer.style.justifyContent = 'center'; | |
| dragItemsContainer.style.gap = '15px'; | |
| dragItems.appendChild(dragItemsContainer); | |
| // 防止觸控滾動 | |
| dragItemsContainer.addEventListener('touchmove', function(e) { | |
| e.preventDefault(); | |
| }, { passive: false }); | |
| // 創建拖拽項 | |
| stageData.dragItems.forEach((item, index) => { | |
| const dragItem = document.createElement('div'); | |
| dragItem.className = 'drag-item'; | |
| dragItem.id = `drag-item-${index}`; | |
| dragItem.textContent = item; | |
| dragItem.dataset.value = item; | |
| dragItem.style.willChange = 'transform'; | |
| dragItem.style.touchAction = 'none'; | |
| // 添加點擊事件,點擊可移除(如果在拖放區內) | |
| dragItem.addEventListener('click', function() { | |
| const parent = this.parentElement; | |
| if (parent && parent.classList.contains('drop-zone')) { | |
| parent.classList.remove('filled'); | |
| parent.style.backgroundColor = 'rgba(100, 100, 100, 0.5)'; | |
| // 移除元素 | |
| this.remove(); | |
| // 更新保存的答案 | |
| updateSavedAnswers(); | |
| } | |
| }); | |
| dragItemsContainer.appendChild(dragItem); | |
| dragItemElements.push(dragItem); | |
| }); | |
| // 初始化拖拽項容器的Sortable | |
| const dragItemsSortable = new Sortable(dragItemsContainer, { | |
| group: { | |
| name: 'formula', | |
| pull: 'clone', // 設置為clone模式,拖拽項不會消失 | |
| put: false // 不允許放回拖拽區 | |
| }, | |
| animation: 100, | |
| delay: 0, | |
| touchStartThreshold: 5, | |
| ghostClass: "drag-ghost", | |
| forceFallback: true, | |
| fallbackTolerance: 3, | |
| sort: false, // 禁止排序 | |
| filter: '.disabled', // 禁止拖拽的元素 | |
| onClone: function(evt) { | |
| // 克隆元素時添加相同的樣式和數據 | |
| evt.clone.className = evt.item.className; | |
| evt.clone.dataset.value = evt.item.dataset.value; | |
| evt.clone.style.willChange = 'transform'; | |
| evt.clone.style.touchAction = 'none'; | |
| // 添加點擊事件,點擊可移除(如果在拖放區內) | |
| evt.clone.addEventListener('click', function() { | |
| const parent = this.parentElement; | |
| if (parent && parent.classList.contains('drop-zone')) { | |
| parent.classList.remove('filled'); | |
| parent.style.backgroundColor = 'rgba(100, 100, 100, 0.5)'; | |
| // 移除元素 | |
| this.remove(); | |
| // 更新保存的答案 | |
| updateSavedAnswers(); | |
| } | |
| }); | |
| } | |
| }); | |
| sortableInstances.push(dragItemsSortable); | |
| // 如果有已保存的答案,恢復它們 | |
| if (savedAnswers && savedAnswers.length > 0) { | |
| savedAnswers.forEach((value, index) => { | |
| if (index < dropZones.length && value) { | |
| // 找到對應值的拖拽項 | |
| const matchingItem = Array.from(dragItemElements).find(item => item.dataset.value === value); | |
| if (matchingItem) { | |
| // 克隆拖拽項 | |
| const clone = matchingItem.cloneNode(true); | |
| clone.dataset.value = value; | |
| // 添加點擊事件,點擊可移除 | |
| clone.addEventListener('click', function() { | |
| const parent = this.parentElement; | |
| if (parent && parent.classList.contains('drop-zone')) { | |
| parent.classList.remove('filled'); | |
| parent.style.backgroundColor = 'rgba(100, 100, 100, 0.5)'; | |
| // 移除元素 | |
| this.remove(); | |
| // 更新保存的答案 | |
| updateSavedAnswers(); | |
| } | |
| }); | |
| // 添加到拖放區 | |
| dropZones[index].appendChild(clone); | |
| dropZones[index].classList.add('filled'); | |
| dropZones[index].style.backgroundColor = 'rgba(255, 140, 0, 0.3)'; | |
| } | |
| } | |
| }); | |
| } | |
| // 顯示檢查答案按鈕,隱藏下一題按鈕 | |
| checkAnswerBtn.style.display = 'inline-block'; | |
| nextQuestionBtn.style.display = 'none'; | |
| // 清空反饋容器 | |
| feedbackContainer.innerHTML = ''; | |
| feedbackContainer.style.display = 'none'; | |
| } | |
| // 更新保存的答案 | |
| function updateSavedAnswers() { | |
| const answers = []; | |
| // 獲取所有拖放區的值 | |
| dropZones.forEach(zone => { | |
| const items = zone.querySelectorAll('.drag-item'); | |
| if (items.length > 0) { | |
| answers.push(items[0].dataset.value); | |
| } else { | |
| answers.push(null); | |
| } | |
| }); | |
| // 保存答案 | |
| if (currentStage === 1) { | |
| stage1Answers[currentQuestionIndex] = answers; | |
| } else { | |
| stage2Answers[currentQuestionIndex] = answers; | |
| } | |
| } | |
| // 檢查答案 | |
| function checkAnswer() { | |
| // 獲取當前階段的問題數據 | |
| const stageData = currentStage === 1 ? questions[currentQuestionIndex].stage1 : questions[currentQuestionIndex].stage2; | |
| // 獲取用戶答案 | |
| const userAnswerValues = []; | |
| dropZones.forEach(zone => { | |
| const items = zone.querySelectorAll('.drag-item'); | |
| if (items.length > 0) { | |
| userAnswerValues.push(items[0].dataset.value); | |
| } else { | |
| userAnswerValues.push(null); | |
| } | |
| }); | |
| // 檢查是否有空白答案 | |
| if (userAnswerValues.includes(null)) { | |
| feedbackContainer.innerHTML = '<p class="error">請填寫所有空格!</p>'; | |
| feedbackContainer.style.display = 'block'; | |
| return false; | |
| } | |
| // 檢查答案是否正確 | |
| let isCorrect = false; | |
| if (currentStage === 1) { | |
| // 第一階段:檢查兩組答案是否匹配 | |
| const group1 = [userAnswerValues[0], userAnswerValues[1]]; | |
| const group2 = [userAnswerValues[2], userAnswerValues[3]]; | |
| // 檢查每個答案組合是否匹配任何一個正確答案組合 | |
| isCorrect = stageData.answers.some(answer => { | |
| return ( | |
| (group1.includes(answer[0]) && group1.includes(answer[1])) && | |
| (group2.includes(answer[0]) && group2.includes(answer[1])) | |
| ); | |
| }); | |
| } else { | |
| // 第二階段:檢查三個值是否匹配 | |
| isCorrect = stageData.answers.some(answer => { | |
| // 第一個值必須是2 | |
| if (userAnswerValues[0] !== answer[0]) return false; | |
| // 其他兩個值順序不限 | |
| const otherValues = [userAnswerValues[1], userAnswerValues[2]]; | |
| return ( | |
| otherValues.includes(answer[1]) && | |
| otherValues.includes(answer[2]) | |
| ); | |
| }); | |
| } | |
| // 顯示反饋 | |
| feedbackContainer.innerHTML = ''; | |
| feedbackContainer.style.display = 'block'; | |
| if (isCorrect) { | |
| // 播放正確音效 | |
| correctSound.currentTime = 0; | |
| correctSound.play().catch(e => console.log('播放音效失敗:', e)); | |
| // 顯示正確反饋 | |
| const correctFeedback = document.createElement('p'); | |
| correctFeedback.className = 'success'; | |
| correctFeedback.textContent = '答對了!'; | |
| feedbackContainer.appendChild(correctFeedback); | |
| // 更新UI | |
| checkAnswerBtn.style.display = 'none'; | |
| if (currentStage === 1) { | |
| // 第一階段完成,進入第二階段 | |
| nextQuestionBtn.textContent = '進入第二階段'; | |
| nextQuestionBtn.onclick = function() { | |
| loadQuestion(currentQuestionIndex, 2); | |
| }; | |
| } else { | |
| // 第二階段完成,進入下一題或完成挑戰 | |
| if (currentQuestionIndex < questions.length - 1) { | |
| nextQuestionBtn.textContent = '下一題'; | |
| nextQuestionBtn.onclick = function() { | |
| loadQuestion(currentQuestionIndex + 1, 1); | |
| }; | |
| } else { | |
| nextQuestionBtn.textContent = '完成挑戰'; | |
| nextQuestionBtn.onclick = function() { | |
| showResult(); | |
| }; | |
| } | |
| } | |
| nextQuestionBtn.style.display = 'inline-block'; | |
| // 更新進度 | |
| if (currentStage === 2) { | |
| doorsProgress[currentQuestionIndex].classList.add('completed'); | |
| correctAnswers++; | |
| } | |
| return true; | |
| } else { | |
| // 播放錯誤音效 | |
| wrongSound.currentTime = 0; | |
| wrongSound.play().catch(e => console.log('播放音效失敗:', e)); | |
| // 增加錯誤嘗試次數 | |
| wrongAttempts++; | |
| // 第一階段特殊處理 | |
| if (currentStage === 1) { | |
| // 創建提示容器(如果不存在) | |
| let hintContainer = document.querySelector('.hint-container'); | |
| if (!hintContainer) { | |
| hintContainer = document.createElement('div'); | |
| hintContainer.className = 'hint-container'; | |
| hintContainer.style.marginBottom = '15px'; | |
| hintContainer.style.padding = '10px'; | |
| hintContainer.style.backgroundColor = 'rgba(60, 60, 60, 0.7)'; | |
| hintContainer.style.borderRadius = '8px'; | |
| hintContainer.style.border = '1px solid rgba(255, 0, 0, 0.5)'; | |
| hintContainer.style.textAlign = 'center'; | |
| // 插入到公式模板前面 | |
| formulaTemplate.parentNode.insertBefore(hintContainer, formulaTemplate); | |
| } | |
| // 清空提示容器 | |
| hintContainer.innerHTML = ''; | |
| // 添加提示圖片 | |
| const hintImage = document.createElement('img'); | |
| hintImage.src = `towerhint${currentQuestionIndex + 1}1.jpg`; | |
| hintImage.style.maxWidth = '50%'; | |
| hintImage.style.display = 'block'; | |
| hintImage.style.margin = '0 auto 10px'; | |
| hintContainer.appendChild(hintImage); | |
| // 添加提示文字 | |
| const hintText = document.createElement('p'); | |
| hintText.style.color = 'white'; | |
| hintText.style.margin = '5px 0'; | |
| if (wrongAttempts === 1) { | |
| // 第一次錯誤 | |
| hintText.textContent = '請仔細觀察上方提示圖,按照分配律的方式展開填入正確答案。'; | |
| } else { | |
| // 第二次或更多次錯誤 | |
| hintText.textContent = `正確答案應為:\n「${stageData.correctAnswer}」\n請依照此答案填入,才能進入第二階段。`; | |
| } | |
| hintContainer.appendChild(hintText); | |
| // 顯示錯誤反饋 | |
| const errorFeedback = document.createElement('p'); | |
| errorFeedback.className = 'error'; | |
| errorFeedback.textContent = '答錯了,請參考上方提示修正答案!'; | |
| feedbackContainer.appendChild(errorFeedback); | |
| } else { | |
| // 第二階段錯誤 | |
| const errorFeedback = document.createElement('p'); | |
| errorFeedback.className = 'error'; | |
| errorFeedback.textContent = '答錯了,請再試一次!'; | |
| feedbackContainer.appendChild(errorFeedback); | |
| } | |
| return false; | |
| } | |
| } | |
| // 顯示結果 | |
| function showResult() { | |
| quizContainer.style.display = 'none'; | |
| resultContainer.style.display = 'block'; | |
| // 計算得分(滿分3星) | |
| const score = Math.min(3, Math.max(1, Math.ceil(correctAnswers / questions.length * 3))); | |
| // 更新星星顯示 | |
| for (let i = 0; i < starResults.length; i++) { | |
| starResults[i].style.opacity = i < score ? '1' : '0.3'; | |
| } | |
| // 更新結果文字 | |
| if (score === 3) { | |
| resultTitle.textContent = '恭喜完成挑戰!'; | |
| resultMessage.textContent = '你已完美掌握平方展開的技巧!'; | |
| successButtons.style.display = 'block'; | |
| failButtons.style.display = 'none'; | |
| } else if (score === 2) { | |
| resultTitle.textContent = '挑戰成功!'; | |
| resultMessage.textContent = '你已基本掌握平方展開的技巧,繼續加油!'; | |
| successButtons.style.display = 'block'; | |
| failButtons.style.display = 'none'; | |
| } else { | |
| resultTitle.textContent = '再接再厲!'; | |
| resultMessage.textContent = '平方展開需要更多練習,不要氣餒!'; | |
| successButtons.style.display = 'none'; | |
| failButtons.style.display = 'block'; | |
| } | |
| // 更新遊戲進度 | |
| gameProgress.completedTrials["展開之塔"].completed = score >= 2; | |
| gameProgress.completedTrials["展開之塔"].score = score; | |
| // 標記所有問題為已完成 | |
| for (let i = 0; i < questions.length; i++) { | |
| gameProgress.completedTrials["展開之塔"].challengesCompleted[i] = true; | |
| } | |
| // 保存遊戲進度 | |
| gameProgress.lastSaved = new Date().toISOString(); | |
| localStorage.setItem(`gameProgress_${currentPlayerId}`, JSON.stringify(gameProgress)); | |
| // 檢查成就 | |
| if (window.achievementSystem) { | |
| const gameState = { | |
| currentTrial: "展開之塔", | |
| totalStars: score, | |
| currentTrialCompleted: true, | |
| currentTrialErrors: questions.length - correctAnswers, | |
| currentTrialCombo: correctAnswers, | |
| completedTrials: { | |
| "展開之塔": { | |
| completed: true, | |
| stars: score, | |
| noErrors: (questions.length - correctAnswers) === 0 | |
| } | |
| } | |
| }; | |
| window.achievementSystem.checkAllAchievements(gameState); | |
| } | |
| } | |
| // 檢查答案按鈕點擊事件 | |
| checkAnswerBtn.addEventListener('click', function() { | |
| checkAnswer(); | |
| }); | |
| // 重試按鈕點擊事件 | |
| retryBtn.addEventListener('click', function() { | |
| resultContainer.style.display = 'none'; | |
| quizContainer.style.display = 'block'; | |
| correctAnswers = 0; | |
| // 重置進度指示器 | |
| Array.from(doorsProgress).forEach(door => { | |
| door.classList.remove('completed'); | |
| }); | |
| // 重置答案 | |
| stage1Answers = Array(questions.length).fill(null).map(() => []); | |
| stage2Answers = Array(questions.length).fill(null).map(() => []); | |
| // 載入第一題 | |
| loadQuestion(0, 1); | |
| }); | |
| // 返回地圖按鈕點擊事件 | |
| backToMapBtn.addEventListener('click', function() { | |
| window.location.href = 'kingdom_map.html'; | |
| }); | |
| // 下一試煉按鈕點擊事件 | |
| nextTrialBtn.addEventListener('click', function() { | |
| window.location.href = 'kingdom_map.html'; | |
| }); | |
| // 階段按鈕點擊事件(僅用於顯示,不可切換) | |
| stage1Btn.addEventListener('click', function() { | |
| if (currentStage !== 1) { | |
| // 檢查是否已完成第一階段 | |
| if (stage1Answers[currentQuestionIndex].length > 0) { | |
| loadQuestion(currentQuestionIndex, 1); | |
| } | |
| } | |
| }); | |
| stage2Btn.addEventListener('click', function() { | |
| if (currentStage !== 2) { | |
| // 檢查是否已完成第一階段 | |
| if (stage1Answers[currentQuestionIndex].length > 0) { | |
| loadQuestion(currentQuestionIndex, 2); | |
| } else { | |
| alert('請先完成第一階段!'); | |
| } | |
| } | |
| }); | |
| }); | |