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!
Related
I ran into a bug with my timer. When I pause my game I noticed that my timer doesn't pause a long with the game. Example: if I pause the game when the timer is at 26 seconds remaining, and unpause the game about ten seconds later, the timer will say 16 seconds left instead of counting down from 26 like I want it to. If I pause the game for 30 seconds the timer still runs down to 0 instead of the timer pausing along with the game. How can I fix this?
code where my game runs:
#game runs here
run = True
paused = False
while run:
for event in pygame.event.get():
if event.type == pygame.USEREVENT:
counter -= 1
text = str(counter).rjust(3) if counter > 0 else 'GAME OVER!'
if event.type == pygame.QUIT:
run = False
#pause game
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
paused = not paused
#check if key is down
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
if event.key == pygame.K_a:
player.movingLeft = True
if event.key == pygame.K_d:
player.movingRight = True
if event.key == pygame.K_SPACE:
player.shoot()
shoot = True
#check if key is up
if event.type == pygame.KEYUP:
if event.key == pygame.K_a:
player.movingLeft = False
if event.key == pygame.K_d:
player.movingRight = False
if paused:
continue
#draw street
screen.blit(bg, [0, 0])
#draw timer
screen.blit(timer_font.render(text, True, (0,0,0)), (800, 10))
#update groups
bullet_group.update()
bullet_group.draw(screen)
debris_group.update()
debris_group.draw(screen)
#draw car
player.draw()
player.move()
player.collision(debris_group)
player.stats()
#update all sprites
all_sprites.update()
all_sprites.draw(screen)
#update the display
pygame.display.update()
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
The timer event can be stopped by passing 0 to the time argument of pygame.time.set_timer.
Stop and restart the timer event when you toggle the pause state:
run = True
paused = False
while run:
for event in pygame.event.get():
if event.type == pygame.USEREVENT:
counter -= 1
text = str(counter).rjust(3) if counter > 0 else 'GAME OVER!'
if event.type == pygame.QUIT:
run = False
#pause game
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
paused = not paused
if pause:
pygame.time.set_timer(pygame.USEREVENT, 0) # stop timer
else:
pygame.time.set_timer(pygame.USEREVENT, 1000) # 1 second interval
# [...]
I have a simple game and I want my mouse click (button doesnt matter) to only register once per click. Right now it works even if it is held down.
def drawer(x, y):
pygame.draw.circle(screen, (0, 0, 0), [int(x), int(y)],20)
def main():
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
exit()
if event.type == pygame.MOUSEBUTTONDOWN:
playerY_change = -player.vy
if event.type == pygame.MOUSEBUTTONUP:
playerY_change = player.vy
player.y += PlayerY_change
drawer(player.x, player.y)
# Other game code
pygame.display.update()
Right now the players movement keeps changing as long as you hold down the button where I want it to change only per click. How do I go about this?
Once the playerY_change is set, the player moves continuously. Therefore do not set playerY_change, but change the player.y when you click with the mouse:
def main():
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
player.y -= player.vy
drawer(player.x, player.y)
# Other game code
pygame.display.update()
pygame.quit()
exit()
I want to close the game after was pressed the esc button. how can I do? And where should I place it?
I also found some problems that I can't solve, so if you solve them for me I would be happy
This is the code:
#Import Libraries
import pygame
import random
#PyGame Initialization
pygame.init()
#Images Variables
background = pygame.image.load('images/sfondo.png')
bird = pygame.image.load('images/uccello.png')
base = pygame.image.load('images/base.png')
gameover = pygame.image.load('images/gameover.png')
tube1 = pygame.image.load('images/tubo.png')
tube2 = pygame.transform.flip(tube1, False, True)
#Display Create
display = pygame.display.set_mode((288,512))
FPS = 60
#Define Functions
def draw_object():
display.blit(background, (0,0))
display.blit(bird, (birdx, birdy))
def display_update():
pygame.display.update()
pygame.time.Clock().tick(FPS)
def animations():
global birdx, birdy, bird_vely
birdx, birdy = 60, 150
bird_vely = 0
#Move Control
animations()
while True:
bird_vely += 1
birdy += bird_vely
for event in pygame.event.get():
if ( event.type == pygame.KEYDOWN
and event.key == pygame.K_UP):
bird_vely = -10
if event.type == pygame.QUIT:
pygame.quit()
draw_object()
display_update()
Well you do so by implementing below code snippet in your code:
running = True
while running:
# other code
event = pygame.event.wait ()
if event.type == pygame.QUIT:
running = False # Be interpreter friendly
pygame.quit()
Make sure that you call pygame.quit() before you exit your main function
You can also reference this thread
Pygame escape key to exit
You must terminate the application loop when the QUIT event occurs. You have implmented the QUIT event, but you don't terminate the loop. Add a variabel run = True and set run = False when the event occurs.
To terminate the game when ESC is pressed you have to implement the KEYDOWN event. Set run = False when the KEDOWN event occurs and event.key == pgame.K_ESC:
run = True
while run:
bird_vely += 1
birdy += bird_vely
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.KEYDOWN:
if event.key == pgame.K_ESC:
run = False
elif event.key == pygame.K_UP:
bird_vely = -10
draw_object()
display_update()
pygame.quit()
exit()
In my game the player can shoot different coloured bullets using the WASD keys. The player can shoot bullets as fast as they can press the keys right now, which means you can mash the WASD keys and shoot a stream of bullets. I've tried creating a USEREVENT to make a cooldown for when the player can shoot, but I'm not entirely sure if I'm doing this right because the player doesn't shoot at all when I run the game.
#cooldown userevent
shot_cool = pygame.USEREVENT + 2
pygame.time.set_timer(shot_cool, 10)
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False #breaks out of the while loop
if event.type == pygame.KEYDOWN and event.type == shot_cool:
if event.key == pygame.K_w:
pygame.time.set_timer(shot_cool, 10)
player.shoot('red')
elif event.key == pygame.K_a:
pygame.time.set_timer(shot_cool, 10)
player.shoot('green')
elif event.key == pygame.K_s:
pygame.time.set_timer(shot_cool, 10)
player.shoot('white')
elif event.key == pygame.K_d:
pygame.time.set_timer(shot_cool, 10)
player.shoot('blue')
Is there any way I can make it so the player has a short cooldown until he can fire another bullet?
As I said in my comment, you fixed your problem perfectly. But since I already had it in my editor I decided I'd share a little more. Since all the keys function the same way, you can handle them in the same function block, using a dictionary. It could end up looking like this:
#cooldown userevent
EVT_SHOT_COOLDOWN = pygame.USEREVENT + 2
# shot cool down time
COOLDOWN_TIME_MS = 100
SHOT_KEYS = {
pygame.K_w:'red',
pygame.K_a:'green',
pygame.K_s:'white',
pygame.K_d:'blue',
}
running = True
shot_delay = False
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False #breaks out of the while loop
elif event_type == shot_cool:
shot_delay = False
elif event.type == pygame.KEYDOWN:
# handle shooting keys
if (event.key in SHOT_KEYS and not shot_delay):
pygame.time.set_timer(shot_cool, COOLDOWN_TIME_MS)
shot_delay = True
player.shoot(SHOT_KEYS[event.key])
# handle other keys (if any)
Thanks to the comment from RufusVS, what you said has worked perfectly. This is the working code:
shoot_cooldown = pygame.USEREVENT +2
pygame.time.set_timer(shoot_cooldown, 100)
shot_delay = False
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == shoot_cooldown:
shot_delay = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w and shot_delay == False:
pygame.time.set_timer(shoot_cooldown, 100)
shot_delay = True
player.shoot('red')
elif event.key == pygame.K_a and shot_delay == False:
pygame.time.set_timer(shoot_cooldown, 100)
shot_delay = True
player.shoot('green')
elif event.key == pygame.K_s and shot_delay == False:
pygame.time.set_timer(shoot_cooldown, 100)
shot_delay = True
player.shoot('white')
elif event.key == pygame.K_d and shot_delay == False:
pygame.time.set_timer(shoot_cooldown, 100)
shot_delay = True
player.shoot('blue')
In my game I have a mainloop variable that while it runs does the main part of the game and when the game is over it should change to False. I have tried to implement it so when my lives are out another loop while start. In that loop there's a button that should turn the mainloop back on but because it never turns to false I can't turn it back on.
MainLoop = True
while MainLoop:
# Setting fps
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
MainLoop = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
MainLoop = False
# Getting keys pressed
keys = pygame.key.get_pressed()
#Walking controls for player
if keys[pygame.K_LEFT] and man.x > 0:
man.x -= man.vel
man.left = True
man.right = False
elif keys[pygame.K_RIGHT] and man.x < 500 - man.vel - man.width:
man.x += man.vel
man.left = False
man.right = True
else:
man.left = False
man.right = False
man.walkCount = 0
redrawgamewindow()
for rockk in my_list:
rockk.draw(win)
rockk.move()
#Controlling man lives and game over screen
if man.hit == 1:
man.lives -=1
elif man.hit ==2:
man.lives -=1
elif man.lives <= 0:
Mainloop = False
GameOver = True
collided(rockk.x, rockk.y, man.x, man.y)
pygame.display.flip()
print (GameOver)
print (MainLoop)
while GameOver:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
GameOver = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
GameOver = False
win.blit(GameO, (0, 0))
button1 = pygame.Rect(200, 400, 100, 50)
pygame.draw.rect(win, [255, 0, 0], button1)
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = event.pos
if button1.collidepoint(mouse_pos):
print ('amazing ')
Text = pygame.font.Font('freesansbold.ttf', 20)
TextSurf, TextRect = text_objects("Restart?", Text)
TextRect.center = ((250), (425))
win.blit(TextSurf, TextRect)
pygame.display.update()
You get stuck in the loop getting pygame.events.
You have break out of this loop bfore you can break out of the outer loop.
Please try:
for event in pygame.event.get():
if event.type == pygame.QUIT:
MainLoop = False
break
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
MainLoop = False
break
if not MainLoop:
break
Please also change the following section
while GameOver:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
GameOver = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
GameOver = False
to
while GameOver:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
GameOver = False
break
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
GameOver = False
break