Faster version of 'pygame.event.get()'. Why are events being missed and why are the events delayed?
[...] and have two for event in
pygame.event.get()
loops [..]"
That's the issue. pygame.event.get()
get all the messages and remove them from the queue. See the documentation:
This will get all the messages and remove them from the queue. [...]
If pygame.event.get()
is called in multiple event loops, only one loop receives the events, but never all loops receive all events. As a result, some events appear to be missed.
Get the events once per frame and use them in multiple loops or pass the list or events to functions and methods where they are handled:
def handle_events(events):
for event in events:
# [...]
while run:
event_list = pygame.event.get()
# [...]
# 1st event loop
for event in event_list:
# [...]
# [...]
# 2nd event loop
for event in event_list:
# [...]
# [...]
# function which handles events
handle_events(event_list)
Pygame : Having trouble w/ multiple event.get() calls
pygame.event.get()
removes the events from the queue (see pygame documentation).
So, some of the events are gotten in the main loop, and the others in the class, and you don't know where a specific event is gotten py pygame. So you miss some of the events.
To avoid that, call pygame.event.get()
one time per frame, and use the same list for both main loop and SingleBullet
:
class Singlebullet(object):
def shoot(self):
...
for e in events: # same events as in main loop
while running:
events = pygame.event.get()
for event in events:
...
Don't forget to set the list to []
the first frame if you get the events after calling Singlebullet.shoot()
(the class will ask for an unexisting list).
PyGame is Freezing
See Faster version of 'pygame.event.get()'. Why are events being missed and why are the events delayed?. The issue is that pygame.event.get()
is called twice:
def game():
# [...]
clock.tick(FPS)
# [...]
pygame.event.get()
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
# [...]
Note, pygame.event.get()
gets all the messages and remove them from the queue. So the first call gets the messages, remove them and puts them nowhere. The 2nd call doesn't get any messages at all.
At least you would've to do a "delay" between the calls of pygame.event.get()
(e.g. clock.tick(FPS)
).
Delete the first call of pygame.event.get()
and move the event loop to the begin of game
:
def game():
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
# [...]
Further note, it makes no sens to call pygame.quit()
and to call pygame.display.update()
after that. pygame.quit()
uninitialize all pygame modules and causes all further calls to pygame operations to crash.
Don't forget to update the display in the game loop by either pygame.display.update()
or pygame.display.flip()
.
Add a return value to the function game
. Return True
, when the game loop should continue and False
when the application should stop:
def game():
returnCode = True
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
returnCode = False
# [...]
for s in [spikeUp0, spikeDown0, BoneUp1, BoneDown1, BoneUp2, BoneDown2]:
if pygame.sprite.collide_rect(Dog, s):
returnCode = False
# [...]
return returnCode
run = True
while run:
run = game()
pygame.display.update()
pygame.quit()
sys.exit()
Throttle keypresses in pygame
To jump you have to use KEYDOWN
instead of pygame.key.get_pressed()
. Use pygame.key.get_pressed()
to move but not to jump.pygame.key.get_pressed()
returns a sequence with the state of each key. If a key is held down, the state for the key is True
, otherwise False
. Use pygame.key.get_pressed()
to evaluate the current state of a button and get continuous movement.
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN
event occurs once every time a key is pressed. KEYUP
occurs once every time a key is released. Use the keyboard events for a single action like jumping or spawning a bullet.
Make sure you only call pygame.get.event()
once (see Faster version of 'pygame.event.get()'. Why are events being missed and why are the events delayed?):
def get_input(self, event_list):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and keys[pygame.K_RIGHT]: pass
elif keys[pygame.K_LEFT]: self.direction.x = -1
elif keys[pygame.K_RIGHT]: self.direction.x = 1
else: self.direction.x = 0
for event in event_list:
if event.type == pygame.KEYDONW and event.key == pygame.K_SPACE:
self.jump()
# application loop
while run:
# event loop
event_list = pygame.get.event()
for event in event_list:
if event.type == pygame.QUIT:
# [...]
player.get_input(event_list)
The other option is to state if SPACE was pressed in previous frames. So you can detect that the SPACE is hold down:
def __init__(self, pos):
super().__init__()
# [...]
self.space_was_pressed = False
def get_input(self):
keys = pygame.key.get_pressed()
# [...]
space_is_pressed = keys[pygame.K_SPACE]
if space_is_pressed and not self.space_was_pressed:
self.jump()
self.space_was_pressed = space_is_pressed
See also How to make a character jump in Pygame?
How To Make An Action Happen Only Once In Python / Pygame
First of all why do you not only allow to jump if self.on_ground
?
class Player(pygame.sprite.Sprite):
# [...]
def get_input(self):
# [...]
if keys[pygame.K_SPACE] and self.on_ground:
self.jump()
Anyway, you have to use the KEYDOWN
event instead of pygame.key.get_pressed()
pygame.key.get_pressed()
returns a list with the state of each key. If a key is held down, the state for the key is True
, otherwise False
. Use pygame.key.get_pressed()
to evaluate the current state of a button and get continuous movement.
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN
event occurs once every time a key is pressed. KEYUP
occurs once every time a key is released. Use the keyboard events for a single action or a step-by-step movement.
class Player(pygame.sprite.Sprite):
# [...]
def get_input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
self.direction.x = 1
elif keys[pygame.K_LEFT]:
self.direction.x = -1
else:
self.direction.x = 0
for event in event_list:
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
self.jump()
# application loop
while run:
#event loop
event_list = pgame.event.get()
for event in event_list:
if event.type == pygame.QUIT:
run = False
# [...]
Note, pygame.event.get()
get all the messages and remove them from the queue. See the documentation:
This will get all the messages and remove them from the queue. [...]
If pygame.event.get()
is called in multiple event loops, only one loop receives the events, but never all loops receive all events. As a result, some events appear to be missed.
See Faster version of 'pygame.event.get()'. Why are events being missed and why are the events delayed?.
Alternatively you can prevent multiple jumps in a row with a state attribute:
class Player(pygame.sprite.Sprite):
def __init__(self, pos):
# [...]
self.is_jumping = False
def get_input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
self.direction.x = 1
elif keys[pygame.K_LEFT]:
self.direction.x = -1
else:
self.direction.x = 0
space_pressed = keys[pygame.K_SPACE]:
if space_pressed and not self.is_jumping:
self.jump()
self.is_jumping = space_pressed
pygame not blitting images onto the surface permanently
You must draw the scene in the application loop. The event loop is only executed once, when the event occurs. Add a state draw_scene = 0
. Change the state when the event occurs (draw_scene = 1
) and draw the scene depending on draw_scene
.
pygame.event.get()
get all the messages and remove them from the queue. See the documentation:
This will get all the messages and remove them from the queue. [...]
If pygame.event.get()
is called in multiple event loops, only one loop receives the events, but never all loops receive all events. As a result, some events appear to be missed.
Get the events once per frame and use them in multiple loops. See Faster version of 'pygame.event.get()'. Why are events being missed and why are the events delayed?
draw_scene = 0
running = True
while running:
screen.fill((211, 211, 211))
alphaval -= 20
event_list = pygame.event.get()
for event in event_list:
if event.type == pygame.QUIT:
quit()
if draw_scene == 0:
screen.blit(frame_0, (0, 0))
pygame.draw.rect(screen, (0, 0, 0), (0, 0, 320, 480), 15)
if realtime >= 1:
loading(337, 99)
fadein()
if realtime <= 9 and realtime >= 3:
channel1.play(pygame.mixer.Sound('missions\call.ogg'))
time.sleep(9)
elif realtime >= 9:
screen.blit(frameE_0, (320, 0))
pygame.draw.rect(screen, (0, 0, 0), (320, 0, 320, 480), 15)
if realtime >= 12.5:
screen.blit(dialE, (45, 300))
textbox("hello?", 65, 340)
if realtime >= 14:
textbox("who is this?", 125, 340)
for event in event_list:
if event.type == pygame.KEYDOWN and realtime >= 14:
if event.key == pygame.K_RETURN:
draw_scene = 1
if draw_scene == 1:
screen.fill((211, 211, 211))
screen.blit(frame_0, (0, 0))
pygame.draw.rect(screen, (0, 0, 0), (0, 0, 320, 480), 15)
screen.blit(frameE_0, (320, 0))
pygame.draw.rect(screen, (0, 0, 0), (320, 0, 320, 480), 15)
pygame.display.update()
clock.tick(30)
Pygame is only drawing one button at a time
Yes of course, because you have an extra while
-loop in the method draw_button
. You have an application loop. Use it! You don't need the while loop in draw_button
at all.
You will also need to remove the display update from draw_button
. One update of the display at the end of the application loop is sufficient. Multiple calls to pygame.display.update()
or pygame.display.flip()
cause flickering.
See Why is the PyGame animation is flickering
Next you will have problems with the events. pygame.event.get()
get all the messages and remove them from the queuepygame.event.get()
get all the messages and remove them from the queue. See the documentation:
This will get all the messages and remove them from the queue. [...]
If pygame.event.get()
is called in multiple event loops, only one loop receives the events, but never all loops receive all events. As a result, some events appear to be missed.
Get the events once and use them in multiple loops or pass the list or events to functions and methods where they are handled.
See Faster version of 'pygame.event.get()'. Why are events being missed and why are the events delayed?.
def draw_button(button, outline, active, inactive, event_list, action=None):
mouse_pos = pygame.mouse.get_pos()
if button.isOver(mouse_pos):
button.color = active
else:
button.color = inactive
button.draw(screen, outline)
for event in event_list:
if event.type == pygame.MOUSEBUTTONDOWN:
if action and button.isOver(event.pos):
action()
def titlescreen():
active = True
start_button = button(buttonnormal, 240, 380, 150, 50, "START")
quit_button = button(buttonnormal, 420, 380, 150, 50, "quit")
while active:
event_list = pygame.event.get()
for event in event_list:
if event.type == pygame.QUIT:
exit_game()
screen.fill(background)
title_text('Welcome To')
titleimage()
draw_button(start_button, black, btn_hover, buttonnormal, event_list, mainmenu)
draw_button(quit_button, black, btn_hover, buttonnormal, event_list, exit_game)
pygame.display.update()
clock.tick(60)
Related Topics
Get Key by Value in Dictionary
Why Does += Behave Unexpectedly on Lists
Read Streaming Input from Subprocess.Communicate()
How to Pass Arguments to a Button Command in Tkinter
Deploying a Minimal Flask App in Docker - Server Connection Issues
Correct Way to Write Line to File
How to Do a Case-Insensitive String Comparison
Get Difference Between Two Lists
Check If Multiple Strings Exist in Another String
Could Not Open Resource File, Pygame Error: "Filenotfounderror: No Such File or Directory."
How to Compare Floats For Almost-Equality in Python
Get a List of Numbers as Input from the User
Getting the Name of a Variable as a String
How to Set the 'Backend' in Matplotlib in Python