pygame.time.set_timer() event reset? - python

I've got a little question...
Is there a reset of some sort for the pygame.time.set_timer()?
I've got it running okay but the issue is that I need the timer to reset back to 0 whenever a certain action is performed. As it's running now, the timer will trigger the movedownauto event every second(no matter what happens), but what I want it to do is reset when a key is pressed so that it will then wait one second AFTER the key is pressed to trigger the movedownauto event.
It would be ideal if something could be put into the if event.type == USEREVENT: section.
Example below ↓
pygame.time.set_timer(USEREVENT, 1000)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
# Figure out if it was an arrow key. If so
# adjust speed.
if event.key == pygame.K_LEFT:
x_speed = -40
elif event.key == pygame.K_RIGHT:
x_speed = 40
elif event.key == pygame.K_DOWN:
y_speed = 40
# User let up on a key
elif event.type == pygame.KEYUP:
# If it is an arrow key, reset vector back to zero
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_speed = 0
elif event.key == event.key == pygame.K_DOWN:
y_speed = 0
# Move the object according to the speed vector.
x_coord += x_speed
y_coord += y_speed
if event.type == USEREVENT:
movedownauto(screen, x_coord, y_coord)
else:
drawcharacter(screen, x_coord, y_coord)
clock.tick(tickspeed)
pygame.display.flip()
Thanks!

If you want to trigger the USEREVENT only once after a keypress, remove the pygame.time.set_timer(USEREVENT, 1000) line from the top and add pygame.time.set_timer(USEREVENT, 1000, True) inside the elif event.type == pygame.KEYDOWN: block.
If you set the third argument of pygame.time.set_timer to True, the event will be added to the event queue only once (note that this feature is only avaiable in pygame version 2)
If you want the USEREVENT to happen regulary and just "reset" the timer if a KEYDOWN happens, just remove the timer and add it again.
elif event.type == pygame.KEYDOWN:
pygame.time.set_timer(USEREVENT, 0)
pygame.time.set_timer(USEREVENT, 1000)
...

Related

Why isn't 'type' attribute working with event object in Python [duplicate]

This question already has answers here:
How to get keyboard input in pygame?
(11 answers)
How can I make a sprite move when key is held down
(6 answers)
Closed 1 year ago.
I am a newbie to pygame so when I type the below code in, it shows that there is no such thing as a 'type' attribute for the event object. Can you please tell me what's the error.
# Importing libraries and other stuff
import pygame
from pygame.locals import *
# defining the funtion for drawing the block
def draw_block():
surface.fill((232,127,7))
surface.blit(block,(block_x,block_y))
pygame.display.flip()
if __name__ == "__main__":
pygame.init()
surface = pygame.display.set_mode((500,500))
surface.fill((232,127,7))
block = pygame.image.load("block_better_3.jpg").convert()
block_x = 100
block_y = 100
surface.blit(block,(block_x,block_y))
pygame.display.flip()
# Making the window run until user input
running = True
while running:
for event in pygame.event.get():
if event.type == K_ESCAPE:
running = False
elif event.type == QUIT:
running = False
elif event.key == K_UP:
block_y -= 10
elif event.key == K_DOWN:
block_y += 10
elif event.key == K_LEFT:
block_x -= 10
elif event.key == K_RIGHT:
block_x +=10
If you want to know when a key is pressed, you need to verify that the event type (event.type) is KEYDOWN and the key attribute of the event object (event.key) is the specific key (K_ESCAPE, K_UP, ...):
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
elif event.key == K_UP:
block_y -= 10
elif event.key == K_DOWN:
block_y += 10
elif event.key == K_LEFT:
block_x -= 10
elif event.key == K_RIGHT:
block_x += 10
See also pygame.event module and pygame.key module.
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.
If you want to achieve a continuously movement, you have to use pygame.key.get_pressed(). pygame.key.get_pressed() returns a list 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:
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
keys = pygame.key.get_pressed()
if keys[K_UP]:
block_y -= 1
if keys[K_DOWN]:
block_y += 1
if keys[K_LEFT]:
block_x -= 1
if keys[K_RIGHT]:
block_x += 1
Further more you need to redraw the scene in every frame:
# Importing libraries and other stuff
import pygame
from pygame.locals import *
# defining the funtion for drawing the block
def draw_block():
surface.fill((232, 127, 7))
surface.blit(block,(block_x, block_y))
pygame.display.flip()
if __name__ == "__main__":
pygame.init()
surface = pygame.display.set_mode((500,500))
clock = pygame.time.Clock()
block = pygame.image.load("block_better_3.jpg").convert()
block_x = 100
block_y = 100
# application loop
running = True
while running:
# limit the frames per second
clock.tick(100)
# handle the events
for event in pygame.event.get():
if event.type == QUIT:
running = False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
# update the game states and positions of objects
keys = pygame.key.get_pressed()
block_x += (keys[K_RIGHT] - keys[K_LEFT]) * 2
block_y += (keys[K_DOWN] - keys[K_UP]) * 2
# clear the display; draw the scene; update the display
draw_block()
pygame.quit()
The typical PyGame application loop has to:
handle the events by calling either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by calling either pygame.display.update() or pygame.display.flip()
limit the frames per second to limit CPU usage with pygame.time.Clock.tick

Pygame- Disabling a Key with pygame.event.set_blocked() crashes window and returns error

I tried to add jumping physics to my game but it is necessary that after the player jumps, the Jump-Key has to be disabled until the player lands again.
Now, there isn't any problem with the gravity, but if the player keeps holding K_UP he could fly forever and the he can fly in a paarabola as he should, so I need to disable jump until the character lands and the jump Loop loops out as expected.
I tried pygame.event.set_blocked(pygame.K_UP) but when I jump the window crashes and there is an error code: "pygame.event.set_blocked(pygame.K_UP) ValueError: event type out of range".
As I couldn't find anything about this command expect that it exists I probablay did an mistake in the Game-Loop using .block().
Here is the Game-Loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
#player1 buttons
if event.type == pygame.KEYDOWN:
#move
if event.key == pygame.K_LEFT:
playerX_change = -1
if event.key == pygame.K_RIGHT:
playerX_change = 1
#Jump
if event.key == pygame.K_UP:
playerY_change = -3
player_jump = True
pygame.event.set_blocked(pygame.K_UP)
if player_jump == True:
playerY_change += gravity
# for X player 1
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
playerX_change = 0
#for Y player 1
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
if playerY == 900:
playerY_change = 0
player_jump = False
pygame.event.set_allowed(pygame.K_UP)
I'm new to Pygame (and programming in general) and treid a lot of things and this is the result, so maybe I have also unnecessary code in it. My problem is the part with pygame.event.set_blocked and pygame.event.set_allowed which I don't know how to use.
pygame.event.set_blocked cannot block a key, it can just block an event such as KEYDOWN or KEYUP.
Anyway, you don't have to "block" anything. Uses the Boolean state variable player_jump instead:
if not player_jump and event.key == pygame.K_UP:
playerY_change = -3
player_jump = True
playerY_change += gravity

pygame - Unpress key on event.key

I am having a problem with pyGame (complete newbie here). I practice with event.key and would like to unpress / cut off key that is pressed continuously. I have tried to google it and checked this site, but that led to no promising results. Whole thing takes place in
if event.key == pygame.K_UP and isJumping == False:
(full lines 49 - 55)
## HOW TO UNPRESS K_UP IN CASE IT WAS PRESSED AND NOT RELEASED?
if event.key == pygame.K_UP and isJumping == False:
yChange -= 10
isJumping = True
elif event.key == pygame.K_UP and isJumping == True:
print("X")
This works just fine if up arrow is pressed once, but keeps on executing yChange in a loop in case it was not released - that of course is not desired at all. Could you help me with this please?
import pygame
pygame.init() # Initialize pyGame module
# Set screen dimensions
screenW = 800
screenH = 600
# Set color
AQUA = (155, 255, 255)
# Set FPS
FPS = 60
fpsClock = pygame.time.Clock()
# Set character
mainChar = pygame.image.load('p1_front.png')
mainCharX = screenH / 2 # char X position
mainCharY = screenW / 2 # char Y position
isJumping = False
xChange = 0
yChange = 0
MOVSPEED = 1
# Set backgrounds
mainBg = pygame.image.load('bg_castle.png')
mainBg = pygame.transform.scale(mainBg, (screenW, screenH))
# Set the window, param in a tuple is width / height
DISPLAYSURF = pygame.display.set_mode((screenW, screenH))
# Set window name (game title)
pygame.display.set_caption("Newbie training")
while True: # Main loop of the game
#set BG
DISPLAYSURF.blit(mainBg, (0,0))
# Events loop below
for event in pygame.event.get():
if event.type == pygame.QUIT: # Quit window when [x] is pressed
pygame.quit()
exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
xChange += MOVSPEED
elif event.key == pygame.K_LEFT:
xChange -= MOVSPEED
## HOW TO UNPRESS K_UP IN CASE IT WAS PRESSED AND NOT RELEASED?
if event.key == pygame.K_UP and isJumping == False:
yChange -= 10
isJumping = True
elif event.key == pygame.K_UP and isJumping == True:
print("X")
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or event.key == pygame.K_LEFT:
xChange = 0
if event.key == pygame.K_UP:
yChange = 0
#print(event)
mainCharX += xChange
mainCharY += yChange
DISPLAYSURF.blit(mainChar, (mainCharX, mainCharY)) # Load character
pygame.display.update() #update window
fpsClock.tick(FPS) # FPS goes always after update
If you only want the player to be able to jump 10 'units' per up press then stop in place, you could simply set yChange to 0 each frame after you add it to mainCharY.
However, if you're looking for a more robust jumping system (button is pressed, player moves up for a few frames, then stops and falls back down) more is required.
To give you an idea: what if you had some logic at the end of each frame that checks if mainCharY > 0 (player is not on ground) and, if so, subtracts some number from yChange (as if gravity were pulling them down)?
In the above case, your code should avoid the repeating up press problem. It might be easier to just test (mainCharY > 0) instead of using an isJumping variable.
It seems you're misunderstanding how the event queue and event loop work. When you press a key, a single pygame.KEYDOWN event gets added to the event queue. Calling pygame.event.get empties the event queue and puts all events into a list over which you iterate with the for loop: for event in pygame.event.get():. That means pygame doesn't know that you're still holding the key, it will only see that you've pressed UP once. It will also notice that you release the key and add a pygame.KEYUP event to the queue.
In your case you're decreasing the yChange variable to -10 when you press the UP key. In the while loop mainCharY will then be decremented by -10 each frame and the character will move upwards. As soon as you release the key, the yChange is reset to 0 and the player character stops.
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
yChange = 0
To implement jumping in your game, you should add a GRAVITY constant which you add to your y-velocity each frame to accelerate downwards. When the character touches the ground, set the y-velocity to 0 and a variable (on_ground or something similar) to True, so that you know that the player can jump. When the player presses the jump key, you can set the y-velocity to a negative value and the sprite will start to move upwards until the GRAVITY pulls him down again. Here's a complete example.
I don't think it's likely at all that pygame could miss a key event.
I think the problem is that you're not setting isJumping to false anywhere, which stops the changing of yChange forever after the first press. If I'm interpreting this correctly, the following code should work:
if event.type == pygame.KEYDOWN:
... # Your other code
if event.key == pygame.K_UP and not isJumping: # "== False" is not necessary
yChange -= 10
isJumping = True
if event.type == pygame.KEYUP:
... # Your other code
if event.key == pygame.K_UP and isJumping:
yChange = 0
isJumping = False # <-- This is the addition to the code
One thing to keep in mind is that this jumping system won't look very natural. Look to #SamHolloway's answer for more clarification on this.

Pygame image moving without proper input

I recently started tinkering a bit with pygame and I made this little piece of code (following a tutorial):
import pygame
pygame.init()
display_width = 1920
display_height = 1080
black = (0,0,0)
white = (255,255,255)
red = (255,0,0)
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("Galvadon's Adventure")
clock = pygame.time.Clock()
galvadon = pygame.image.load("galvadonModelVersion1.0.png")
def galvadonIsHere(x,y):
gameDisplay.blit(galvadon,(x,y))
x = (display_width * 0.30)
y = (display_height * 0.2)
y_change = 0
crashed = False
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
y_change = 5
elif event.key == pygame.K_UP:
y_change = -5
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
y_change = 0
y += y_change
gameDisplay.fill(white)
galvadonIsHere(x,y)
print(event)
pygame.display.update()
clock.tick(30)
pygame.quit()
quit()
and to an extent this code works, the problem is that after I move the image using the up and down arrows, the image starts to respond to any mouse movement by just gliding in the direction it last moved towards. I probably missed something out, but I just can't seem to find what it is. I looked at various websites looking for the answer but I couldn't find anyone asking a similar question, hence why I make this topic.
There are couple of things that you can do better here. But lets start with fixing the issue.
'Bug' is that after you press keys, y_change is set and never reset for next engine loop. This should help you:
...
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
y_change = 5
elif event.key == pygame.K_UP:
y_change = -5
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
y_change = 0
y += y_change
gameDisplay.fill(white)
galvadonIsHere(x, y)
print(event)
pygame.display.update()
clock.tick(30)
y_change = 0
...
Pay close attention at the last line in my snippet. Here you reset y_change so in next engine loop, whatever happens or doesn't, it wont affect position of your image.
Refactor and improve
First, you can agree that checking if event type is KEY_DOWN and nesting checks if it is particular key button is pain to read and work with. Not to mention you check if event type is KEYUP even though you know that is KEYDOWN here:
if event.type == pygame.KEYDOWN:
...
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
y_change = 0
So, what I do is define helper function, that can be usual one or lambda. Now, many would argue that lambda functions are affecting readability but here it can certainly help you with these checks.
Example:
key_pressed = lambda event, key: event.type == pygame.KEYDOWN and event.key == key
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
break
elif key_pressed(event, pygame.K_DOWN):
y_change = 5
elif key_pressed(event, pygame.K_UP):
y_change = -5
else:
y_change = 0
y += y_change
gameDisplay.fill(white)
galvadonIsHere(x, y)
print(event)
pygame.display.update()
clock.tick(30)
y_change = 0
One more thing, pay attention at condition that there was pygame.QUIT event. break exits the for loop and then while loop ends too. This way you do not process any queued events, nor you update and blit image.
Your problem is in the while loop. The if statement for keyup is in the if statement for keydown, so it is preventing it from working. The following solves your problem:
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
y_change = 5
elif event.key == pygame.K_UP:
y_change = -5
else:
y_change = 0
Hope this helps.

Pygame - when i push a button and then another

First of all, here is my code:
while not crashed:
curr_event = pygame.event.get()
if (len(curr_event) == 2):
print curr_event[0],'\n',curr_event[1],'\n\n\n'
for event in curr_event:
if event.type == pygame.KEYUP and not len(curr_event) == 1:
continue
if event.type == pygame.QUIT:
crashed = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change = -5
elif event.key == pygame.K_RIGHT:
x_change = 5
if event.type == pygame.KEYUP:
x_change = 0
x += x_change
Display.fill((255, 255, 255))
car(x,y)
pygame.display.update()
clock.tick(100)
This should be a try to move smoothly from right to left and opposite.
All is good when for example, I press "left key" and wait 2 seconds and then press "right key".
But - when I press "left key", leave the key, and just after it press "right key" - the "key up" is smashing my right press and the player stops on the screen.
I thought it's because created a list of 2 indexes when the first have the "right press" and the second have the "key up", so i tried to do:
if event.type == pygame.KEYUP and not len(curr_event) == 1:
continue
As you can see in my code.
Well... sometimes it's the situation... But sometimes it doesn't creates a list with two indexes - but smash the "right key" pressing..
How can I fix it and what is the issue?
Moving the mouse, pressing buttons and other actions counts as events and are put in the queue, so the code if event.type == pygame.KEYUP and not len(curr_event) == 1: continue might be unreliable.
Solution
You could check the state of the button (if it's being held down or not) rather than just when it's pressed and released. pygame.key.get_pressed() returns a list of all the keys current state: 0 if not being pressed and 1 if it's being pressed. A key position in the list is it's integer constant representation.
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
x_change = -5
elif key[pygame.K_RIGHT]:
x_change = 5
This doesn't keep track on was what pressed first or last, so if you're holding down both keys it'll go left. I've tried another solution that works pretty well. It basically a list that keeps track of the key presses in a list and moves the player based on the last key pressed.
import pygame
pygame.init()
screen = pygame.display.set_mode((500, 200))
clock = pygame.time.Clock()
x, y = 100, 100
car = pygame.Surface((32, 32))
velocity_dx = []
speed = 5
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
velocity_dx.insert(0, -speed)
elif event.key == pygame.K_RIGHT:
velocity_dx.insert(0, speed)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
velocity_dx.remove(-speed)
elif event.key == pygame.K_RIGHT:
velocity_dx.remove(speed)
try:
x += velocity_dx[0] # Take the first value from the list
except IndexError: # if list is empty, catch the IndexError.
pass
screen.fill((255, 255, 255))
screen.blit(car, (x, y))
pygame.display.update()
# print(velocity_dx) # Uncomment to see what's happening in action!

Categories

Resources