Files
science-bowl-practice/player.js

123 lines
4.1 KiB
JavaScript

// Get player ID from URL
const urlParams = new URLSearchParams(window.location.search);
const playerId = urlParams.get('id') || '1';
const playerColors = ['#ff4444', '#4444ff', '#44ff44', '#ffff44'];
const playerNames = ['Player 1', 'Player 2', 'Player 3', 'Player 4'];
// Buzzer sound frequencies (different for each player)
const buzzerFrequencies = [523.25, 659.25, 783.99, 880.00]; // C5, E5, G5, A5
// DOM elements
const playerName = document.getElementById('playerName');
const playerScore = document.getElementById('playerScore');
const statusMessage = document.getElementById('statusMessage');
const buzzer = document.getElementById('buzzer');
const questionDisplay = document.getElementById('questionDisplay');
// Set player identity
playerName.textContent = playerNames[playerId - 1];
playerName.style.color = playerColors[playerId - 1];
document.body.style.setProperty('--player-color', playerColors[playerId - 1]);
// Game state
let canBuzz = false;
let hasBuzzed = false;
// Audio context for buzzer sounds
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
function playBuzzerSound(playerNum) {
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.frequency.value = buzzerFrequencies[playerNum - 1];
oscillator.type = 'sine';
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.3);
}
// Listen to game state
database.ref('gameState').on('value', (snapshot) => {
const state = snapshot.val();
if (!state) return;
// Update score
if (state.scores && state.scores[`player${playerId}`] !== undefined) {
playerScore.textContent = state.scores[`player${playerId}`];
}
// Show question status
if (state.isReading) {
questionDisplay.textContent = '🔊 Listen to the question...';
questionDisplay.style.display = 'block';
} else if (state.currentQuestion) {
questionDisplay.textContent = 'Question loaded. Waiting for moderator to read...';
questionDisplay.style.display = 'block';
} else {
questionDisplay.style.display = 'none';
}
// Update buzzer state
if (state.buzzerActive) {
canBuzz = true;
hasBuzzed = false;
buzzer.disabled = false;
buzzer.classList.remove('locked');
statusMessage.textContent = 'Ready to buzz!';
} else {
canBuzz = false;
buzzer.disabled = true;
buzzer.classList.add('locked');
}
// Check if this player buzzed in
if (state.buzzer && state.buzzer.playerId === `player${playerId}`) {
statusMessage.textContent = '🎯 You buzzed in! Answer verbally to the moderator.';
buzzer.classList.add('locked');
} else if (state.buzzer && state.buzzer.playerId) {
const buzzedPlayerNum = state.buzzer.playerId.replace('player', '');
statusMessage.textContent = `Player ${buzzedPlayerNum} buzzed in`;
buzzer.classList.add('locked');
}
});
// Listen for buzzer events to play sounds
database.ref('gameState/buzzer').on('value', (snapshot) => {
const buzzer = snapshot.val();
if (buzzer && buzzer.playerId) {
const playerNum = parseInt(buzzer.playerId.replace('player', ''));
playBuzzerSound(playerNum);
}
});
// Buzzer click
buzzer.addEventListener('click', buzzIn);
// Spacebar to buzz
document.addEventListener('keydown', (e) => {
if (e.code === 'Space' && canBuzz && !hasBuzzed) {
e.preventDefault();
buzzIn();
}
});
function buzzIn() {
if (!canBuzz || hasBuzzed) return;
hasBuzzed = true;
database.ref('gameState/buzzer').set({
playerId: `player${playerId}`,
timestamp: Date.now()
});
// Visual feedback
buzzer.classList.add('buzzed');
setTimeout(() => buzzer.classList.remove('buzzed'), 300);
}