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')
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
# [...]
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!
I am currently trying to code a series of rooms, here referred to as nodes. You start out in the first room/node (node1) facing north, and the image for north is displayed. If you press left/right/down on the arrow keys you face towards the corresponding point on the compass and the new image for that direction is displayed. If you press the up arrow key while facing north in the first node you proceed to the second node.
However when I execute this code, any key press results in me proceeding to the second node. I looked through and I feel like the use of AND statements ought to make this a non-issue but clearly I am missing something within these loops.
Thanks in advance for your help...
def node1():
node1_here = True
node1_look_north = True
node1_look_south = False
node1_look_east = False
node1_look_west = False
node1_north_image = pygame.image.load('node1north.jpg')
node1_south_image = pygame.image.load('node1south.jpg')
node1_east_image = pygame.image.load('node1east.jpg')
node1_west_image = pygame.image.load('node1west.jpg')
while node1_here:
while node1_look_north:
screen.blit(node1_north_image, (0, 0))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
elif event.type == pygame.KEYDOWN and pygame.K_UP:
node2()
elif event.type == pygame.KEYDOWN and pygame.K_DOWN:
node1_look_south = True and not node1_look_north
elif event.type == pygame.KEYDOWN and pygame.K_LEFT:
node1_look_east = True and not node1_look_north
elif event.type == pygame.KEYDOWN and pygame.K_RIGHT:
node1_look_west = True and not node1_look_north
while node1_look_south:
screen.blit(node1_south_image, (0, 0))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
elif event.type == pygame.KEYDOWN and pygame.K_DOWN:
node1_look_north = True and not node1_look_south
elif event.type == pygame.KEYDOWN and pygame.K_LEFT:
node1_look_west = True and not node1_look_south
elif event.type == pygame.KEYDOWN and pygame.K_RIGHT:
node1_look_east = True and not node1_look_south
while node1_look_east:
screen.blit(node1_east_image, (0, 0))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
elif event.type == pygame.KEYDOWN and pygame.K_DOWN:
node1_look_west = True and not node1_look_east
elif event.type == pygame.KEYDOWN and pygame.K_LEFT:
node1_look_south = True and not node1_look_east
elif event.type == pygame.KEYDOWN and pygame.K_RIGHT:
node1_look_north = True and not node1_look_east
while node1_look_west:
screen.blit(node1_west_image, (0, 0))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
elif event.type == pygame.KEYDOWN and pygame.K_DOWN:
node1_look_east = True and not node1_look_west
elif event.type == pygame.KEYDOWN and pygame.K_LEFT:
node1_look_north = True and not node1_look_west
elif event.type == pygame.KEYDOWN and pygame.K_RIGHT:
node1_look_south = True and not node1_look_west
def node2():
node2_here = True
node2_look_north = True
node2_north_image = pygame.image.load('node2north.jpg')
while node2_here:
while node2_look_north:
screen.blit(node2_north_image, (0, 0))
pygame.display.update()
Explanation:
pygame.K_UP
^this is a constant and is always true. As such,
elif event.type == pygame.KEYDOWN and pygame.K_UP:
^this will always resolve to True when you press any key, resulting in
node2()
being executed.
Solution:
elif event.type == pygame.KEYDOWN and event.key == pygame.K_UP:
^this will check to see if the key pressed is K_UP
Hope that helps!
Reference:
Pygame key docs
import pygame
finish = False
while not finish:
for event in pygame.event.get():
if event.type == pygame.QUIT:
finish = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
print "A"
if event.key == pygame.K_RIGHT:
print "B"
if event.key == pygame.K_LEFT:
print "C"
Why doesn't this let me press 2 buttons at the same time and how do I make a code that does that?
The keyboard events (e.g. pygame.KEYDOWN) occure only once when a button is pressed.
Use pygame.key.get_pressed() to continuously evaluate the states of the buttons. e.g.:
finish = False
while not finish:
for event in pygame.event.get():
if event.type == pygame.QUIT:
finish = True
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
print "A"
if keys[pygame.K_RIGHT]:
print "B"
if keys[pygame.K_LEFT]:
print "C"
Or if you would rather get a list:
finish = False
while not finish:
for event in pygame.event.get():
if event.type == pygame.QUIT:
finish = True
keys = pygame.key.get_pressed()
if any(keys):
kmap = {pygame.K_UP : "A", pygame.K_RIGHT : "B", pygame.K_LEFT : "C"}
sl = [kmap[key] for key in kmap if keys[key]]
print sl
Try this:
import pygame
finish = False
while not finish:
for event in pygame.event.get():
if event.type == pygame.QUIT:
finish = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
print "A"
if event.key == pygame.K_RIGHT:
print "B"
if event.key == pygame.K_LEFT:
print "C"
In your version you're iterating over pygame.event.get() and you evaluate only the last event in the for loop (apart from the quit logic), meaning you only evaluate the last keypress. Move the code into the loop and you can evaluate all the events.
If you want to detect multiple keypresses then use pygame.key.get_pressed()
finish = False
while not finish:
for event in pygame.event.get():
if event.type == pygame.QUIT:
finish = True
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
print("C")
if keys[pygame.K_RIGHT]:
print("B")
if keys[pygame.K_UP]:
print("A")
I am working on a game called HypoPixel using ray casting, and I found yet another bug. I can not get the game to open, it just crashes, and when I use it in IDE it does not give an error.
I just used the simple
elif event.type == pygame.MOUSEBUTTONDOWN:
procedure, but it keeps crashing ever since I added this
pygame.init()
Screen = "None"
Sobj = "None"
Width = 800
Height = 600
Time = 0
MouseX, MouseY = pygame.mouse.get_pos()
Frame = pygame.display.set_mode((Width,Height))
pygame.display.set_caption("HypoPixel")
FPS = pygame.time.Clock()
def button(DisplayText,ButtonPosition,Function):
pass
def mapX(MapXPos):
pass
def mapY(MapYPos):
pass
def mapZ(MapZPos):
pass
def ReDisplayItem():
if Sobj == "None":
Raycast('Assets/Textures/Extra/ItemBox.png',0,0,160,160)
elif Sobj == "Loom":
Raycast('Assets/Textures/Extra/IBO.png',0,0,160,160)
Raycast('Assets/Textures/Blocks/loom_side.png',10,10,140,140)
def Raycast(TTR, RayXPos, RayYPos, RaySizeX, RaySizeY):
RaycastThis = pygame.image.load(TTR)
RaycastThis = pygame.transform.scale(RaycastThis,(RaySizeX,RaySizeY))
Frame.blit(RaycastThis, (RayXPos, RayYPos))
Loop = True
Raycast('Assets/Textures/Screens/Skybox/Earth.png',0,0,800,600)
Raycast('Assets/Textures/Extra/ItemBox.png',0,0,160,160)
while Loop == True:
Time = Time + 1
while Sobj == "None":
RCT = 'Assets/Textures/Blocks/air.png'
while Sobj == "Loom":
RCT = 'Assets/Textures/Blocks/loom_side.png'
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
Raycast(RCT,MouseX,MouseY,160,160)
elif event.type == pygame.KEYDOWN:
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
exit()
elif event.type == pygame.KEYDOWN and event.key == pygame.K_0:
Raycast('Assets/Textures/Extra/ItemBox.png',0,0,160,160)
Sobj = "None"
elif event.type == pygame.KEYDOWN and event.key == pygame.K_1:
Raycast('Assets/Textures/Blocks/loom_side.png',10,10,140,140)
Sobj = "Loom"
if Time >= 2400 and Time < 4800:
Raycast('Assets/Textures/Screens/Skybox/EarthNight.png',0,0,800,600)
ReDisplayItem()
elif Time >= 4800:
Time = 0
Raycast('Assets/Textures/Screens/Skybox/Earth.png',0,0,800,600)
ReDisplayItem()
pygame.display.update()
FPS.tick(60)
I expected the application to open like normal and with the new added ability of painting blocks for a Alpha Test of my game, but it crashed, with no sign of an error.
NeverMind, I realized that I had to use
if
and
elif
instead of while loops, sorry for the clutter Stack OverFlow Community. :(