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
Related
I've been trying to get pygame to detect keypresses so later on I can move a character around on the screen. I'm new to coding so I might just be missing something simple, but I can't figure out what's wrong with the code, should I switch to pygame.key.get_pressed() or something instead? thanks in advance.
running = True
while running:
screen.fill((0,0,0))
# set background
screen.blit(background, (0,0))
player(playerX, playerY)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# detecting key presses
if event.type == pygame.KEYDOWN:
if event.type == pygame.K_LEFT:
print("left")
if event.type == pygame.K_RIGHT:
print("right")
if event.type == pygame.K_UP:
print("up")
if event.type == pygame.KEYUP:
if event.type == pygame.K_LEFT or event.type == pygame.K_RIGHT:
print("stop")
pygame.display.update()
It is a matter of Indentation. You must evaluate the events in the event loop instead of the application loop.
If you want to determine if a certain key is pressed, the you've to verify if the event type is pygame.KEYDOWN (or pygame.KEYUP for button release) and if the .key attribute of the event is equal the key enumerator.
running = True
while running:
screen.fill((0,0,0))
# set background
screen.blit(background, (0,0))
player(playerX, playerY)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# INDENTATION
#-->|
# detecting key presses
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT: #<-- "key" instead of "type"
print("left")
if event.key == pygame.K_RIGHT: #<-- "key" instead of "type"
print("right")
if event.key == pygame.K_UP: #<-- "key" instead of "type"
print("up")
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT: #<-- "key" instead of "type"
print("stop")
#-->|
# INDENTATION
However, I recommend to use pygame.key.get_pressed() instead of the KEYDOWN event.
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
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.
clock = pygame.time.Clock()
velocity = 5
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
playerX += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * velocity
playerY += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * velocity
screen.blit(background, (0,0))
player(playerX, playerY)
pygame.display.update()
You need to indent this part of your code to be in the for loop:
if event.type == pygame.KEYDOWN:
if event.type == pygame.K_LEFT:
print("left")
if event.type == pygame.K_RIGHT:
print("right")
if event.type == pygame.K_UP:
print("up")
if event.type == pygame.KEYUP:
if event.type == pygame.K_LEFT or event.type == pygame.K_RIGHT:
print("stop")
pygame.display.update()
Otherwise, the event will always only be the last event from the pygame.event.get() list.
So basically, from
running = True
while running:
screen.fill((0,0,0))
# set background
screen.blit(background, (0,0))
player(playerX, playerY)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# detecting key presses
if event.type == pygame.KEYDOWN:
if event.type == pygame.K_LEFT:
print("left")
if event.type == pygame.K_RIGHT:
print("right")
if event.type == pygame.K_UP:
print("up")
if event.type == pygame.KEYUP:
if event.type == pygame.K_LEFT or event.type == pygame.K_RIGHT:
print("stop")
pygame.display.update()
to:
running = True
while running:
screen.fill((0,0,0))
# set background
screen.blit(background, (0,0))
player(playerX, playerY)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
print("left")
if event.key == pygame.K_RIGHT:
print("right")
if event.key == pygame.K_UP:
print("up")
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
print("stop")
pygame.display.update()
(Notice the event.keys I replaced part of your event.types with.)
I'm trying to build a little python program using pygame that detects when the shift key is pressed but it isn't working it isn't printing the debug print that I put in there here is my code
while running:
screen.fill((0, 0, 0))
x, y = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
rectangle = "green"
if event.type == pygame.MOUSEBUTTONUP:
rectangle = "red"
if event.type == pygame.KEYDOWN:
if event.key == pygame.KMOD_SHIFT:
modshift = "down"
print("debug shift")
if event.key == pygame.KMOD_CTRL:
modctrl = "down"
if event.type == pygame.KEYUP:
if event.key == pygame.KMOD_SHIFT:
modshift = "up"
Instead of using if event.key == pygame.KMOD_SHIFT: try using:
if event.mod & pygame.KMOD_SHIFT:
The documentation explains it pretty well here: https://www.pygame.org/docs/ref/key.html#key-modifiers-label
The modifier information is contained in the mod attribute of the pygame.KEYDOWN and pygame.KEYUP events. The mod attribute is a bitmask of all the modifier keys that were in a pressed state when the event occurred. The modifier information can be decoded using a bitwise AND (except for KMOD_NONE, which should be compared using equals ==).
Basically, the & operator checks that pygame.KMOD_SHIFT was the button clicked.
Final code would look like:
while running:
screen.fill((0, 0, 0))
x, y = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
rectangle = "green"
if event.type == pygame.MOUSEBUTTONUP:
rectangle = "red"
if event.type == pygame.KEYDOWN:
if event.mod & pygame.KMOD_SHIFT:
modshift = "down"
print("debug shift")
if event.mod & pygame.KMOD_CTRL:
modctrl = "down"
if event.type == pygame.KEYUP:
if event.mod & pygame.KMOD_SHIFT:
modshift = "up"
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')
For some reason I can't get pygame.MOUSEBUTTONDOWN to register on pygame.event.get().
events_list = pygame.event.get()
for event in events_list:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_i:
menu_close = True
if event.type == pygame.MOUSEBUTTONDOWN:
print(event.button)
While pygame.mouse.get_pressed() returns when I press any button, I don't understand what I'm doing wrong with the code highlighted above.
It is a matter of Indentation. In your code event.type == pygame.MOUSEBUTTONDOWN is evaluated only, if event.type == pygame.KEYDOWN is True. That's impossible, since event.type can't have 2 states at once.
Instead of:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_i:
menu_close = True
if event.type == pygame.MOUSEBUTTONDOWN:
print(event.button)
It has to be:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_i:
menu_close = True
if event.type == pygame.MOUSEBUTTONDOWN:
print(event.button)
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")