Why doesn't this loop run properly? - python

while g.running:
for event in pygame.event.get():
if event == pygame.QUIT:
g.running = False
g.run(Player_1)
quit()
when I run this loop it completely skips the for loop or just does it once and is too fast for me to be able to run and it just goes on to run. How do I make the loop work fine?
https://github.com/maartenww/100daysOfCode_projectOne << for the full code.
Also, what g.run basically does is just update the game. So it draws and or moves all the sprites, draws the text unto the screen and does some calculations
class Game:
def __init__(self):
self.running = True
def run(self, player_1):
self.border_col(player_1)
self.load_text(player_1)
self.update_game(player_1)
def update_game(self, player_1):
clock.tick(FPS)
gameDisplay.fill(black)
gameDisplay.blit(self.xcolon, (0, 0))
gameDisplay.blit(self.actual_x, (25, 0))
gameDisplay.blit(self.ycolon, (0, 30))
gameDisplay.blit(self.actual_y, (25, 30))
gameDisplay.blit(self.acolon, (0, 60))
gameDisplay.blit(self.actual_a, (25, 60))
gameDisplay.blit(self.vcolon, (0, 90))
gameDisplay.blit(self.actual_v, (25, 90))
all_sprites.draw(gameDisplay)
Player.move_player(player_1)
Player.update_player(player_1)
pygame.display.update()

I looked into your repo, and the revelant code is this, in player.py:
def move_player(self):
for event in pygame.event.get():
# Player movement
if (event.type == pygame.KEYDOWN):
if (event.key == pygame.K_d):
self.player_acc = PLAYER_ACC
if (event.key == pygame.K_a):
self.player_acc = -PLAYER_ACC
if (event.type == pygame.KEYUP):
if (event.key == pygame.K_d):
self.player_acc = 0
if (event.key == pygame.K_a):
self.player_acc = 0
Think about what happens in your main loop:
while g.running:
for event in pygame.event.get():
if (event.type == pygame.QUIT):
g.running = False
g.run(Player_1)
You get all events from the event queue, clearing it, and check for QUIT.
Then you call g.run, which will call self.update_game, which will call Player.move_player, which will again get all events from the event queue and clear it.
So when the QUIT event is in the event queue at the moment pygame.event.get() is called inside Player.move_player, it is practically lost, since you don't handle it in this for loop. When pygame.event.get() is then called again in main, the QUIT event is no longer in the queue (because calling event.get clears the queue).
Basically, you should call 'event.get' only once per main loop iteration (the same is true for pygame.display.flip/pygame.display.update).
Maybe change the loop in main to something like this:
while g.running:
for event in pygame.event.get():
g.handle(event, Player_1)
g.run(Player_1)
add this to Game:
def handle(self, event, player_1):
if event.type == pygame.QUIT:
self.running = False
else:
player_1.handle(event)
and this to Player:
def handle(self, event):
# Player movement
if (event.type == pygame.KEYDOWN):
if (event.key == pygame.K_d):
self.player_acc = PLAYER_ACC
if (event.key == pygame.K_a):
self.player_acc = -PLAYER_ACC
if (event.type == pygame.KEYUP):
if (event.key == pygame.K_d):
self.player_acc = 0
if (event.key == pygame.K_a):
self.player_acc = 0
and remove Player.move_player

I expect the loop does run, but you've hit a case of type mismatch not being reported.
for event in pygame.event.get():
if event == pygame.QUIT:
event will be a pygame.event.Event object. The QUIT value you're checking against is a value that might appear in the event.type attribute. Since no event is the integer value QUIT, all events are being ignored. You might want to add an else clause to diagnose which events are received but not handled.

Related

How do I stop continuous loop of KEYDOWN?

I am new to pygame. Whenever I press the key "Delete". It prints "key" continuously. I only want it to print it only one time. How can I do this ?
import pygame
import sys
sprite = "sprite_1.jpg"
position = (20,0)
canvas = pygame.display.set_mode((952, 592))
color = (255,255,255)
exit = False
back = pygame.image.load("th.jpg").convert_alpha()
back = pygame.transform.scale(back, (952,592))
Sprite = pygame.image.load(sprite)
Sprite.set_colorkey((255,255,255))
Sprite = pygame.transform.scale(Sprite, (35,35))
pygame.display.set_caption("Game")
while not exit:
canvas.fill(color)
canvas.blit(back, dest = (0,0))
canvas.blit(Sprite, dest=position)
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit = True
if (event.type == pygame.KEYDOWN):
if (event.key == pygame.K_DELETE):
print("hi")
pygame.display.update()
Please tell the solution. Thanks in advance
It is a matter of Indentation. The event has to be handled in the event loop instead of the applicaition loop:
while not exit:
canvas.fill(color)
canvas.blit(back, dest = (0,0))
canvas.blit(Sprite, dest=position)
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit = True
# INDENTATION
#-->|
if (event.type == pygame.KEYDOWN):
if (event.key == pygame.K_DELETE):
print("hi")
pygame.display.update()
count=0
while not exit:
enter code herecanvas.fill(color)
canvas.blit(back, dest = (0,0))
canvas.blit(Sprite, dest=position)
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit = True
if (event.type == pygame.KEYDOWN):
if count<=0:
if (event.key == pygame.K_DELETE):
print("hi")
else:
continue
pygame.display.update()

Pygame cant get events inside nested while loop

I've looked at a couple sources so far and i can't seem to figure out why pygame wont grab events to unpause in my pause function.
def pause():
paused = True
while paused:
for event in pygame.event.get():
if event == pygame.QUIT:
pygame.quit()
quit()
elif event == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
paused = False
Keep in mind that this is nested in another while loop that's running the game, the function is called, gets stuck into an infinite loop, but can't detect key press to escape even with get keys function. Anybody got answers?
pygame.event.get() returns a list of pygame.event.Event() objects. You have to test if the type attribute of the event is pygame.KEYDOWN:
elif event == pygame.KEYDOWN:
elif event.type == pygame.KEYDOWN:
def pause():
paused = True
while paused:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
paused = False

Making a pause screen

Im trying to make a pause screen function but the images shutter and appear with a good delay. Any
ideas Heres my code:
PauseLogo = pg.image.load('Stop.png')
Pause = pg.image.load('Pause.png')
#------------------------------------------
while running:
clock.tick(FPS)
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
if event.type == pg.KEYDOWN:
if event.key == pg.K_SPACE:
paused = not paused
if paused == True:
clock.tick(27)
screen.blit(PauseLogo, (0,0))
screen.blit(Pause, (400, 330))
if not paused:
all_sprites.update()
screen.fill(DARKGRAY)
all_sprites.draw(screen)
Draw different scenes dependent on the state of paused:
while running:
clock.tick(FPS)
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
if event.type == pg.KEYDOWN:
if event.key == pg.K_SPACE:
paused = not paused
if paused == True:
screen.blit(PauseLogo, (0,0))
screen.blit(Pause, (400, 330))
else:
all_sprites.update()
screen.fill(DARKGRAY)
all_sprites.draw(screen)
pygame.display.update()
Note, pygame.time.Clock.tick() measures the time since the last call of this function and delays the application. If you call it twice in the application, the application is delayed twice.

pygame KEYUP registers only KEYDOWNs

When I press the spacebar "up" and "down" is printed simultaneous, however when I release, nothing is happening.
while True:
pygame.display.set_mode((600,600))
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
print('down')
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
print('up')
if event.type == pygame.QUIT:
pygame.quit()
exit()
You're creating a new display every single frame of your game.
You need to create the display only once, on the outside of your game loop. It should also be assigned to a variable, as you'll need it if you want to draw (blit) items to it, for example.
display = pygame.display.set_mode((600,600))
# Game loop
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
# ...

Pygame error: pygame.error: display Surface quit

So I created a Python game Tetris based on Youtube tutorial:
https://www.youtube.com/watch?v=zfvxp7PgQ6c&t=2075s
But the pygame.error: display Surface quit occurs.
I have tried to add "break", "sys.exit()", "QUIT" after the pygame.quit but does not work.
Does anyone know how to solve it? Here is the code: (You can skip to the def main_menu)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run == False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
current_piece.x -= 1
if not (valid_space(current_piece, grid)):
current_piece.x += 1
if event.key == pygame.K_RIGHT:
current_piece.x += 1
if not (valid_space(current_piece, grid)):
current_piece.x -= 1
if event.key == pygame.K_DOWN:
current_piece.y += 1
if not (valid_space(current_piece, grid)):
current_piece.y -= 1
if event.key == pygame.K_UP:
current_piece.rotation += current_piece.rotation + 1 % len(current_piece.shape)
if not (valid_space(current_piece, grid)):
current_piece.rotation -= 1
shape_pos = convert_shape_format(current_piece)
for i in range(len(shape_pos)):
x, y = shape_pos[i]
if y > -1:
grid[y][x] = current_piece.color
if change_piece:
for pos in shape_pos:
p = (pos[0], pos[1])
locked_positions[p] = current_piece.color
current_piece = next_piece
next_piece = get_shape()
change_piece = False
score += clear_rows(grid, locked_positions) * 10
draw_window(win, grid, score, last_score)
draw_next_shape(next_piece, win)
pygame.display.update()
if check_lost(locked_positions):
draw_text_middle(win, "You Lost!", 80, (255,255,255))
pygame.display.update()
pygame.time.delay(1500)
run = False
update_score(score)
def main_menu(win):
run = True
while run:
win.fill((0,0,0))
draw_text_middle(win, 'Press any key to play', 60, (255,255,255))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.display.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
main(win)
pygame.display.QUIT()
win = pygame.display.set_mode((s_width, s_height))
pygame.display.set_caption('Tetris')
main_menu(win)
Updated code:
def main_menu(win):
run = True
while run:
win.fill((0,0,0))
draw_text_middle(win, 'Press any key to play', 60, (255,255,255))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
main(win)
pygame.quit()
win = pygame.display.set_mode((s_width, s_height))
pygame.display.set_caption('Tetris')
main_menu(win)
In your main_menu loop you are telling it to loop while local boolean run == True. This is okay, but you should as people mentioned in the comments do a pygame.quit() and optionally quit() (closes the window) instead of the pygame.display.quit() and sys.exit() that you have right now.
The second problem occurs if you start the game by going into the main loop. I assume that the main loop runs your events function shown at the top?
Depending on how you have written the code, the boolean run in the event function is
local. This means that it will not change the value of the run you are using in your
main loop (nor change it in the main_menu loop). I would suggest to transfer into OOP and create a self.run boolean instead,
or else you need to make the boolean run global.
And you should in the event function write this instead of what you have now at the
top:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
Hope this helps!

Categories

Resources