I am making a game in pygame 1.9.2.
It's a faily simple game in which a ship moves between five columns of bad guys who attack by moving slowly downward. I am attempting to make it so that the ship moves left and right with the left and right arrow keys. Here is my code:
keys=pygame.key.get_pressed()
if keys[K_LEFT]:
location-=1
if location==-1:
location=0
if keys[K_RIGHT]:
location+=1
if location==5:
location=4
It works too well. The ship moves too fast. It is near impossible to have it move only one location, left or right. How can i make it so the ship only moves once every time the key is pressed?
You can get the events from pygame and then watch out for the KEYDOWN event, instead of looking at the keys returned by get_pressed()(which gives you keys that are currently pressed down, whereas the KEYDOWN event shows you which keys were pressed down on that frame).
What's happening with your code right now is that if your game is rendering at 30fps, and you hold down the left arrow key for half a second, you're updating the location 15 times.
events = pygame.event.get()
for event in events:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
location -= 1
if event.key == pygame.K_RIGHT:
location += 1
To support continuous movement while a key is being held down, you would have to establish some sort of limitation, either based on a forced maximum frame rate of the game loop or by a counter which only allows you to move every so many ticks of the loop.
move_ticker = 0
keys=pygame.key.get_pressed()
if keys[K_LEFT]:
if move_ticker == 0:
move_ticker = 10
location -= 1
if location == -1:
location = 0
if keys[K_RIGHT]:
if move_ticker == 0:
move_ticker = 10
location+=1
if location == 5:
location = 4
Then somewhere during the game loop you would do something like this:
if move_ticker > 0:
move_ticker -= 1
This would only let you move once every 10 frames (so if you move, the ticker gets set to 10, and after 10 frames it will allow you to move again)
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 1, otherwise 0. Use pygame.key.get_pressed() to evaluate the current state of a button and get continuous movement:
while True:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
x -= speed
if keys[pygame.K_RIGHT]:
x += speed
if keys[pygame.K_UP]:
y -= speed
if keys[pygame.K_DOWN]:
y += speed
This code can be simplified by subtracting "left" from "right" and "up" from "down":
while True:
keys = pygame.key.get_pressed()
x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * speed
y += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * speed
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 movement:
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x -= speed
if event.key == pygame.K_RIGHT:
x += speed
if event.key == pygame.K_UP:
y -= speed
if event.key == pygame.K_DOWN:
y += speed
See also Key and Keyboard event
Minimal example of continuous movement: replit.com/#Rabbid76/PyGame-ContinuousMovement
import pygame
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
rect = pygame.Rect(0, 0, 20, 20)
rect.center = window.get_rect().center
vel = 5
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
print(pygame.key.name(event.key))
keys = pygame.key.get_pressed()
rect.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * vel
rect.y += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * vel
rect.centerx = rect.centerx % window.get_width()
rect.centery = rect.centery % window.get_height()
window.fill(0)
pygame.draw.rect(window, (255, 0, 0), rect)
pygame.display.flip()
pygame.quit()
exit()
Minimal example for a single action: replit.com/#Rabbid76/PyGame-ShootBullet
import pygame
pygame.init()
window = pygame.display.set_mode((500, 200))
clock = pygame.time.Clock()
tank_surf = pygame.Surface((60, 40), pygame.SRCALPHA)
pygame.draw.rect(tank_surf, (0, 96, 0), (0, 00, 50, 40))
pygame.draw.rect(tank_surf, (0, 128, 0), (10, 10, 30, 20))
pygame.draw.rect(tank_surf, (32, 32, 96), (20, 16, 40, 8))
tank_rect = tank_surf.get_rect(midleft = (20, window.get_height() // 2))
bullet_surf = pygame.Surface((10, 10), pygame.SRCALPHA)
pygame.draw.circle(bullet_surf, (64, 64, 62), bullet_surf.get_rect().center, bullet_surf.get_width() // 2)
bullet_list = []
run = True
while run:
clock.tick(60)
current_time = pygame.time.get_ticks()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
bullet_list.insert(0, tank_rect.midright)
for i, bullet_pos in enumerate(bullet_list):
bullet_list[i] = bullet_pos[0] + 5, bullet_pos[1]
if bullet_surf.get_rect(center = bullet_pos).left > window.get_width():
del bullet_list[i:]
break
window.fill((224, 192, 160))
window.blit(tank_surf, tank_rect)
for bullet_pos in bullet_list:
window.blit(bullet_surf, bullet_surf.get_rect(center = bullet_pos))
pygame.display.flip()
pygame.quit()
exit()
import pygame
pygame.init()
pygame.display.set_mode()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); #sys.exit() if sys is imported
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_0:
print("Hey, you pressed the key, '0'!")
if event.key == pygame.K_1:
print("Doing whatever")
In note that K_0 and K_1 aren't the only keys, to see all of them, see pygame documentation, otherwise, hit tab after typing in
pygame.
(note the . after pygame) into an idle program. Note that the K must be capital. Also note that if you don't give pygame a display size (pass no args), then it will auto-use the size of the computer screen/monitor. Happy coding!
I think you can use:
pygame.time.delay(delayTime)
in which delayTime is in milliseconds.
Put it before events.
Try this:
keys=pygame.key.get_pressed()
if keys[K_LEFT]:
if count == 10:
location-=1
count=0
else:
count +=1
if location==-1:
location=0
if keys[K_RIGHT]:
if count == 10:
location+=1
count=0
else:
count +=1
if location==5:
location=4
This will mean you only move 1/10 of the time. If it still moves to fast you could try increasing the value you set "count" too.
The reason behind this is that the pygame window operates at 60 fps (frames per second) and when you press the key for just like 1 sec it updates 60 frames as per the loop of the event block.
clock = pygame.time.Clock()
flag = true
while flag :
clock.tick(60)
Note that if you have animation in your project then the number of images will define the number of values in tick(). Let's say you have a character and it requires 20 sets images for walking and jumping then you have to make tick(20) to move the character the right way.
Just fyi, if you're trying to ensure the ship doesn't go off of the screen with
location-=1
if location==-1:
location=0
you can probably better use
location -= 1
location = max(0, location)
This way if it skips -1 your program doesn't break
make something like this, but based on time delay. i call my function first time immediately and then lunch timer, and while button is pressed i call it every button_press_delta seconds
from time import time
before main loop:
button_press_delta = 0.2
right_button_pressed = 0
while not done:
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
if not right_button_pressed:
call_my_function()
right_button_pressed = 1
right_button_pressed_time_start = time()
if right_button_pressed:
right_button_pressed_time = (
time() - right_button_pressed_time_start)
if right_button_pressed_time > button_press_delta:
call_my_function()
right_button_pressed_time_start = time()
else:
right_button_pressed = 0
You should use clock.tick(10) as stated in the docs.
all of the answers above are too complexicated i would just change the variables by 0.1 instead of 1
this makes the ship 10 times slower
if that is still too fast change the variables by 0.01
this makes the ship 100 times slower
try this
keys=pygame.key.get_pressed()
if keys[K_LEFT]:
location -= 0.1 #or 0.01
if location==-1:
location=0
if keys[K_RIGHT]:
location += 0.1 #or 0.01
if location==5:
location=4
To slow down your game, use pygame.clock.tick(10)
I need some help with reseting a game I made. I've got the main loop going and the collision detection working. I'm trying to get an instant restart on the game, one that just resets the score and gets going again - I don't want it to have any user input before it restarts the game again.
MoveAsteroids() simply moves asteroids across the screen which the player has to avoid. It's also the function where score is incremented by 1 each time an asteroid is dodged.
def game_loop():
global score
while not game_over:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
spaceship.change = -5
elif event.key == pygame.K_DOWN:
spaceship.change = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
spaceship.change = 0
spaceship.y += spaceship.change
if spaceship.y > window_height - spaceship.height: # Creating borders on the window
spaceship.y = window_height - spaceship.height
elif spaceship.y < 0:
spaceship.y = 0
window.blit(bg_img, (0, 0))
MoveAsteroids()
CollisionDetection()
Score_display("Score: " + str(score * 100), white)
pygame.display.update()
def CollisionDetection():
global score
spaceship_rect = pygame.Rect(spaceship.x, spaceship.y, spaceship.width, spaceship.height)
for x in range(1, 5):
rect = pygame.Rect(asteroids[x].x, asteroids[x].y, asteroids[x].width, asteroids[x].height)
if spaceship_rect.colliderect(rect):
pass
# The part I need help with is this line of code just above^. .colliderect() returns true when a collision happens.
If I get you right you just want to reset the game. Just do
def CollisionDetection():
global score
spaceship_rect = pygame.Rect(spaceship.x, spaceship.y, spaceship.width, spaceship.height)
for x in range(1, 5):
rect = pygame.Rect(asteroids[x].x, asteroids[x].y, asteroids[x].width, asteroids[x].height)
if spaceship_rect.colliderect(rect):
score = 0
// here you reset your spaceship.x and y to the normal state
you could also have a look at sprites. It makes collision detection easier and is nice for larger games with it's groups.
So recently I have been working on a project with pygame and I was starting work on my character that you could control. The player can move with the arrow keys but cannot stop when there is no keys being pressed. My solution to the was for pygame to test if the user is not pressing left, right, up, or down then the players speed would go to zero. But for some reason when I don't have and keys pressed the player speed does still not stop. I am wondering what is wrong with my if statement. Thanks for reading this and helping!
The if statement code is this:
if event.key != K_LEFT and event.key != K_RIGHT and event.key != K_DOWN and event.key != K_UP:
playerSpeed = 0
This is the full code for the movment:
#Keypress-player movement
elif event.type == KEYDOWN:
if event.key != K_LEFT and event.key != K_RIGHT and event.key != K_DOWN and event.key != K_UP:
playerSpeed = 0
if event.key == K_LEFT:
direction = LEFT
playerSpeed = .2
elif event.key == K_RIGHT:
direction = RIGHT
playerSpeed = .2
elif event.key == K_DOWN:
direction = DOWN
playerSpeed = .2
elif event.key == K_UP:
playerSpeed = .2
direction = UP
if direction == UP:
if canMoveUp == 'true':
newPlayer = {'x':coords[0]['x'], 'y':coords[0]['y']-playerSpeed}
elif direction == DOWN:
if canMoveDown == 'true':
newPlayer = {'x':coords[0]['x'], 'y':coords[0]['y']+playerSpeed}
elif direction == LEFT:
if canMoveLeft == 'true':
newPlayer = {'x':coords[0]['x']-playerSpeed, 'y':coords[0]['y']}
elif direction == RIGHT:
if canMoveRight == 'true':
newPlayer = {'x':coords[0]['x']+playerSpeed, 'y':coords[0]['y']}
You need to completely rethink your approach. There are 2 good ways of doing key-based input.
1) Have a flag for each key, set it on KEYDOWN, and unset it on KEYUP.
2) Use the currently-pressed keys dictionary that Pygame provides.
Then you can say stuff like "if keys["UP"]:". This lets you use more than one key at a time, and makes the logic simpler.
Using pygame.event.wait() to decrease system overhead between events. But the way I'm using it seems to filter out most events. Must not be placing it in the right spot in my program.
Can someone please take a look and comment about whether I'm using it wrong?
run the game loop
LEFT=1
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN and event.button == LEFT:
print "You pressed the left mouse button at (%d, %d)" % event.pos
elif event.type == pygame.MOUSEBUTTONUP and event.button == LEFT:
print "You released the left mouse button at (%d, %d)" % event.pos
pygame.display.update()
pygame.event.wait()
pygame.event.wait returns the event in question and pops it from the queue, so you have to manage it with the other ones:
for event in [pygame.event.wait()]+pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN and event.button == LEFT:
print "You pressed the left mouse button at (%d, %d)" % event.pos
elif event.type == pygame.MOUSEBUTTONUP and event.button == LEFT:
print "You released the left mouse button at (%d, %d)" % event.pos
I'm having some issues with my game in Pygame. I wanted the cross on the top right of Windows to exit the game if clicked. But it does not seem to work. I also want it to take input from the space bar and roll the dice.
diceRoll = random.randint(1, 4)
while True:
events = pygame.event.get()
for event in events:
if event.type == pygame.KEYDOWN:
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.key == pygame.K_SPACE:
diceRoll
The rest of the code falls under this but the screen goes black when I do the loop with this.
To tell PyGame to quit correctly, you must do
if event.type == pygame.QUIT:
pygame.quit()
# perhaps force a quit using sys.exit()
If you're in a loop, you should also break that loop, using break
For the space bar event, you're already half-way there.
if event.key =0 pygame.K_SPACE:
roll_dice()
You are making a very big mistake with your first if statement. You are supposed to have the event.type lines in line with each other. You are doing this:
if event.type == pygame.KEYDOWN:
if event.type == pygame.QUIT:
when you should be doing this:
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
pass #Put your other code here
The second error is that you NEVER put pygame.quit in the while loop. It will exit the game/make the screen have nothing on it and make your program go crazy. The only logical way to safely exit the program inside the loop is with sys.exit().So your new while loop should be:
while True:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
print 'diceRoll' #Doing diceRoll alone won't do anything
pygame.quit() #This is the proper location of this function
I hope this helps you!