dcrey7 commited on
Commit
5a77811
·
verified ·
1 Parent(s): e66223c

Update static/js/game.js

Browse files
Files changed (1) hide show
  1. static/js/game.js +148 -326
static/js/game.js CHANGED
@@ -1,326 +1,148 @@
1
- // Initialize Socket.IO connection with automatic reconnection
2
- const socket = io({
3
- reconnection: true,
4
- reconnectionAttempts: 5,
5
- reconnectionDelay: 1000
6
- });
7
-
8
- class Game {
9
- constructor() {
10
- // Core game state
11
- this.state = {
12
- gameId: null,
13
- currentPhase: 'landing',
14
- playerId: null,
15
- players: [],
16
- currentQuestion: null,
17
- isRecording: false,
18
- recordingTime: 30, // seconds
19
- listeningTime: 60, // seconds
20
- votingTime: 60, // seconds
21
- recordings: new Map(),
22
- votes: new Map(),
23
- impostor: null
24
- };
25
-
26
- // Audio recording configuration
27
- this.audioConfig = {
28
- mediaRecorder: null,
29
- audioChunks: [],
30
- stream: null
31
- };
32
-
33
- // Initialize the game
34
- this.initializeEventListeners();
35
- this.bindUIElements();
36
- }
37
-
38
- // Initialize all event listeners for the game
39
- initializeEventListeners() {
40
- // Socket event listeners
41
- socket.on('connect', () => this.handleConnection());
42
- socket.on('game_created', (data) => this.handleGameCreated(data));
43
- socket.on('player_joined', (data) => this.handlePlayerJoined(data));
44
- socket.on('round_start', (data) => this.handleRoundStart(data));
45
- socket.on('round_result', (data) => this.handleRoundResult(data));
46
-
47
- // UI event listeners
48
- document.getElementById('start-button')?.addEventListener('click', () => this.startGame());
49
- document.getElementById('add-player-button')?.addEventListener('click', () => this.addPlayer());
50
- }
51
-
52
- // Bind UI elements and initialize their event handlers
53
- bindUIElements() {
54
- // Bind all necessary UI elements
55
- const uiElements = {
56
- gameContainer: document.getElementById('game-container'),
57
- landingPage: document.getElementById('landing-page'),
58
- setupPage: document.getElementById('setup-page'),
59
- gamePage: document.getElementById('game-page'),
60
- questionDisplay: document.getElementById('question-display'),
61
- timerDisplay: document.getElementById('timer-display'),
62
- recordButton: document.getElementById('record-button'),
63
- playerList: document.getElementById('player-list'),
64
- voteButtons: document.querySelectorAll('.vote-button')
65
- };
66
-
67
- // Store UI elements in the class
68
- this.ui = uiElements;
69
- }
70
-
71
- // Handle initial connection to the server
72
- handleConnection() {
73
- console.log('Connected to server');
74
- this.showPage('landing');
75
- }
76
-
77
- // Create a new game session
78
- async createGame() {
79
- try {
80
- socket.emit('create_game');
81
- } catch (error) {
82
- this.handleError('Failed to create game');
83
- }
84
- }
85
-
86
- // Handle successful game creation
87
- handleGameCreated(data) {
88
- this.state.gameId = data.gameId;
89
- this.showPage('setup');
90
- }
91
-
92
- // Add a new player to the game
93
- async addPlayer() {
94
- if (this.state.players.length >= 5) {
95
- this.handleError('Maximum player limit reached');
96
- return;
97
- }
98
-
99
- const playerName = prompt('Enter player name:');
100
- if (!playerName) return;
101
-
102
- socket.emit('join_game', {
103
- gameId: this.state.gameId,
104
- playerName: playerName
105
- });
106
- }
107
-
108
- // Handle new player joining the game
109
- handlePlayerJoined(data) {
110
- this.state.players.push({
111
- id: data.playerId,
112
- name: data.playerName
113
- });
114
- this.updatePlayerList();
115
- }
116
-
117
- // Update the player list in the UI
118
- updatePlayerList() {
119
- if (!this.ui.playerList) return;
120
-
121
- this.ui.playerList.innerHTML = '';
122
- this.state.players.forEach(player => {
123
- const playerElement = document.createElement('div');
124
- playerElement.className = 'player-avatar';
125
- playerElement.textContent = player.id;
126
- this.ui.playerList.appendChild(playerElement);
127
- });
128
- }
129
-
130
- // Start the game
131
- async startGame() {
132
- if (this.state.players.length < 3) {
133
- this.handleError('Need at least 3 players to start');
134
- return;
135
- }
136
-
137
- try {
138
- const response = await fetch('/api/start_game', {
139
- method: 'POST',
140
- headers: {
141
- 'Content-Type': 'application/json'
142
- },
143
- body: JSON.stringify({
144
- gameId: this.state.gameId
145
- })
146
- });
147
-
148
- const data = await response.json();
149
- if (data.status === 'success') {
150
- this.handleRoundStart(data);
151
- }
152
- } catch (error) {
153
- this.handleError('Failed to start game');
154
- }
155
- }
156
-
157
- // Handle the start of a new round
158
- handleRoundStart(data) {
159
- this.state.currentQuestion = data.question;
160
- this.state.currentPhase = 'recording';
161
- this.showPage('game');
162
- this.updateQuestionDisplay();
163
- this.startTimer(this.state.recordingTime, () => this.endRecordingPhase());
164
- }
165
-
166
- // Start audio recording
167
- async startRecording() {
168
- try {
169
- this.audioConfig.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
170
- this.audioConfig.mediaRecorder = new MediaRecorder(this.audioConfig.stream);
171
- this.audioConfig.audioChunks = [];
172
-
173
- this.audioConfig.mediaRecorder.ondataavailable = (event) => {
174
- this.audioConfig.audioChunks.push(event.data);
175
- };
176
-
177
- this.audioConfig.mediaRecorder.onstop = () => {
178
- this.submitRecording();
179
- };
180
-
181
- this.audioConfig.mediaRecorder.start();
182
- this.state.isRecording = true;
183
- this.updateRecordButton();
184
- } catch (error) {
185
- this.handleError('Failed to start recording');
186
- }
187
- }
188
-
189
- // Stop audio recording
190
- stopRecording() {
191
- if (this.audioConfig.mediaRecorder && this.state.isRecording) {
192
- this.audioConfig.mediaRecorder.stop();
193
- this.audioConfig.stream.getTracks().forEach(track => track.stop());
194
- this.state.isRecording = false;
195
- this.updateRecordButton();
196
- }
197
- }
198
-
199
- // Submit recording to server
200
- async submitRecording() {
201
- const audioBlob = new Blob(this.audioConfig.audioChunks, { type: 'audio/wav' });
202
- const formData = new FormData();
203
- formData.append('audio', audioBlob);
204
- formData.append('gameId', this.state.gameId);
205
- formData.append('playerId', this.state.playerId);
206
-
207
- try {
208
- const response = await fetch('/api/submit_recording', {
209
- method: 'POST',
210
- body: formData
211
- });
212
-
213
- const data = await response.json();
214
- if (data.status === 'success') {
215
- this.state.recordings.set(this.state.playerId, data.recordingUrl);
216
- }
217
- } catch (error) {
218
- this.handleError('Failed to submit recording');
219
- }
220
- }
221
-
222
- // Start the timer for a game phase
223
- startTimer(duration, callback) {
224
- let timeLeft = duration;
225
- this.updateTimerDisplay(timeLeft);
226
-
227
- this.timer = setInterval(() => {
228
- timeLeft--;
229
- this.updateTimerDisplay(timeLeft);
230
-
231
- if (timeLeft <= 0) {
232
- clearInterval(this.timer);
233
- if (callback) callback();
234
- }
235
- }, 1000);
236
- }
237
-
238
- // Update the timer display
239
- updateTimerDisplay(timeLeft) {
240
- if (this.ui.timerDisplay) {
241
- const minutes = Math.floor(timeLeft / 60);
242
- const seconds = timeLeft % 60;
243
- this.ui.timerDisplay.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;
244
- }
245
- }
246
-
247
- // End the recording phase and move to listening phase
248
- endRecordingPhase() {
249
- if (this.state.isRecording) {
250
- this.stopRecording();
251
- }
252
- this.state.currentPhase = 'listening';
253
- this.startListeningPhase();
254
- }
255
-
256
- // Start the listening phase
257
- startListeningPhase() {
258
- this.showPage('listening');
259
- this.loadRecordings();
260
- this.startTimer(this.state.listeningTime, () => this.startVotingPhase());
261
- }
262
-
263
- // Load all player recordings
264
- async loadRecordings() {
265
- // Implementation for loading and playing recordings
266
- // This would integrate with the audio playback UI
267
- }
268
-
269
- // Start the voting phase
270
- startVotingPhase() {
271
- this.state.currentPhase = 'voting';
272
- this.showPage('voting');
273
- this.startTimer(this.state.votingTime, () => this.endVotingPhase());
274
- }
275
-
276
- // Submit a vote
277
- submitVote(votedPlayerId) {
278
- socket.emit('submit_vote', {
279
- gameId: this.state.gameId,
280
- voterId: this.state.playerId,
281
- votedPlayerId: votedPlayerId
282
- });
283
- }
284
-
285
- // Handle the round results
286
- handleRoundResult(data) {
287
- this.showResults(data);
288
- // Trigger dramatic background effect
289
- window.gameBackground?.addDramaticEffect('impostor_reveal');
290
- }
291
-
292
- // Show the results page
293
- showResults(data) {
294
- this.showPage('results');
295
- // Implementation for displaying round results
296
- }
297
-
298
- // Switch between game pages
299
- showPage(pageName) {
300
- const pages = document.querySelectorAll('.game-page');
301
- pages.forEach(page => {
302
- page.classList.remove('active');
303
- if (page.id === `${pageName}-page`) {
304
- page.classList.add('active');
305
- }
306
- });
307
- }
308
-
309
- // Handle errors
310
- handleError(message) {
311
- const errorElement = document.createElement('div');
312
- errorElement.className = 'error-message';
313
- errorElement.textContent = message;
314
- this.ui.gameContainer.appendChild(errorElement);
315
- setTimeout(() => errorElement.remove(), 3000);
316
- }
317
- }
318
-
319
- // Initialize the game when the DOM is loaded
320
- document.addEventListener('DOMContentLoaded', () => {
321
- const game = new Game();
322
- // Expose game instance for debugging
323
- window.game = game;
324
- });
325
-
326
- export default Game;
 
1
+ // Initialize Socket.IO connection with automatic reconnection
2
+ const socket = io({
3
+ reconnection: true,
4
+ reconnectionAttempts: 5,
5
+ reconnectionDelay: 1000
6
+ });
7
+
8
+ class Game {
9
+ constructor() {
10
+ // Core game state
11
+ this.state = {
12
+ gameId: null,
13
+ currentPhase: 'landing',
14
+ playerId: null,
15
+ players: [],
16
+ currentQuestion: null,
17
+ isRecording: false,
18
+ recordingTime: 30,
19
+ listeningTime: 60,
20
+ votingTime: 60,
21
+ recordings: new Map(),
22
+ votes: new Map(),
23
+ impostor: null
24
+ };
25
+
26
+ // Wait for DOM to be fully loaded before initializing
27
+ if (document.readyState === 'loading') {
28
+ document.addEventListener('DOMContentLoaded', () => this.initialize());
29
+ } else {
30
+ this.initialize();
31
+ }
32
+ }
33
+
34
+ initialize() {
35
+ // Initialize event listeners and UI bindings
36
+ this.initializeEventListeners();
37
+ this.bindUIElements();
38
+
39
+ // Initialize Socket.IO event handlers
40
+ this.initializeSocketHandlers();
41
+
42
+ // Show the landing page
43
+ this.showPage('landing');
44
+ }
45
+
46
+ initializeEventListeners() {
47
+ // Handle play button click
48
+ const playButton = document.getElementById('play-button');
49
+ if (playButton) {
50
+ playButton.addEventListener('click', () => {
51
+ console.log('Play button clicked'); // Debug log
52
+ this.handlePlayButton();
53
+ });
54
+ }
55
+
56
+ // Other button handlers
57
+ document.getElementById('start-button')?.addEventListener('click', () => this.startGame());
58
+ document.getElementById('add-player-button')?.addEventListener('click', () => this.addPlayer());
59
+ }
60
+
61
+ bindUIElements() {
62
+ // Cache frequently used elements
63
+ this.ui = {
64
+ gameContainer: document.getElementById('game-container'),
65
+ pages: {
66
+ landing: document.getElementById('landing-page'),
67
+ setup: document.getElementById('setup-page'),
68
+ game: document.getElementById('game-page'),
69
+ recording: document.getElementById('recording-page'),
70
+ listening: document.getElementById('listening-page'),
71
+ voting: document.getElementById('voting-page'),
72
+ results: document.getElementById('results-page')
73
+ },
74
+ buttons: {
75
+ play: document.getElementById('play-button'),
76
+ start: document.getElementById('start-button'),
77
+ addPlayer: document.getElementById('add-player-button'),
78
+ record: document.getElementById('record-button')
79
+ }
80
+ };
81
+ }
82
+
83
+ initializeSocketHandlers() {
84
+ socket.on('connect', () => {
85
+ console.log('Connected to server');
86
+ });
87
+
88
+ socket.on('game_created', (data) => {
89
+ this.handleGameCreated(data);
90
+ });
91
+
92
+ socket.on('player_joined', (data) => {
93
+ this.handlePlayerJoined(data);
94
+ });
95
+ }
96
+
97
+ async handlePlayButton() {
98
+ console.log('Handling play button click'); // Debug log
99
+ try {
100
+ // Create new game session
101
+ await this.createGame();
102
+ // Show the setup page
103
+ this.showPage('setup');
104
+ } catch (error) {
105
+ console.error('Error starting game:', error);
106
+ this.handleError('Failed to start game');
107
+ }
108
+ }
109
+
110
+ async createGame() {
111
+ try {
112
+ socket.emit('create_game');
113
+ } catch (error) {
114
+ console.error('Error creating game:', error);
115
+ throw new Error('Failed to create game');
116
+ }
117
+ }
118
+
119
+ handleGameCreated(data) {
120
+ console.log('Game created:', data); // Debug log
121
+ this.state.gameId = data.gameId;
122
+ }
123
+
124
+ showPage(pageName) {
125
+ console.log('Showing page:', pageName); // Debug log
126
+
127
+ // Hide all pages
128
+ Object.values(this.ui.pages).forEach(page => {
129
+ if (page) {
130
+ page.classList.remove('active');
131
+ }
132
+ });
133
+
134
+ // Show requested page
135
+ const pageToShow = this.ui.pages[pageName];
136
+ if (pageToShow) {
137
+ pageToShow.classList.add('active');
138
+ this.state.currentPhase = pageName;
139
+ }
140
+ }
141
+
142
+ // Rest of the Game class implementation remains the same...
143
+ }
144
+
145
+ // Initialize the game when the DOM is loaded
146
+ document.addEventListener('DOMContentLoaded', () => {
147
+ window.game = new Game();
148
+ });