I am trying to create a reaction time test game in python using pygame for gui. Since, I am fairly new to the technology, I am stuck at a portion of the code as how to register further keypresses and then record time accordingly.
This is my code till now:
import pygame
from datetime import datetime
import time
import random
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Reaction Time Test")
font = pygame.font.SysFont(None, 30)
text = font.render("PRESS ANY KEY TO START TEST", 0, (255,255,255))
w = font.render("PRESS ANY KEY",0,(0,255,0))
count = 0
screen.blit(text, (150,240))
running = True
while running:
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.quit()
if count <= 5 and event.type == pygame.KEYDOWN:
screen.fill(pygame.Color("black"))
pygame.display.flip()
wait_time = random.randint(1,4)
time.sleep(wait_time)
reaction_start = datetime.now()
print(reaction_start)
screen.blit(w,(225,200))
count = count + 1
if event.type == pygame.KEYDOWN:
reaction_end = datetime.now()
print(reaction_end)
t = reaction_end - reaction_start
print(t)
f = font.render("REACTION TIME: "+ str(t),0,(255,255,255))
screen.blit(f,(225,300))
if count > 5:
screen.fill(pygame.Color("black"))
pygame.display.flip()
s = font.render("AVERAGE REACTION TIME IS: ",0,(255,255,255))
screen.blit(s,(150,200))
pygame.display.flip()
The part where I am stuck at it is this code snippet
if count <= 5 and event.type == pygame.KEYDOWN:
screen.fill(pygame.Color("black"))
pygame.display.flip()
wait_time = random.randint(1,4)
time.sleep(wait_time)
reaction_start = datetime.now()
print(reaction_start)
screen.blit(w,(225,200))
count = count + 1
if event.type == pygame.KEYDOWN:
reaction_end = datetime.now()
print(reaction_end)
t = reaction_end - reaction_start
print(t)
f = font.render("REACTION TIME: "+ str(t),0,(255,255,255))
screen.blit(f,(225,300))
It would register the reaction_start and reaction_end almost simulataneously and would not wait for the key press.
This currently prints both the statements "PRESS ANY KEY" and "REACTION TIME:" together, but when I had put the statements of screen.fill(pygame.Color("black") and pygame.display.flip() before the screen.blit(f), it would only show REACTION TIME: and not "PRESS ANY KEY"
In pygame the system time can be obtained by calling pygame.time.get_ticks(), which returns the number of milliseconds since pygame.init() was called.
Do not try to delay or to wait in the application loop. Add a game_state variabel, that which can have the states "start", "wait" and "wait_for_reaction".
Get the current time at the begin of the application loop:
while running:
current_time = pygame.time.get_ticks()
Set the start time when a key is pressed:
if event.type == pygame.KEYDOWN:
if game_state == "start":
game_state = "wait"
start_time = current_time + random.randint(1000, 4000)
Chang the game_state form "wait" to "wait_for_reaction" when the current time is greater or equal the start time:
if game_state == "wait":
if current_time >= start_time:
game_state = "wait_for_reaction"
Compute the reaction time and restart the process, when a key is hit again:
if event.type == pygame.KEYDOWN:
# [...]
if game_state == "wait_for_reaction":
game_state = "wait"
reaction_time = (current_time - start_time) / 1000
start_time = current_time + random.randint(1000, 4000)
count += 1
average_time = (average_time * (count-1) + reaction_time) / count
r_surf = font.render(f"REACTION TIME: {reaction_time:.03f}",0,(255,255,255))
ar_surf = font.render(f"AVERAGE REACTION TIME IS: {average_time:.03f}",0,(255,255,255))
Redraw the scene in every frame, dependent on the state of the game:
while running:
# [...]
screen.fill(pygame.Color("black"))
center = screen.get_rect().center
if game_state == "start":
screen.blit(text, text.get_rect(center = center))
if game_state == "wait_for_reaction":
screen.blit(w, w.get_rect(center = center))
if r_surf:
screen.blit(r_surf, r_surf.get_rect(center = (center[0], 350)))
if ar_surf:
screen.blit(ar_surf, ar_surf.get_rect(center = (center[0], 400)))
pygame.display.flip()
Complete example:
import pygame
import random
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Reaction Time Test")
font = pygame.font.SysFont(None, 30)
text = font.render("PRESS ANY KEY TO START TEST", 0, (255,255,255))
w = font.render("PRESS ANY KEY",0,(0,255,0))
r_surf = None
ar_surf = None
game_state = "start"
start_time = 0
average_time = 0
count = 0
running = True
while running:
current_time = pygame.time.get_ticks()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.quit()
if event.type == pygame.KEYDOWN:
if game_state == "start":
game_state = "wait"
start_time = current_time + random.randint(1000, 4000)
if game_state == "wait_for_reaction":
game_state = "wait"
reaction_time = (current_time - start_time) / 1000
start_time = current_time + random.randint(1000, 4000)
count += 1
average_time = (average_time * (count-1) + reaction_time) / count
r_surf = font.render(f"REACTION TIME: {reaction_time:.03f}",0,(255,255,255))
ar_surf = font.render(f"AVERAGE REACTION TIME IS: {average_time:.03f}",0,(255,255,255))
if game_state == "wait":
if current_time >= start_time:
game_state = "wait_for_reaction"
screen.fill(pygame.Color("black"))
center = screen.get_rect().center
if game_state == "start":
screen.blit(text, text.get_rect(center = center))
if game_state == "wait_for_reaction":
screen.blit(w, w.get_rect(center = center))
if r_surf:
screen.blit(r_surf, r_surf.get_rect(center = (center[0], 350)))
if ar_surf:
screen.blit(ar_surf, ar_surf.get_rect(center = (center[0], 400)))
pygame.display.flip()
Related
I have a ball animation and I want it so that it that runs until you CLOSE the program (A.K.A until pygame.QUIT is activated) And then after pygame.QUIT is activated it will count down from 10 seconds before it closes.
(PS. If you're an admin of this website the other post you send me doesn't help with my specific problem)
import pygame
import random
pygame.init()
window = pygame.display.set_mode([400,400])
c = pygame.time.Clock()
black = (0,0,0)
white = (255,255,255)
x = random.randint(10,390)
y = random.randint(10,390)
speed_x = random.randint(3,5)
speed_y = random.randint(3,5)
time = 10
#this is definitely wrong so this where I need help on
playing = True
while playing:
for event in pygame.event.get():
if event.type == pygame.QUIT:
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
if time == 0:
playing = False
x += speed_x
y += speed_y
window.fill((white))
pygame.draw.circle(window,black,(x,y),20)
if x > 390 or x < 10:
speed_x = speed_x * -1
if y > 390 or y < 10:
speed_y = speed_y * -1
c.tick(60)
pygame.display.flip()
Instead of exiting the application, start a countdown timer. Quit the application when the countdown is complete.
See Countdown timer in Pygame.
Minimal example:
import pygame
pygame.init()
window = pygame.display.set_mode((200, 200))
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 100)
counter = 0
text = font.render(str(10), True, (0, 128, 0))
timer_event = pygame.USEREVENT+1
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
counter = 10
pygame.time.set_timer(timer_event, 1000)
elif event.type == timer_event:
counter -= 1
text = font.render(str(counter), True, (0, 128, 0))
if counter == 0:
run = False
window.fill((255, 255, 255))
# draw game
# [...]
if counter > 0:
text_rect = text.get_rect(center = window.get_rect().center)
window.blit(text, text_rect)
pygame.display.flip()
pygame.quit()
exit()
Hi everyone! I want to create a stopwatch with pygame. I saw this code:
import pygame as pg
pg.init()
screen = pg.display.set_mode((400, 650))
clock = pg.time.Clock()
font = pg.font.Font(None, 54)
font_color = pg.Color('springgreen')
passed_time = 0
timer_started = False
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_SPACE:
timer_started = not timer_started
if timer_started:
start_time = pg.time.get_ticks()
if timer_started:
passed_time = pg.time.get_ticks() - start_time
screen.fill((30, 30, 30))
text = font.render(str(passed_time / 1000), True, font_color)
screen.blit(text, (50, 50))
pg.display.flip()
clock.tick(30)
pg.quit()
but when you press the spacebar, the timer restarts. how can i print it (on the screen)?
here is the updated code (since I assumed that You want to print multiple results on the screen, that is what I did):
import pygame as pg
pg.init()
screen = pg.display.set_mode((400, 650))
clock = pg.time.Clock()
font = pg.font.Font(None, 54)
font_color = pg.Color('springgreen')
passed_time = 0
start_time = None
timer_started = False
done = False
results = []
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_SPACE:
timer_started = not timer_started
if timer_started:
start_time = pg.time.get_ticks()
elif not timer_started:
results.append(passed_time)
if len(results) > 10:
results.pop(0)
if timer_started:
passed_time = pg.time.get_ticks() - start_time
screen.fill((30, 30, 30))
text = font.render(f'{(passed_time / 1000):.3f}', True, font_color)
screen.blit(text, (50, 50))
for index, result in enumerate(results):
text = font.render(f'{(result / 1000):.3f}', True, font_color)
screen.blit(text, (50, 50 + 54 * (len(results) - index)))
pg.display.flip()
clock.tick(30)
pg.quit()
The way this works: if the stopwatch is stopped the value it was stopped at gets appended to the list.
Then later in the code it reads each item in the list and puts it on the screen.
(50, 50 + 54 * (len(results) - index)) this makes sure that time is displayed in chronological order by when the time was recorded.
Also there is this part:
if len(results) > 10:
results.pop(0)
which makes sure that the list doesn't get overfilled.
I've been working on a sorting application in python using pygame for visual purposes, and now I am experiencing an error which I am not sure how to fix. My code was working perfectly fine, and then I started getting an error which was saying "pygame.error: video system not initialized". Here is my code:
import pygame
import random
import keyboard
pygame.font.init()
lines = [random.randint(1,25) for i in range(100)]
def line_draw():
array_items = len(lines)
line_color = (0,0,0)
line_width = int(650 / array_items)
list_pos = 1
for i in lines:
start_x = (800 / (array_items + 1)) * list_pos
start_y = 600
end_x = start_x
end_y = 600 - (i * 20)
pygame.draw.line(gameDisplay, line_color, (start_x, start_y), (end_x, end_y), line_width)
list_pos = list_pos + 1
def refill():
gameDisplay.fill((255,255,255))
line_draw()
pygame.display.update()
pygame.time.delay(3)
def bubble_sort():
exchange = True
elements = len(lines)
passes_remaining = elements - 1
while passes_remaining > 0 and exchange:
exchange = False
pygame.event.pump()
for i in range(passes_remaining):
if lines[i] > lines[i+1]:
exchange = True
temp = lines[i]
lines[i] = lines[i+1]
lines[i+1] = temp
refill()
passes_remaining = passes_remaining - 1
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_o:
bubble_sort()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
lines = [random.randint(1,25) for i in range(100)]
line_draw()
gameDisplay.fill((255, 255, 255))
line_draw()
pygame.display.update()
You have to initialized to pygame modules (e.g. pygame.init()) and you must initialize a window or screen for display with pygame.display.set_mode, before the application loop:
import pygame
# [...]
pygame.init()
pygame.display.set_mode((640, 480))
# [...]
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# [...]
pygame.quit()
I am making a mole shooter game using pygame. I want my mole to spawn at a random position after every 1 second. I have tried using time.sleep(1.0) but that delays my whole code and thus the game doesn't function properly because of delayed responses. I am moving an aim using the mouse(which also gets affected because of time.sleep) to which i will be adding a click to shoot. I need help with delaying and spawning my mole. I would also like some opinions on how to organize my code to provide various levels of difficulty and a main menu later on.
import pygame
import random
import time
from threading import Timer
pygame.font.init()
win_width = 1000
win_height = 710
FPS = 60
screen = pygame.display.set_mode((win_width, win_height))
pygame.display.set_caption("Mole Shooter")
white = (255,255,255)
red = (255, 0, 0)
counter, text = 30, 'Time Left: 30'.rjust(3)
pygame.time.set_timer(pygame.USEREVENT, 1000)
font = pygame.font.Font('freesansbold.ttf', 32)
run = True
clock = pygame.time.Clock()
background = pygame.transform.scale(pygame.image.load('back_land.png'), (win_width, win_height))
aim = pygame.image.load("aim.png")
mole = pygame.image.load("mole.png")
def mole_spawn_easy():
molex = random.randint(50, 950)
moley = random.randint(450, 682)
screen.blit(mole, (molex, moley))
while run:
screen.blit(background, [0,0])
ax, ay = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.USEREVENT:
counter -= 1
text = ("Time Left: " + str(counter)).rjust(3)
if counter > 0:
time.sleep(1.0);mole_spawn_easy()
else:
print("game over")
break
screen.blit(aim, ((ax - 32 ),(ay - 32)))
screen.blit(font.render(text, True, (0, 0, 0)), (32, 48))
clock.tick(FPS)
pygame.display.flip()
In pygame exists a timer event. Use pygame.time.set_timer() to repeatedly create a USEREVENT in the event queue.. The time has to be set in milliseconds:
pygame.time.set_timer(pygame.USEREVENT, 1000) # 1 second
Note, in pygame customer events can be defined. Each event needs a unique id. The ids for the user events have to be between pygame.USEREVENT (24) and pygame.NUMEVENTS (32). In this case the value of pygame.USEREVENT is the event id for the timer event.
Receive the event in the event loop:
running = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.USEREVENT:
# [...]
The timer event can be stopped by passing 0 to the time argument of pygame.time.set_timer.
See also Spawning multiple instances of the same object concurrently in python.
Create a list of moles and add a random position to the list in mole_spawn_easy:
moles = []
def mole_spawn_easy():
molex = random.randint(50, 950)
moley = random.randint(450, 682)
moles.append((molex, moley))
Draw the moles in the main application loop:
while run:
# [...]
for pos in moles:
screen.blit(mole, pos)
See the example:
moles = []
def mole_spawn_easy():
molex = random.randint(50, 950)
moley = random.randint(450, 682)
moles.append((molex, moley))
pygame.time.set_timer(pygame.USEREVENT, 1000)
while run:
ax, ay = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.USEREVENT:
counter -= 1
text = ("Time Left: " + str(counter)).rjust(3)
if counter > 0:
mole_spawn_easy()
else:
print("game over")
screen.blit(background, [0,0])
for pos in moles:
screen.blit(mole, pos)
screen.blit(aim, ((ax - 32 ),(ay - 32)))
screen.blit(font.render(text, True, (0, 0, 0)), (32, 48))
pygame.display.flip()
clock.tick(FPS)
I'm trying to make a reaction time tester in Pygame, but the timer for each attempt is displaying 0. When the screen is red, pressing the down key is supposed to record the time taken. I'm not sure exactly where I'm supposed to place the timer, as I'm struggling to understand how the event loop actually works.
import pygame, sys
import random
from random import randint
import time
from time import sleep
from pygame.locals import *
FPS = 30
fpsClock = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((400, 300), 0, 32)
pygame.display.set_caption('Test')
WHITE = (255, 255, 255)
RED = (255, 0, 0)
y = False
x = 0
while True:
if y is False:
y = True
DISPLAYSURF.fill(WHITE)
start = time.time()
sleep(randint(1,3))
else:
y = False
DISPLAYSURF.fill(RED)
time.sleep(2)
for event in pygame.event.get():
if x < 5:
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if y is True:
end = time.time()
print(end - start)
x += 1
else:
pygame.quit()
sys.exit()
pygame.display.update()
fpsClock.tick(FPS)
I'm not sure if it works exactly as you expect but it checks time reaction on red color in miliseconds, and it works without time.sleep()
import pygame
import random
# --- constants ---
FPS = 30
WHITE = (255, 255, 255)
RED = (255, 0, 0)
# --- main ---
pygame.init()
screen = pygame.display.set_mode((400, 300))
pygame.display.set_caption('Test')
repeats = 5
testing = False
color = WHITE
current_time = pygame.time.get_ticks()
# random time to start test
start_test = current_time + random.randint(1, 3)*1000 # 1000ms = 1s
# - mainloop -
fps_clock = pygame.time.Clock()
while True:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
elif event.type == pygame.KEYDOWN:
if testing:
end = pygame.time.get_ticks()
print(end - start, 'ms')
repeats -= 1
# - other
if repeats == 0:
pygame.quit()
exit()
current_time = pygame.time.get_ticks()
# is it time to start displaying red color
if not testing and current_time >= start_test:
testing = True
color = RED
start = pygame.time.get_ticks()
# display white color
stop_test = current_time + 2*1000 # 1000ms = 1s
# is it time to stop displaying red color
if testing and current_time >= stop_test:
testing = False
color = WHITE
# random time to start next test
start_test = current_time + random.randint(1, 3)*1000 # 1000ms = 1s
# - draws -
screen.fill(color)
pygame.display.flip()
fps_clock.tick(FPS)