龍族動物森友會

龍族扶輪森友會 - 動物賽跑大賽

🐉 龍族扶輪森友會 🐉

動物森友會賽跑大賽

🏝️🐰🏃‍♂️🦁

歡迎來到動物賽跑世界!

' + description + '
'; document.body.appendChild(toast); setTimeout(function() { toast.classList.remove('translate-x-full'); }, 100); setTimeout(function() { toast.classList.add('translate-x-full'); setTimeout(function() { document.body.removeChild(toast); }, 300); }, 3000); } function showScreen(screenName) { const screens = ['mainScreen', 'joinScreen', 'gameRoom', 'raceScreen']; screens.forEach(function(screen) { document.getElementById(screen).classList.add('hidden'); }); document.getElementById(screenName).classList.remove('hidden'); gameState.currentScreen = screenName; } function generateClientId() { const stored = localStorage.getItem('game_client_id'); if (stored) return stored; const id = 'player_' + Math.random().toString(36).slice(2, 9); localStorage.setItem('game_client_id', id); return id; } // Create Room async function createRoom() { const playerName = prompt('請輸入你的暱稱(作為主持人):'); if (!playerName || playerName.trim() === '') { showToast('錯誤', '請輸入有效的暱稱!', 'error'); return; } const roomId = Math.random().toString(36).substr(2, 6).toUpperCase(); const roomRef = db.ref('rooms/' + roomId); try { const snapshot = await roomRef.once('value'); if (snapshot.exists()) { createRoom(); return; } gameState.roomId = roomId; gameState.isHost = true; gameState.playerName = playerName.trim(); gameState.selectedAnimal = null; gameState.isReady = false; gameState.players = {}; await roomRef.set({ host: gameState.playerName, createdAt: firebase.database.ServerValue.TIMESTAMP, raceActive: false, raceResults: null }); await db.ref('rooms/' + roomId + '/players/' + gameState.playerName).set({ name: gameState.playerName, animal: null, ready: false, isHost: true }); setupRoomListeners(); showGameRoom(); showToast('成功', '房間創建成功: ' + roomId, 'success'); } catch (error) { console.error('Create room error:', error); showToast('錯誤', '創建房間失敗,請重試', 'error'); } } // Join Room async function joinRoom() { const roomId = document.getElementById('roomIdInput').value.trim().toUpperCase(); const playerName = document.getElementById('nicknameInput').value.trim(); if (!roomId || !playerName) { showToast('錯誤', '請填寫房間號碼和暱稱!', 'error'); return; } try { const roomSnapshot = await db.ref('rooms/' + roomId).once('value'); if (!roomSnapshot.exists()) { showToast('錯誤', '房間不存在!', 'error'); return; } const roomData = roomSnapshot.val(); if (roomData.raceActive) { showToast('錯誤', '比賽進行中,無法加入!', 'error'); return; } const playersSnapshot = await db.ref('rooms/' + roomId + '/players').once('value'); const players = playersSnapshot.val() || {}; if (Object.keys(players).length >= 20) { showToast('錯誤', '房間已滿!', 'error'); return; } if (players[playerName]) { showToast('錯誤', '暱稱已被使用!', 'error'); return; } gameState.roomId = roomId; gameState.isHost = false; gameState.playerName = playerName; gameState.selectedAnimal = null; gameState.isReady = false; gameState.players = {}; await db.ref('rooms/' + roomId + '/players/' + playerName).set({ name: playerName, animal: null, ready: false, isHost: false }); setupRoomListeners(); showGameRoom(); showToast('成功', '成功加入房間: ' + roomId, 'success'); } catch (error) { console.error('Join room error:', error); showToast('錯誤', '加入房間失敗,請重試', 'error'); } } // Fixed joinOrUpdate function - corrected variable assignment function joinOrUpdate() { const name = document.getElementById('player-name-input').value.trim(); const animal = document.getElementById('animal-select').value; const isHost = document.getElementById('host-checkbox').checked; if (!name) { showToast('錯誤', '請輸入你的名稱才能加入房間', 'error'); return; } localStorage.setItem('game_name', name); localStorage.setItem('game_animal', animal); gameState.playerName = name; gameState.selectedAnimal = animal; gameState.isHost = isHost; const playerData = { id: generateClientId(), name: name, animal: animal, joinedAt: Date.now() }; // Fixed: Proper object initialization and assignment const updates = {}; updates['players/' + playerData.id] = playerData; if (isHost && !gameState.hostId) { updates.hostId = playerData.id; } const joinBtn = document.getElementById('join-room-btn'); const originalText = joinBtn.innerHTML; joinBtn.innerHTML = '🔄 連接中...'; joinBtn.disabled = true; db.ref('rooms/' + gameState.roomId).update(updates).then(function() { showToast('成功', '歡迎 ' + name + '!', 'success'); db.ref('rooms/' + gameState.roomId + '/players/' + playerData.id).onDisconnect().remove(); }).catch(function(error) { console.error('Error joining room:', error); showToast('錯誤', '加入失敗,請稍後重試', 'error'); }).finally(function() { joinBtn.innerHTML = originalText; joinBtn.disabled = false; }); } function setupRoomListeners() { db.ref('rooms/' + gameState.roomId + '/players').on('value', function(snapshot) { const players = snapshot.val() || {}; gameState.players = players; updatePlayersDisplay(); updateUIState(); }); db.ref('rooms/' + gameState.roomId + '/raceActive').on('value', function(snapshot) { const raceActive = snapshot.val() || false; gameState.raceActive = raceActive; if (raceActive) { showRaceScreen(); startRace(); } }); db.ref('rooms/' + gameState.roomId + '/raceResults').on('value', function(snapshot) { const results = snapshot.val(); if (results) { gameState.raceResults = results; showRaceResults(results); } }); } function showGameRoom() { showScreen('gameRoom'); document.getElementById('currentRoomId').textContent = gameState.roomId; document.getElementById('userRole').textContent = gameState.isHost ? '主持人' : '參與者'; createAnimalSelection(); updatePlayersDisplay(); updateUIState(); } function createAnimalSelection() { const grid = document.getElementById('animalGrid'); grid.innerHTML = ''; gameState.animals.forEach(function(animal) { const button = document.createElement('button'); button.className = 'animal-btn w-16 h-16 bg-white border-2 border-gray-300 rounded-xl flex items-center justify-center text-2xl hover:border-blue-500 hover:bg-blue-50 transition-all'; button.innerHTML = animal.emoji; button.title = animal.name; button.onclick = function() { selectAnimal(animal); }; grid.appendChild(button); }); } async function selectAnimal(animal) { if (gameState.raceActive) { showToast('錯誤', '比賽進行中無法更換動物!', 'error'); return; } const isAnimalTaken = Object.values(gameState.players).some(function(player) { return player.animal && player.animal.id === animal.id && player.name !== gameState.playerName; }); if (isAnimalTaken) { showToast('錯誤', '這隻動物已被其他玩家選擇!', 'error'); return; } try { gameState.selectedAnimal = animal; await db.ref('rooms/' + gameState.roomId + '/players/' + gameState.playerName).update({ animal: animal }); updateAnimalSelection(); showToast('成功', '已選擇 ' + animal.name, 'success'); } catch (error) { console.error('Select animal error:', error); showToast('錯誤', '選擇動物失敗,請重試', 'error'); } } function updateAnimalSelection() { const buttons = document.querySelectorAll('.animal-btn'); buttons.forEach(function(btn) { btn.classList.remove('border-blue-500', 'bg-blue-100', 'border-red-500', 'bg-red-100'); btn.classList.add('border-gray-300', 'bg-white'); }); Object.values(gameState.players).forEach(function(player) { if (player.animal) { const animalIndex = gameState.animals.findIndex(function(a) { return a.id === player.animal.id; }); if (animalIndex !== -1) { const btn = buttons[animalIndex]; if (player.name === gameState.playerName) { btn.classList.add('border-blue-500', 'bg-blue-100'); } else { btn.classList.add('border-red-500', 'bg-red-100'); } } } }); } function updatePlayersDisplay() { const playersList = document.getElementById('playersList'); const playerCount = document.getElementById('playerCount'); const players = Object.values(gameState.players); playerCount.textContent = players.length; if (players.length === 0) { playersList.innerHTML = '
暫無玩家
'; return; } playersList.innerHTML = ''; players.forEach(function(player) { const playerDiv = document.createElement('div'); playerDiv.className = 'flex items-center justify-between p-3 bg-white rounded-lg shadow-sm'; const animalDisplay = player.animal ? (player.animal.emoji + ' ' + player.animal.name) : '未選擇動物'; const readyStatus = player.ready ? '✅ 已準備' : '⏳ 未準備'; const hostBadge = player.isHost ? ' 👑' : ''; playerDiv.innerHTML = '
' + player.name + hostBadge + '
' + animalDisplay + '
' + readyStatus + '
'; playersList.appendChild(playerDiv); }); updateAnimalSelection(); } async function toggleReady() { if (!gameState.selectedAnimal) { showToast('錯誤', '請先選擇一隻動物!', 'error'); return; } if (gameState.raceActive) { showToast('錯誤', '比賽進行中無法更改準備狀態!', 'error'); return; } try { const newReadyState = !gameState.isReady; gameState.isReady = newReadyState; await db.ref('rooms/' + gameState.roomId + '/players/' + gameState.playerName).update({ ready: newReadyState }); showToast('狀態', newReadyState ? '已準備完成' : '取消準備', 'success'); } catch (error) { console.error('Toggle ready error:', error); showToast('錯誤', '更新準備狀態失敗,請重試', 'error'); } } function updateUIState() { const readyBtn = document.getElementById('readyBtn'); const startGameBtn = document.getElementById('startGameBtn'); const currentPlayer = gameState.players[gameState.playerName]; if (currentPlayer) { if (currentPlayer.ready) { readyBtn.textContent = '取消準備'; readyBtn.className = 'bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-700 text-white px-8 py-3 rounded-xl font-semibold shadow-lg transform hover:scale-105 transition-all'; } else { readyBtn.textContent = '準備'; readyBtn.className = 'bg-gradient-to-r from-yellow-500 to-yellow-600 hover:from-yellow-600 hover:to-yellow-700 text-white px-8 py-3 rounded-xl font-semibold shadow-lg transform hover:scale-105 transition-all'; } } if (gameState.isHost) { startGameBtn.classList.remove('hidden'); const players = Object.values(gameState.players); const readyPlayers = players.filter(function(p) { return p.ready && p.animal; }); const canStart = readyPlayers.length >= 2 && !gameState.raceActive; startGameBtn.disabled = !canStart; if (canStart) { startGameBtn.className = 'bg-gradient-to-r from-red-500 to-red-600 hover:from-red-600 hover:to-red-700 text-white px-8 py-3 rounded-xl font-semibold shadow-lg transform hover:scale-105 transition-all'; } else { startGameBtn.className = 'bg-gradient-to-r from-gray-400 to-gray-500 text-white px-8 py-3 rounded-xl font-semibold cursor-not-allowed opacity-50'; } } else { startGameBtn.classList.add('hidden'); } } async function startGame() { if (!gameState.isHost) { showToast('錯誤', '只有主持人可以開始遊戲!', 'error'); return; } const players = Object.values(gameState.players); const readyPlayers = players.filter(function(p) { return p.ready && p.animal; }); if (readyPlayers.length
' + player.animal.emoji + '
' + player.name + '
' + player.animal.name + '
🏁
'; raceTrack.appendChild(trackDiv); }); } function startRace() { const readyPlayers = Object.values(gameState.players).filter(function(p) { return p.ready && p.animal; }); readyPlayers.forEach(function(player, index) { const animalElement = document.getElementById('animal-' + index); if (animalElement) { const finishTime = gameState.raceResults[index].finishTime; animalElement.classList.add('running'); animalElement.style.animationDuration = finishTime + 'ms'; animalElement.style.animationTimingFunction = 'ease-out'; } }); const slowestTime = Math.max.apply(Math, gameState.raceResults.map(function(r) { return r.finishTime; })); setTimeout(function() { showRaceResults(gameState.raceResults); }, slowestTime + 1000); } function showRaceResults(results) { const raceResult = document.getElementById('raceResult'); const winnerInfo = document.getElementById('winnerInfo'); if (results && results.length > 0) { const winner = results[0]; winnerInfo.innerHTML = '
' + winner.animal.emoji + '
' + winner.name + '
' + winner.animal.name + ' 獲得勝利!
完成時間: ' + (winner.finishTime / 1000).toFixed(2) + ' 秒
'; } raceResult.classList.remove('hidden'); } async function backToRoom() { try { if (gameState.isHost) { await db.ref('rooms/' + gameState.roomId).update({ raceActive: false, raceResults: null }); } gameState.raceActive = false; gameState.raceResults = null; showGameRoom(); showToast('返回', '已返回房間', 'success'); } catch (error) { console.error('Back to room error:', error); showToast('錯誤', '返回房間失敗,請重試', 'error'); } } async function leaveRoom() { if (!confirm('確定要離開房間嗎?')) { return; } try { if (gameState.roomId && gameState.playerName) { await db.ref('rooms/' + gameState.roomId + '/players/' + gameState.playerName).remove(); if (gameState.isHost) { const playersSnapshot = await db.ref('rooms/' + gameState.roomId + '/players').once('value'); const players = playersSnapshot.val() || {}; if (Object.keys(players).length === 0) { await db.ref('rooms/' + gameState.roomId).remove(); } } } gameState = { currentScreen: 'main', roomId: null, isHost: false, playerName: '', selectedAnimal: null, isReady: false, players: {}, raceActive: false, raceResults: null, animals: gameState.animals }; showScreen('mainScreen'); showToast('離開', '已離開房間', 'success'); } catch (error) { console.error('Leave room error:', error); showToast('錯誤', '離開房間失敗,請重試', 'error'); } } // Event Listeners document.addEventListener('DOMContentLoaded', function() { document.getElementById('createRoomBtn').addEventListener('click', createRoom); document.getElementById('joinRoomBtn').addEventListener('click', function() { showScreen('joinScreen'); }); document.getElementById('confirmJoinBtn').addEventListener('click', joinRoom); document.getElementById('backFromJoinBtn').addEventListener('click', function() { showScreen('mainScreen'); }); document.getElementById('readyBtn').addEventListener('click', toggleReady); document.getElementById('startGameBtn').addEventListener('click', startGame); document.getElementById('leaveRoomBtn').addEventListener('click', leaveRoom); document.getElementById('backToRoomBtn').addEventListener('click', backToRoom); });