Make guessing phase while hearing
All checks were successful
Publish Docker image / Push Docker image to Docker Hub (push) Successful in 1m55s

This commit is contained in:
2025-03-01 15:57:31 +01:00
parent 33a1715adc
commit 2fb5af4171
4 changed files with 78 additions and 11 deletions

View File

@ -149,6 +149,10 @@ export const Game = () => {
return prevMsg; return prevMsg;
})); }));
}, },
"song-options": (data) => {
console.log("Received song options early:", data);
setSongOptions(data.songOptions || []);
},
}; };
const cleanupFunctions = Object.entries(eventHandlers).map( const cleanupFunctions = Object.entries(eventHandlers).map(
@ -320,11 +324,38 @@ export const Game = () => {
)} )}
{role === "guesser" && ( {role === "guesser" && (
<div className="guessing-display">
<div className="listening-display"> <div className="listening-display">
<div className="listening-icon"> <div className="listening-icon">
<FontAwesomeIcon icon={faHeadphones} size="4x" /> <FontAwesomeIcon icon={faHeadphones} size="4x" />
</div> </div>
<p className="instruction">Höre genau zu und versuche, den Song zu erkennen!</p> <p className="instruction">Listen carefully and think about which song it might be!</p>
</div>
{songOptions.length > 0 && (
<div className="song-grid early-preview">
{songOptions.map(song => (
<div
key={song.id}
className={`song-option ${selectedSong?.id === song.id ? 'selected' : ''}`}
onClick={() => handleSongSelect(song)}
>
<div className="song-image">
<img src={song.coverUrl} alt={song.title} />
{selectedSong?.id === song.id && (
<div className="selection-indicator">
<FontAwesomeIcon icon={faCheckCircle} />
</div>
)}
</div>
<div className="song-details">
<div className="song-title">{song.title}</div>
<div className="song-artist">{song.artist}</div>
</div>
</div>
))}
</div>
)}
</div> </div>
)} )}
</div> </div>
@ -334,8 +365,8 @@ export const Game = () => {
return ( return (
<div className="guessing-phase"> <div className="guessing-phase">
<div className="phase-header"> <div className="phase-header">
<h3>Runde {round}: Song erraten</h3> <h3>Final Answer Time!</h3>
<div className="timer"> <div className="timer urgent">
<FontAwesomeIcon icon={faClock} /> {timeLeft}s <FontAwesomeIcon icon={faClock} /> {timeLeft}s
</div> </div>
</div> </div>

View File

@ -597,6 +597,26 @@
opacity: 0.8 opacity: 0.8
animation: pulse 1.5s infinite ease-in-out animation: pulse 1.5s infinite ease-in-out
.guessing-display
display: flex
flex-direction: column
gap: 20px
margin-top: 20px
.early-preview
opacity: 0.8
transition: opacity 0.3s ease
&:hover
opacity: 1
.song-grid
margin-top: 10px
.timer.urgent
animation: urgent-pulse 1s infinite
background: rgba(255, 100, 100, 0.2)
@keyframes subtle-text-glow @keyframes subtle-text-glow
0%, 100% 0%, 100%
text-shadow: 0 0 10px rgba(255, 255, 255, 0.4) text-shadow: 0 0 10px rgba(255, 255, 255, 0.4)
@ -1046,3 +1066,11 @@
50% 50%
transform: scale(1.1) transform: scale(1.1)
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.5), 0 0 30px rgba(255, 255, 0, 0.6) box-shadow: 0 5px 20px rgba(0, 0, 0, 0.5), 0 0 30px rgba(255, 255, 0, 0.6)
@keyframes urgent-pulse
0%, 100%
transform: scale(1)
background: rgba(255, 100, 100, 0.2)
50%
transform: scale(1.05)
background: rgba(255, 100, 100, 0.3)

View File

@ -26,7 +26,7 @@ const initializeGameState = (roomId) => {
roundStartTime: null, roundStartTime: null,
phaseTimeLimit: { phaseTimeLimit: {
composing: 30, composing: 30,
guessing: 30 guessing: 10
}, },
lastFrequency: 440, lastFrequency: 440,
}; };
@ -55,11 +55,14 @@ const startNewRound = async (roomId) => {
gameState.currentComposer = determineNextComposer(roomId, gameState, users); gameState.currentComposer = determineNextComposer(roomId, gameState, users);
const success = await selectSongAndOptions(gameState);
if (!success) return false;
users.forEach(user => { users.forEach(user => {
gameState.roles[user.id] = user.id === gameState.currentComposer ? 'composer' : 'guesser'; gameState.roles[user.id] = user.id === gameState.currentComposer ? 'composer' : 'guesser';
}); });
return await selectSongAndOptions(gameState); return true;
}; };
const determineNextComposer = (roomId, gameState, users) => { const determineNextComposer = (roomId, gameState, users) => {

View File

@ -55,18 +55,22 @@ module.exports = (io) => (socket) => {
const roles = gameController.getRoles(roomId); const roles = gameController.getRoles(roomId);
const selectedSong = gameController.getSelectedSong(roomId); const selectedSong = gameController.getSelectedSong(roomId);
const timeLeft = gameController.getTimeRemaining(roomId); const timeLeft = gameController.getTimeRemaining(roomId);
const songOptions = gameController.getSongOptions(roomId);
io.to(roomId).emit('roles-assigned', roles); io.to(roomId).emit('roles-assigned', roles);
Object.entries(roles).forEach(([userId, role]) => { Object.entries(roles).forEach(([userId, role]) => {
if (role === 'composer') { if (role === 'composer') {
io.to(userId).emit('song-selected', selectedSong); io.to(userId).emit('song-selected', selectedSong);
} else {
io.to(userId).emit('song-options', { songOptions });
} }
}); });
io.to(roomId).emit('round-started', { io.to(roomId).emit('round-started', {
round: gameController.getRoundResults(roomId).round, round: gameController.getRoundResults(roomId).round,
timeRemaining: timeLeft timeRemaining: timeLeft,
phase: 'composing'
}); });
startPhaseTimer(roomId); startPhaseTimer(roomId);
@ -84,7 +88,8 @@ module.exports = (io) => (socket) => {
io.to(roomId).emit('phase-changed', { io.to(roomId).emit('phase-changed', {
phase: 'guessing', phase: 'guessing',
timeRemaining: timeLeft timeRemaining: timeLeft,
message: 'Time to submit your final answer!'
}); });
Object.entries(roles).forEach(([userId, role]) => { Object.entries(roles).forEach(([userId, role]) => {