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
# [...]
Related
I am new to Python and especially new to Pygame. Been working on a basic space invader type game to attempt to learn more about Pygame, but I cannot figure out the code for moving the user ship. Have looked up some tutorials on it, and I THINK my code looks good, but I might be looking over something. I am in Python version 3.8 and Pygame version 1.9.6.
'''
This script is creating a space invader type game with the Pygame module.
Tutorial following YT video from freecodecamp.org
(https://www.youtube.com/watch?v=FfWpgLFMI7w&ab_channel=freeCodeCamp.org)
'''
import sys
import pygame
# Initializing Pygame
# (ALWAYS REQUIRED)
pygame.init()
# Screen Dimensions
width = 800
height = 600
screen = pygame.display.set_mode((width, height))
# Other Game Settings
framerate = pygame.time.Clock()
framerate.tick(60)
# Setting Title and Images
pygame.display.set_caption('Space Invaders')
icon = pygame.image.load('spaceship.png')
pygame.display.set_icon(icon)
player_ship = pygame.image.load('space-invaders.png')
def player(x,y):
'''
Draws the player's ship on the screen at (x,y) coordinates.
'''
screen.blit(player_ship,(x, y))
# Game Function
def game():
'''
Actual code for the game itself.
'''
# Sets the starting position for the player's ship
playerX = 368 # Middle of Screen (on x-axis)
playerY = 506 # 30px off bottom of the screen (y-axis)
x_change = 0
# Game Loop
game_exit = False
while not game_exit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_exit = True
elif event.type == pygame.KEYDOWN:
if event.type == pygame.K_ESCAPE:
game_exit = True
elif event.type == pygame.K_d:
x_change = 5
elif event.type == pygame.K_a:
x_change = -5
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d or event.key == pygame.K_a:
x_change = 0
playerX += x_change
print(x_change) # Using this to see if the script is recognizing the user keystrokes
# Setting Screen RGB
screen.fill((0,0,0))
player(playerX, playerY)
# Screen Update
# (ALWAYS REQUIRED)
pygame.display.update()
game()
pygame.quit()
sys.exit()
Thanks for your help!
The issue is you're checking for an event.type of pygame.K_d, etc.
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_exit = True
elif event.type == pygame.KEYDOWN:
if event.type == pygame.K_ESCAPE: # <-- HERE
game_exit = True
elif event.type == pygame.K_d: # <-- HERE
x_change = 5
elif event.type == pygame.K_a: # <-- AND HERE
x_change = -5
The event.type cannot be equal to both pygame.KEYDOWN and pygame.K_d at the same time!. If you check the documentation on event, notice that the key-code is sent in event.key, so it's a simple fix.
KEYDOWN key, mod, unicode, scancode
KEYUP key, mod
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_exit = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE: # <-- FIX HERE
game_exit = True
elif event.key == pygame.K_d: # <-- FIX HERE
x_change = 5
elif event.key == pygame.K_a: # <-- AND FIX HERE
x_change = -5
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')
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!
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
what i am trying to achieve
I am attempting to get the enemy to do a set of movements with a picture swap that are timed and in a ordered sequence that repeats.
the timing is not doing milliseconds?
what is happening
After a long time the enemy does first movement then long pause images some times swap sometimes not.
I am not getting any exceptions or errors when I run it.
Also when I add the userevent into the game loop above the keydown events I break the player movement.
Github to images and full code
Below is the most successful of the things I tried so far
I created the desired numbered USEREVENT in ordered sequence
# Create a bunch of AI events
ai_uppercut_event = pygame.USEREVENT + 1
ai_l_punch_event = pygame.USEREVENT + 2
ai_r_punch_event = pygame.USEREVENT + 3
ai_r_dodge_event = pygame.USEREVENT + 4
ai_l_dodge_event = pygame.USEREVENT + 5
Gave the enemy ai character a start position
enemy_x = 235
enemy_y = 145
gave the enemy ai a movement amount
aimovex = 40
aimovey = 40
defined the images to swap out for the different moves
# Define ai images for different moves
enemy_default = pygame.image.load("enemy_default.png")
ai_uppercut_image = pygame.image.load("enemy_uppercut.png")
ai_l_punch_image = pygame.image.load("enemy_left.png")
ai_r_punch_image = pygame.image.load("enemy_right.png")
ai_r_dodge_image = pygame.image.load("enemy_dodge_right.png")
ai_l_dodge_image = pygame.image.load("enemy_dodge_left.png")
set up the clock and tick and timer for events
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
start_time = pygame.time.get_ticks()
# set timer for the ai movement events
pygame.time.set_timer(ai_uppercut_event, MOVE_UPPERCUT)
pygame.time.set_timer(ai_l_punch_event, MOVE_PUNCH_LEFT)
pygame.time.set_timer(ai_r_punch_event, MOVE_PUNCH_RIGHT)
pygame.time.set_timer(ai_r_dodge_event, MOVE_DODGE_RIGHT)
pygame.time.set_timer(ai_l_dodge_event, MOVE_DODGE_LEFT)
in the main event loop
# -------- Main Program Loop -----------
paused = False
running = True
while running:
# --- Main Event Loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
for event in pygame.event.get():
if event.type == ai_uppercut_event:
aimovex =+ 80
activeEnemyImage = ai_uppercut_image
elif event.type == ai_l_punch_event:
aimovex =+ 80
activeEnemyImagee = ai_l_punch_image
elif event.type == ai_r_punch_event:
aimovex =- 80
activeEnemyImage = ai_r_punch_image
elif event.type == ai_r_dodge_event:
aimovey =+ 80
activeEnemyImage = ai_r_dodge_image
elif event.type == ai_l_dodge_event:
aimovey =- 80
activeEnemyImage = ai_l_dodge_image
enemy_x += aimovex
enemy_y += aimovey
#elif event.type == reloaded_event:
# when the reload timer runs out, reset it
#reloaded = True
#pygame.time.set_timer(reloaded_event, 0)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
if event.key == pygame.K_SPACE:
paused = not paused
# --- Event Processing ---
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
movex =- 40
activeCharacterImage = player_left
elif event.key == pygame.K_RIGHT:
movex =+ 40
activeCharacterImage = player_right
I suspect your issue has to do with your doubled event polling loops:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
for event in pygame.event.get():
if event.type == ai_uppercut_event:
# ...
Because there are two loops, you'll often have your events lost to the first loop which only checks if they're QUIT events and ignores all other kinds of events.
To fix this, combine the two loops and use an elif for the first non-QUIT event check:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == ai_uppercut_event:
# ...