39
39
ball_radius = 20
40
40
ball_color = WHITE
41
41
ball_pos = [WIDTH // 2 , HEIGHT // 2 ]
42
- ball_speed = 40
42
+ ball_speed = 30
43
43
44
44
# Player properties
45
45
player_width = 10
46
46
player_height = 100
47
47
player1_pos = [50 , HEIGHT // 2 - player_height // 2 ]
48
48
player2_pos = [WIDTH - 50 - player_width , HEIGHT // 2 - player_height // 2 ]
49
49
50
+ # Font settings
51
+ font_size = 50
52
+ font = pygame .font .Font (None , font_size )
53
+ title_text = "Force Ball Game"
54
+
55
+ title_surface = font .render (title_text , True , WHITE )
56
+ title_rect = title_surface .get_rect (center = (800 // 2 , font_size )) # Center at the top middle
57
+
50
58
clock = pygame .time .Clock ()
51
59
52
60
eeg_queue = queue .Queue () # Initialize EEG queue
56
64
game_started = False
57
65
first_attempt = True # Keeps track if it's the first game or a restart
58
66
67
+ powerData1 = []
68
+ powerData2 = []
69
+
59
70
def bandpower (data , sf , band , window_sec = None , relative = False ):
60
71
band = np .asarray (band )
61
72
low , high = band
@@ -75,22 +86,17 @@ def bandpower(data, sf, band, window_sec=None, relative=False):
75
86
return bp
76
87
77
88
def eeg_data_thread (eeg_queue ):
89
+ global powerData1 , powerData2
78
90
streams = resolve_stream ('name' , 'BioAmpDataStream' )
79
91
if not streams :
80
92
print ("No LSL stream found!" )
81
93
return
82
94
83
95
inlet = StreamInlet (streams [0 ])
84
- channel_assignments = {0 : 'Player A' , 1 : 'Player B' }
85
- sampling_frequency = 250
86
- bands = {
87
- 'Delta' : [0.5 , 4 ],
88
- 'Theta' : [4 , 8 ],
89
- 'Alpha' : [8 , 13 ],
90
- 'Beta' : [13 , 30 ],
91
- 'Gamma' : [30 , 40 ]
92
- }
93
- buffer_length = sampling_frequency * 4
96
+ channel_assignments = {0 :'Player A' , 1 :'Player B' }
97
+ sampling_frequency = 500
98
+ bands = {'Alpha' : [8 , 13 ],'Beta' : [13 , 30 ]}
99
+ buffer_length = sampling_frequency * 1
94
100
data_buffer = {'Channel1' : [], 'Channel2' : []}
95
101
powerData1 = []
96
102
powerData2 = []
@@ -100,6 +106,9 @@ def eeg_data_thread(eeg_queue):
100
106
baseline1 = baseline2 = 1 # Initialize baselines
101
107
102
108
while running :
109
+ if paused :
110
+ time .sleep (0.1 ) # Pause the thread when the game is paused
111
+ continue
103
112
try :
104
113
sample , timestamp = inlet .pull_sample ()
105
114
if len (sample ) >= 6 :
@@ -118,12 +127,8 @@ def eeg_data_thread(eeg_queue):
118
127
if len (data_buffer ['Channel1' ]) >= buffer_length :
119
128
power_data = {'Channel1' : {}, 'Channel2' : {}}
120
129
for band_name , band_freqs in bands .items ():
121
- power_data ['Channel1' ][band_name ] = bandpower (
122
- np .array (data_buffer ['Channel1' ]), sampling_frequency , band_freqs
123
- )
124
- power_data ['Channel2' ][band_name ] = bandpower (
125
- np .array (data_buffer ['Channel2' ]), sampling_frequency , band_freqs
126
- )
130
+ power_data ['Channel1' ][band_name ] = bandpower (np .array (data_buffer ['Channel1' ]), sampling_frequency , band_freqs )
131
+ power_data ['Channel2' ][band_name ] = bandpower (np .array (data_buffer ['Channel2' ]), sampling_frequency , band_freqs )
127
132
128
133
powerData1 .append (power_data ['Channel1' ]['Beta' ] / power_data ['Channel1' ]['Alpha' ])
129
134
powerData2 .append (power_data ['Channel2' ]['Beta' ] / power_data ['Channel2' ]['Alpha' ])
@@ -156,40 +161,44 @@ def eeg_data_thread(eeg_queue):
156
161
eeg_thread .start ()
157
162
158
163
def reset_game ():
159
- global ball_pos , force_player1 , force_player2 , paused , game_started
164
+ global ball_pos , force_player1 , force_player2 , paused , game_started , win_text , win_handled , restart_clicked , powerData1 , powerData2
160
165
ball_pos = [WIDTH // 2 , HEIGHT // 2 ]
161
166
force_player1 = force_player2 = 0
167
+ powerData1 .clear () # Clear force data for player 1
168
+ powerData2 .clear () # Clear force data for player 2
162
169
paused = False # Ensure the game is not paused after reset
163
170
game_started = True # Ensure the game is marked as started
171
+ win_text = None # Reset win text
172
+ win_handled = False # Reset win handling
173
+ restart_clicked = True # Mark the restart button as clicked
164
174
165
175
# Clear any buffered EEG data
166
176
while not eeg_queue .empty ():
167
177
eeg_queue .get ()
168
- print ("Empty" )
178
+ print ("Game Reset Successfully." )
179
+
180
+ def update_ball_position (force_player1 , force_player2 , threshold = 0.7 ):
181
+ global ball_pos , powerData1 , powerData2
169
182
170
- def update_ball_position (force_player1 , force_player2 ):
171
- global ball_pos
172
- net_force = force_player2 - force_player1 # force direction
173
- ball_pos [0 ] += net_force * ball_speed * 0.01
183
+ # Apply moving average
184
+ average_force1 = np .mean (powerData1 [- 10 :]) if len (powerData1 ) >= 10 else 0
185
+ average_force2 = np .mean (powerData2 [- 10 :]) if len (powerData2 ) >= 10 else 0
186
+
187
+ net_force = average_force1 - average_force2
188
+
189
+ # Apply the threshold
190
+ if abs (net_force ) > threshold :
191
+ ball_pos [0 ] += net_force * ball_speed * 0.01
174
192
if ball_pos [0 ] < ball_radius :
175
193
ball_pos [0 ] = ball_radius
176
194
elif ball_pos [0 ] > WIDTH - ball_radius :
177
195
ball_pos [0 ] = WIDTH - ball_radius
178
196
179
- print (f"Force Player 1: { force_player1 :.2f} , Force Player 2: { force_player2 :.2f} , Net Force: { net_force :.2f} " ) # Print the forces to the console
180
-
181
- def handle_input ():
182
- global force_player1 , force_player2
183
- keys = pygame .key .get_pressed ()
184
-
185
- if keys [pygame .K_LEFT ]:
186
- force_player1 += 0.25
187
- if keys [pygame .K_RIGHT ]:
188
- force_player2 += 0.25
197
+ print (f"Force Player 1: { average_force1 :.2f} , Force Player 2: { average_force2 :.2f} , Net Force: { net_force :.2f} " )
189
198
190
199
def draw_buttons (paused , first_attempt ): # Button dimensions and positions
191
- button_width = 120
192
- button_height = 40
200
+ button_width = 140
201
+ button_height = 50
193
202
button_radius = 15 # Radius for rounded corners
194
203
195
204
# Button positions (y-position is moved up slightly for a better fit)
@@ -235,52 +244,53 @@ def draw_players():
235
244
236
245
def check_win_condition ():
237
246
if ball_pos [0 ] <= ball_radius :
238
- return "PLAYER A WINS!"
239
- elif ball_pos [0 ] >= WIDTH - ball_radius :
240
247
return "PLAYER B WINS!"
248
+ elif ball_pos [0 ] >= WIDTH - ball_radius :
249
+ return "PLAYER A WINS!"
241
250
return None
242
251
243
252
def main ():
244
253
global paused , game_started , first_attempt
245
254
force_player1 = force_player2 = 0
246
255
win_text = None # Initialize win text
247
256
latest_data = (0 , 0 ) # To store the latest EEG data for both players
257
+ win_handled = False # Track if win actions are handled
248
258
249
259
while True :
250
260
screen .fill (BLACK )
261
+ screen .blit (title_surface , title_rect ) # For Title of the game
251
262
252
- pygame .draw .circle (screen , ball_color , (int (ball_pos [0 ]), int (ball_pos [1 ])), ball_radius ) # Draw the ball
263
+ pygame .draw .circle (screen , ball_color , (int (ball_pos [0 ]), int (ball_pos [1 ])), ball_radius ) # Draw the ball
253
264
254
265
for event in pygame .event .get ():
255
266
if event .type == pygame .QUIT :
256
267
pygame .quit ()
257
268
sys .exit ()
258
269
259
- if event .type == pygame .KEYDOWN :
260
- if event .key == pygame .K_ESCAPE :
261
- pygame .quit ()
262
- sys .exit ()
263
-
264
270
if event .type == pygame .MOUSEBUTTONDOWN :
265
271
mouse_pos = pygame .mouse .get_pos ()
266
272
if event .button == 1 : # Left mouse button
267
273
# Check if the mouse click is within the bounds of any button
268
274
if pygame .Rect (WIDTH // 4 - 60 , HEIGHT - 80 , 120 , 40 ).collidepoint (mouse_pos ):
269
275
# Start or restart the game
270
276
reset_game ()
277
+ time .sleep (1 )
271
278
game_started = True
272
279
first_attempt = False
273
- win_text = None # Reset win text on new game
280
+ win_text = None
281
+ win_handled = False # Reset win handling
282
+ paused = False # Ensure the game is unpaused
283
+ print ("Game Restarted." )
274
284
elif pygame .Rect (WIDTH // 2 - 60 , HEIGHT - 80 , 120 , 40 ).collidepoint (mouse_pos ):
275
285
# Pause/Resume the game
276
286
paused = not paused
287
+ print ("Game Paused!" if paused else "Game Resumed!" )
277
288
elif pygame .Rect (3 * WIDTH // 4 - 60 , HEIGHT - 80 , 120 , 40 ).collidepoint (mouse_pos ):
278
289
pygame .quit ()
279
290
sys .exit ()
280
291
281
292
if game_started :
282
293
if not paused :
283
- handle_input ()
284
294
if not eeg_queue .empty ():
285
295
force_player1 , force_player2 = eeg_queue .get ()
286
296
latest_data = (force_player1 , force_player2 ) # Store latest data
@@ -295,11 +305,10 @@ def main():
295
305
if game_started :
296
306
win_text = check_win_condition ()
297
307
if win_text :
298
- win_sound .play () # Play sound on win
299
- paused = True # Automatically pause the game on win
300
- while not eeg_queue .empty ():
301
- eeg_queue .get ()
302
- force_player1 , force_player2 = latest_data # Store the latest data when the game is won
308
+ if not win_handled : # Ensure win actions execute only once
309
+ win_sound .play () # Play sound on win
310
+ paused = True # Automatically pause the game on win
311
+ win_handled = True # Mark win actions as handled
303
312
304
313
# Draw win text if there is a winner
305
314
if win_text :
@@ -310,4 +319,10 @@ def main():
310
319
clock .tick (60 ) # 60 frames per second
311
320
312
321
if __name__ == "__main__" :
313
- main ()
322
+ main ()
323
+
324
+ # Threshold = 0.7
325
+ # Moving Average of last 10 values of powerData.
326
+ # Ball Speed = 30
327
+ # Adding the font title "Force Ball Game"
328
+ # Sleep of 1 sec so that game reset properly
0 commit comments