I was learning python and trying to make snake game using pygame library. I made a rectangle which moves using the pressing of keys but rather than moving one block it moves to the end of the block.
Whenever i press in any direction whether it be up , left, right, or down rather than moving 1 box size it moves to the end of the other direction
Could someone tell me why that happens.
import pygame
box_size = 50
num_box = 15
color1 = (169, 215, 81)
color2 = (169,250,81)
x = 0
y = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
break
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
if x < width - box_size:
x = x + box_size
if keys[pygame.K_LEFT]:
if x > 0:
x = x - box_size
if keys[pygame.K_UP]:
if y > 0:
y = y - box_size
if keys[pygame.K_DOWN]:
if y < height - box_size:
y = y + box_size
print(x,y)
for i in range(0,num_box):
if i %2 == 0:
for j in range(0,num_box):
if j%2 == 0:
pygame.draw.rect(win, color1, (box_size*j, box_size*i, box_size, box_size))
else:
pygame.draw.rect(win, color2, (box_size * j, box_size * i, box_size, box_size))
else:
for k in range(0,num_box):
if k%2 == 0:
pygame.draw.rect(win, color2, (box_size*k, box_size*i, box_size, box_size))
else:
pygame.draw.rect(win, color1, (box_size * k, box_size * i, box_size, box_size))
pygame.draw.rect(win, (0, 0, 250), (x, y, box_size, box_size))
# # rect(surface, color, (left, top, width, height))
pygame.display.update()
pass
See pygame.time.Clock.tick():
This method should be called once per frame.
Use pygame.time.Clock to control the frames per second and thus the game speed. The method tick() of a pygame.time.Clock object, delays the game in that way, that every iteration of the loop consumes the same period of time. e.g.:
clock = pygame.time.Clock()
while True:
clock.tick(100)
for event in pygame.event.get():
# [...]
If you want to move the object step by step you need to use KEYDOWN event instead of pygame.key.get_pressed():
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# INDENTATION
#-->|
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
if x < width - box_size:
x = x + box_size
if event.key == pygame.K_LEFT:
if x > 0:
x = x - box_size
if event.key == pygame.K_UP:
if y > 0:
y = y - box_size
if event.key == pygame.K_DOWN:
if y < height - box_size:
y = y + box_size
See How to get keyboard input in pygame? and How can I make a sprite move when key is held down.
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.
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 like jumping or spawning a bullet or a step-by-step movement.
Related
I'm fairly new to Python (and programming in general), and brand-new to Pygame.
My desired outcome is: if I'm holding the A key, the character moves left. If I continue holding the A key and additionally hold down the W key, the character moves up. If I release the W key but not the A key, the character continues left.
This is the main loop:
direction = 0 #0 left, 1 right, 2 up, 3 down
move = False
running = True
while running:
#cap framerate
clock.tick(FPS)
#locational updates
dx = 0
dy = 0
if move:
if direction == 0:
dx = -SPEED
if direction == 1:
dx = SPEED
if direction == 2:
dy = -SPEED
if direction == 3:
dy = SPEED
#draw background
screen.fill(GREY)
player.move(dx, dy)
player.update()
player.draw(screen)
#handle keypresses
keys = pygame.key.get_pressed()
if keys[pygame.K_a] or keys[pygame.K_LEFT]:
direction = 0
move = True
elif keys[pygame.K_d] or keys[pygame.K_RIGHT]:
direction = 1
move = True
elif keys[pygame.K_w] or keys[pygame.K_UP]:
direction = 2
move = True
elif keys[pygame.K_s] or keys[pygame.K_DOWN]:
direction = 3
move = True
else:
move = False
#event handler
for event in pygame.event.get():
if event.type == QUIT:
running = False
#show all the things
pygame.display.update()
The actual outcome is: the S key can be overridden as desired, since it's at the bottom of the if statements. The W key can be overridden by any key except S, D can only be overridden by A, and A cannot be overridden at all.
I tried using KEYDOWN and KEYUP, but that was even further from what I wanted. I also tried changing the elifs to ifs, but that just reversed the hierarchy, which makes sense. I've also searched for the answer, but I haven't found anything which specifically relates to my problem.
I understand that the root of the problem is that Python reads the code line by line, but with my limited knowledge I don't know how to get around that. Also, I'm specifically trying to avoid diagonal movement. Thanks for any help you guys can give.
So with help from #Rabbid76, I found this solution, in case anyone else has this problem (though there's probably a better way to do it):
First, instead of using the direction and move variables, I used these two:
#save the last pressed key
last_key = None
#create a list of key presses
key_list = []
Second, this section now uses the last_key variable to determine direction:
running = True
while running:
#[...]
#locational updates
dx, dy = 0, 0
#check which key should be controlling movement
if last_key in [pygame.K_a, pygame.K_LEFT]:
dx = -SPEED
elif last_key in [pygame.K_d, pygame.K_RIGHT]:
dx = SPEED
elif last_key in [pygame.K_w, pygame.K_UP]:
dy = -SPEED
elif last_key in [pygame.K_s, pygame.K_DOWN]:
dy = SPEED
else:
dx, dy = 0, 0
Finally, my event handler now adds KEYDOWN events to the list stored in the key_list variable, then uses that list during KEYUP events to see if it should revert to a previous direction:
running = True
while running:
#[...]
for event in pygame.event.get():
#handle keypresses
if event.type == pygame.KEYDOWN:
if event.key in [pygame.K_a, pygame.K_LEFT]:
last_key = event.key
#avoid redundancy in list of key presses
if last_key in key_list:
key_list.remove(last_key)
#add the key to the list
key_list.append(last_key)
if event.key in [pygame.K_d, pygame.K_RIGHT]:
last_key = event.key
if last_key in key_list:
key_list.remove(last_key)
key_list.append(last_key)
if event.key in [pygame.K_w, pygame.K_UP]:
last_key = event.key
if last_key in key_list:
key_list.remove(last_key)
key_list.append(last_key)
if event.key in [pygame.K_s, pygame.K_DOWN]:
last_key = event.key
if last_key in key_list:
key_list.remove(last_key)
key_list.append(last_key)
if event.type == pygame.KEYUP:
if event.key == last_key: #this is important or else the character stops moving if you, say, hold right, then left, then release right
try:
#check the second-to-last key to see if it is still pressed
if pygame.key.get_pressed()[key_list[len(key_list) - 2]]:
#if so, that is now the key to use
last_key = key_list[len(key_list) - 2]
#check if third-to-last key is still pressed
elif pygame.key.get_pressed()[key_list[len(key_list) - 3]]:
last_key = key_list[len(key_list) - 3]
#check if fourth-to-last key is still pressed
elif pygame.key.get_pressed()[key_list[len(key_list) - 4]]:
last_key = key_list[len(key_list) - 4]
#this breaks if you mix arrows and wasd, but you could add more of the above checks to fix that if it's an issue
else:
last_key = None
except:
last_key = None
if event.type == QUIT:
running = False
You have to use the KEYDOW and KEYUP event. The last key pressed defines the direction of the movement. You need to implement a queue of hit keys.
Create a dictionary that maps keys to direction vectors and an empty direction queue:
direction_map = {
pygame.K_a: (-1, 0), pygame.K_LEFT: (-1, 0), pygame.K_d: (1, 0), pygame.K_RIGHT: (1, 0),
pygame.K_w: (0, -1), pygame.K_UP: (0, -1), pygame.K_s: (0, 1), pygame.K_DOWN: (0, 1)
}
direction_queue = []
Add or move a direction to the end of the queue in the 'KEYDOWN' event:
while run:
for event in pygame.event.get():
# [...]
if event.type == pygame.KEYDOWN:
new_direction = direction_map.get(event.key)
if new_direction in direction_queue:
direction_queue.remove(new_direction)
if new_direction:
direction_queue.append(new_direction)
Removes a direction vector from the queue in the 'KEYUP' event:
while run:
for event in pygame.event.get():
# [...]
if event.type == pygame.KEYUP:
release_direction = direction_map.get(event.key)
if release_direction in direction_queue:
direction_queue.remove(release_direction)
Set the movement depending on the last item in the queue:
while run:
# [...]
dx, dy = direction_queue[-1] if direction_queue else (0, 0)
Minimal example:
import pygame
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
rect = pygame.Rect(190, 190, 20, 20)
speed = 1
direction_map = {
pygame.K_a: (-1, 0), pygame.K_LEFT: (-1, 0), pygame.K_d: (1, 0), pygame.K_RIGHT: (1, 0),
pygame.K_w: (0, -1), pygame.K_UP: (0, -1), pygame.K_s: (0, 1), pygame.K_DOWN: (0, 1)
}
direction_queue = []
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
new_direction = direction_map.get(event.key)
if new_direction in direction_queue:
direction_queue.remove(new_direction)
if new_direction:
direction_queue.append(new_direction)
if event.type == pygame.KEYUP:
release_direction = direction_map.get(event.key)
if release_direction in direction_queue:
direction_queue.remove(release_direction)
dx, dy = direction_queue[-1] if direction_queue else (0, 0)
rect.x = (rect.x + dx * speed) % 400
rect.y = (rect.y + dy * speed) % 400
window.fill(0)
pygame.draw.rect(window, "red", rect)
pygame.display.flip()
pygame.quit()
exit()
I'm creating 2-player PONG game with pygame.I have my Racquets on both sides.
One of them move with W and S and another with UP and DOWN arrow.
I'm using this code to move Racquets:
chx = 0.051
chy = 0.051
def ychangeneg():
global y
if y <= 4:
return
else:
y -= chy
return
def ychangepos():
global y
if y >= 327:
return
else:
y += chy
return
def y1changeneg():
global y1
if y1 <= 4:
return
else:
y1 -= chy
return
def y1changepos():
global y1
if y1 >= 327:
return
else:
y1 += chy
return
while True:
for event in pygame.event.get():
keyQ = pygame.key.get_pressed()
if event.type == pygame.QUIT:
system("cls")
quit()
keyboard.add_hotkey("w",lambda:ychangeneg())
keyboard.add_hotkey("s",lambda:ychangepos())
keyboard.add_hotkey("up",lambda:y1changeneg())
keyboard.add_hotkey("down",lambda:y1changepos())
chy variable changes y of Racquet and moves it.But I have these problems:
When I start holding a key,Racquet starts moving with delay and then becomes faster
When I holding 2 key (W and UP arrow) at a same time, Racquets don't move
At first, I found some codes that using key= pygame.key.get_pressed() but when you hold a key with this code, It moves but not continuously.
Do not mix the pygame.key module with the python keyboard module.
See How can I make a sprite move when key is held down and that changes the y-coordinate, depending on the keys pressed:
def move_y(y, keys, up, down):
new_y = y + (keys[down] - keys[up]) * chy
return max(4, min(327, new_y))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
system("cls")
quit()
keyQ = pygame.key.get_pressed()
y = move_y(y, keyQ, pygame.K_w, pygame.K_s)
y1 = move_y(y1, keyQ, pygame.K_UP, pygame.K_DOWN)
Minimal example:
import pygame
pygame.init()
window = pygame.display.set_mode((400, 350))
clock = pygame.time.Clock()
paddle1 = pygame.Rect(10, 0, 10, 20)
paddle1.centery = window.get_rect().centery
paddle2 = pygame.Rect(380, 0, 10, 20)
paddle2.centery = window.get_rect().centery
chy = 10
def move_y(y, keys, up, down):
new_y = y + (keys[down] - keys[up]) * chy
return max(4, min(327, new_y))
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keyQ = pygame.key.get_pressed()
paddle1.y = move_y(paddle1.y, keyQ, pygame.K_w, pygame.K_s)
paddle2.y = move_y(paddle2.y, keyQ, pygame.K_UP, pygame.K_DOWN)
window.fill(0)
pygame.draw.rect(window, (255, 255, 255), paddle1)
pygame.draw.rect(window, (255, 255, 255), paddle2)
pygame.display.flip()
clock.tick(60)
pygame.quit()
exit()
I'd suggest not using the keyboard module. Instead look, which key is pressed by using pygame.key.get_pressed(). Check if the key is in there, and if so then change the coordinates.
somewhat like this:
pressed_keys = pygame.key.get_pressed()
if pressed_keys[pygame.UP]: # this evaluates to true if the up key is pressed
ychangeneg()
if pressed_keys[pygame.DOWN]:
ychangepos()
# and so on...
When SPACE or DOWN is held, then the sprite disappears because of the scrolling background. When the background is a still image, it works. Furthermore the animation is fast so I used a timer to make it slower, but when the DOWN button is let go of, the screen speeds up.
I have tried searching up syntax online and it works when the background image is still.
from time import sleep as s
import random
import pygame
pygame.init()
import time
window = pygame.display.set_mode((1000, 500))
pygame.display.set_caption("Practice Game")
image = pygame.image.load('pixel6.png')
image = pygame.transform.scale(image, (1000, 500))
jump1 = [pygame.image.load('adventurer-jump-00.png'),pygame.image.load('adventurer-jump-01.png'),pygame.image.load('adventurer-jump-02.png'),pygame.image.load('adventurer-jump-03.png'), pygame.image.load('adventurer-smrslt-00.png'),pygame.image.load('adventurer-smrslt-01.png'),pygame.image.load('adventurer-smrslt-02.png'),pygame.image.load('adventurer-smrslt-03.png')]
run2 = [pygame.image.load('adventurer-run-00.png'), pygame.image.load('adventurer-run-01.png'),pygame.image.load('adventurer-run-02.png'),pygame.image.load('adventurer-run-03.png')]
slide1 = [pygame.image.load('adventurer-slide-00.png'),pygame.image.load('adventurer-slide-01.png'),pygame.image.load('adventurer-stand-00.png'),pygame.image.load('adventurer-stand-01.png'),pygame.image.load('adventurer-stand-02.png')]
#attack = [pygame.image.load('
imagex = 0
imagex2 = image.get_width()
clock = pygame.time.Clock()
run = True
run1 = True
jump2 = True
slide2 = True
imagess = True
x = 40
y = 391
FPS = 60
speed = 0.6
jumpcount = 10
jumpcount1 = 0
runcount = 0
slide = 0
isJump = False
down = False
class obstacles(object):
img = [pygame.image.load('img.png')]
def __init__(self, x,y, width, height):
self.x = x
self.y =y
self.width = width
self.height = height
self.hitbox = (x,y,width,height)
self.count = 0
def draw(self, window):
self.hitbox = (self.x + 5, self.y + 5, self.width, self.height)
if self.count >= 8:
self.count = 0
self.count +=1
window.blit(pygame.transform.scale(self.img[self.count//1000], (150,100)), (self.x, self.y))
pygame.draw.rect(window, (255,0,0), self.hitbox, 2)
objects = []
def keepdrawing():
global runcount, slide, run1,jumpcount1
window.blit(image, (imagex,0))
window.blit(image, (imagex2,0))
for object1 in objects:
object1.draw(window)
if runcount >= 3:
runcount = 0
if run1 == True:
window.blit(run2[runcount],(int(x),int(y)))
runcount +=1
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN and y == 391:
run1 = False
if slide >= 4:
slide = 0
if slide2:
window.blit(slide1[slide],(int(x),int(y)))
slide +=1
if event.key == pygame.K_SPACE:
run1 = False
if jumpcount1 >= 7:
jumpcount1 = 0
if jump2 and y!=391:
window.blit(jump1[jumpcount1],(int(x),int(y)))
jumpcount1 +=1
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN:
run1 = True
if event.key == pygame.K_SPACE:
run1=True
pygame.display.update()
pygame.time.set_timer(pygame.USEREVENT+1, 500)
pygame.time.set_timer(pygame.USEREVENT+2, random.randrange(1000,2000))
obstacles = obstacles(1050,300,64,64)
while run:
clock.tick(60)
imagex -= 2
imagex2 -= 2
if imagex < image.get_width() * -1:
imagex = image.get_width()
if imagex2 < image.get_width() * -1:
imagex2 = image.get_width()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.USEREVENT+1:
speed += 1
if event.type == pygame.USEREVENT+2:
objects.append(obstacles)
for object1 in objects:
object1.x -= 1
if object1.x < -100:
objects.pop(objects.index(object1))
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if not(isJump):
if keys[pygame.K_SPACE]:
isJump =True
else:
if jumpcount >= -10:
neg=1
if jumpcount <0:
neg = -1
s(0.01)
y-= (jumpcount**2)*0.3*neg
s(0.01)
jumpcount -=1
else:
isJump = False
jumpcount = 10
keepdrawing()
I cannot test your game due to the lot of images I do not have, but I think you are misunderstanding how the event system works, or at least you have neglected a case.
When you press a key, the KEYDOWN is emitted, and when you lift the key, the KEYUP is emitted.
These event are instantaneous (well, not really, but they are very fast), and are catched by the event manager only when the status of the button changes (from pressed to unpressed and viceversa). You must not rely on them to check if a button is kept pressed. Have a look at this post for a better understanding.
With this in mind, let's see what happening to your keepdrawing function. Here the relevant parts:
def keepdrawing():
#...
if run1 == True:
#blitting
if event.type == pygame.KEYDOWN:
run1 = False
#stuff and blitting
if event.type == pygame.KEYUP:
run1 = True
As you can see, when you hold the button pressed (that is, between KEYDOWN and KEYUP events) the boolean run1 is False. So nothing is blit. That's why your image disappear.
You should still be able to see the beginning of the movement: the frame when you press the button the KEYDOWN event is catched and that part of the code is executed. But the frame later, nothing is blit because run1 is False and there is no event to be catched.
I do not have a working solution, as I said I cannot test the game, but I would suggest at least to be sure that keepdrawing always draw something. Try to figure what you should draw when run1 is False and add a couple of lines about it in keepdrawing.
As a more general advice, do not use the pygame event system in the keepdrawing function. Just check if a button is pressed like you do here:
keys = pygame.key.get_pressed()
I am coding a top-down shooter game, and was recently trying to figure out a way to continuously move my character while holding down a key. I was searching the internet to find a way, and found pygame.key.get_pressed(), this worked great until I tried to create borders so you couldn't escape the sides of the screen. I have basically worked out the problem being while your holding down the movement keys, pygame can't check the x and y coordinates of your player, therefore it allows the player to move out of bounds even when you add something like if x >= 0:.
I am asking if there is a way to create a border for the sides of the screen, while holding down a movement button with pygame.key.get_pressed(), or if there is a good alternative for moving.
Some of the code :
if eventHandler == "LEVEL1":
# SEE IF PLAYER QUIT AND PROCEED TO QUIT
for event in pygame.event.get():
if event.type == pygame.QUIT:
loop = False
if event.type == pygame.KEYDOWN:
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
movingUP = True
if keys[pygame.K_DOWN]:
movingDOWN = True
if keys[pygame.K_LEFT]:
movingLEFT = True
if keys[pygame.K_RIGHT]:
movingRIGHT = True
if event.type == pygame.KEYUP:
movingUP = False
movingDOWN = False
movingLEFT = False
movingRIGHT = False
x_change = 0
y_change = 0
if movingUP == True:
y_change -= 5
if movingDOWN == True:
y_change += 5
if movingLEFT == True:
x_change -= 5
if movingRIGHT == True:
x_change += 5
# UPDATES EVERY TIME GAME LOOPS
pygame.display.update()
clock.tick(60)
x += x_change
y += y_change
if eventHandler == "LEVEL1":
w.blit(level1map, (0, 0))
w.blit(player, (x, y))
pygame.display.update()
I have already tried adding (with 16 being the border)
if x >= 16:
x_change = 0
movingLEFT = 0
and so on with all of the directions. I tried this for basically anywhere it would make sense in the code. I have also tried putting
if keys[pygame.K_LEFT] and x >= 16:
movingLEFT = True
"and variable >= border" everywhere it might make a border, but still no results.
Any way to create a border that works or an alternative for moving?
[...] while your holding down the movement keys, pygame can't check the x and y coordinates of your player, [...]
No.
While your holding down the movement keys, no event occurs. There is a single pygame.KEYDOWN event when the key is pressed and a single pygame.KEYUP event when the key is released.
But there are no continuously events, when a key is pressed.
It is perfect suitable to get the pressed key in the event loop by (pygame.key.get_pressed()) and to change the state of the control variables movingUP, movingDOWN, movingLEFT movingRIGHT. The values which are returned by pygame.key.get_pressed() are updated when the event is handled by pygame.event.get().
But the bounds check has to be done in every frame, every time when the position (x, y) was changed. It has to bed done in the main game loop, rather than the event loop:
maxX = # screenWidth - playerWidth
maxY = # screenHeight - playerHeight
while loop:
if eventHandler == "LEVEL1":
# SEE IF PLAYER QUIT AND PROCEED TO QUIT
for event in pygame.event.get():
if event.type == pygame.QUIT:
loop = False
if event.type == pygame.KEYDOWN:
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
movingUP = True
# [...]
if movingUP == True:
y_change -= 5
# [...]
x += x_change
y += y_change
if x < 0:
x = 0
x_change = 0
elif x > maxX
x = maxX
x_change = 0
if y < 0:
y = 0
y_change = 0
elif y > maxY
y = maxY
y_change = 0
I have written the following code that creates a simple game where when you click an arrow on the keyboard a box moves a unit over in the game.
I am trying to make it so that if i push any of the arrow buttons the box will continue to move in that direction until another arrow is pushed. So if i push the right arrow once instead of scooting +50 pixels it will move continuously across the screen untill a different arrow is clicked and then it will go that way
import pygame #importing the pygame library
# some initializations
pygame.init() # this line initializes pygame
window = pygame.display.set_mode( (800,600) ) # Create a window with width=800 and height=600
pygame.display.set_caption( 'Rectangle move' ) # Change the window's name we create to "Rectangle move"
clock = pygame.time.Clock() # Clocks are used to track and control the frame-rate of a game (how fast and how slow the pace of the game)
# This line creates and initializes a clock.
# color definitions, using RBG color model.
black = (0,0,0)
white = (255,255,255)
# initial center position for the square (bob)
x,y = 0,0
lastKey=0
game_loop=True
while game_loop:
for event in pygame.event.get(): # loop through all events
if event.type == pygame.QUIT:
game_loop = False # change the game_loop boolean to False to quit.
if event.type == pygame.KEYDOWN:
lastKey = event.key
#check last entered key
#lastKey equals "LEFT", "RIGHT", "UP", "DOWN" --> do the required stuff!
#set x coordinate minus 50 if left was pressed
if lastKey == pygame.K_LEFT:
x -= 50
if lastKey == pygame.K_RIGHT:
x += 50
if lastKey == pygame.K_UP:
y += 50
if lastKey == pygame.K_DOWN:
y -= 50
if event.key == pygame.K_LEFT:
x -= 50
if event.key == pygame.K_RIGHT:
x += 50
if event.key == pygame.K_UP:
y += 50
if event.key == pygame.K_DOWN:
y -= 50
# draw and update screen
window.fill( black ) # fill the screen with black overwriting even bob.
pygame.draw.rect( window, white, (x, y, 50, 50) ) # draw bob on the screen with new coordinates after its movement.
# the parameters are as follows: window: is the window object you want to draw on. white: the object color used to fill the rectangle
# (x,y,50,50) x is the x position of the left side of the rectangle. y is the y position of the upper side of the rectangle.
# In other words (x,y) is the coordinate of the top left point of the rectangle.
# 50 is the width, and 50 is the height
pygame.display.update() #updates the screen with the new drawing of the rectangle.
#fps stuff:
clock.tick(10) # this controls the speed of the game. low values makes the game slower, and large values makes the game faster.
pygame.quit()
any help would be much appreciated.
Try to save the entered key into a variable and check it after your Event-Loop.
Like this:
#...
lastKey = None
while game_loop:
for event in pygame.event.get(): # loop through all events
if event.type == pygame.QUIT:
game_loop = False # change the game_loop boolean to False to quit.
if event.type == pygame.KEYDOWN:
lastKey = event.key
#check last entered key
#lastKey equals "LEFT", "RIGHT", "UP", "DOWN" --> do the required stuff!
#set x coordinate minus 50 if left was pressed
if lastKey == pygame.K_LEFT
x -= 50
#<add the other statements here>
#(...)
I would recommend to not use that many if-statements. It could get a bit confusing after some time.
Check the following question out to keep your code brief:
Replacements for switch statement in Python?
You want to change the state of your application when you press a key. So you need a variable to keep track of that state (the state is: What direction should the box move?).
Here's a complete, minimal example that does what you're looking for. Note the comments.
import pygame, sys
pygame.init()
screen = pygame.display.set_mode((640, 480))
screen_r = screen.get_rect()
clock = pygame.time.Clock()
rect = pygame.rect.Rect(0, 0, 50, 50)
# let's start at the center of the screen
rect.center = screen_r.center
# a dict to map keys to a direction
movement = {pygame.K_UP: ( 0, -1),
pygame.K_DOWN: ( 0, 1),
pygame.K_LEFT: (-1, 0),
pygame.K_RIGHT: ( 1, 0)}
move = (0, 0)
# a simple helper function to apply some "speed" to your movement
def mul10(x):
return x * 10
while True:
for e in pygame.event.get():
if e.type == pygame.QUIT:
sys.exit()
# try getting a direction from our dict
# if the key is not found, we don't change 'move'
if e.type == pygame.KEYDOWN:
move = movement.get(e.key, move)
# move the rect by using the 'move_ip' function
# but first, we multiply each value in 'move' with 10
rect.move_ip(map(mul10, move))
# ensure that 'rect' is always inside the screen
rect.clamp_ip(screen_r)
screen.fill(pygame.color.Color('Black'))
pygame.draw.rect(screen, pygame.color.Color('White'), rect)
pygame.display.update()
clock.tick(60)
I use a Rect instead of keeping track of two coordinates x and y, since that allows to make use of the move_ip and clamp_ip functions to easily move the rect inside the screen.
Here are two versions, the first demonstrates how to utilize an event loop to get continuous movement (similar to Sloth's solution, but a bit simpler for beginners who don't know dictionaries yet), the second one shows how to achieve this with pygame.key.get_pressed().
Solution 1: Check which key was pressed in the event loop and change the x and y velocities to the desired values. Then add the velocities to the rect.x and rect.y positions in the while loop.
I'd actually recommend using vectors instead of the velocity_x and velocity_y variables and another one for the actual position of your sprite. pygame.Rects can't have floats as their coordinates and so a vector or separate variables for the position would be more accurate.
import pygame as pg
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
rect = pg.Rect(100, 200, 40, 60)
velocity_x = 0
velocity_y = 0
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_d:
velocity_x = 4
elif event.key == pg.K_a:
velocity_x = -4
elif event.type == pg.KEYUP:
if event.key == pg.K_d and velocity_x > 0:
velocity_x = 0
elif event.key == pg.K_a and velocity_x < 0:
velocity_x = 0
rect.x += velocity_x
rect.y += velocity_y
screen.fill((40, 40, 40))
pg.draw.rect(screen, (150, 200, 20), rect)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
Solution 2: Call pygame.key.get_pressed to check which key is currently being held down. Check if the left, right, up or down keys are held and then adjust the position of the sprite each frame.
pygame.key.get_pressed has the disadvantage that you can't know the order of the key presses, but the code looks a bit simpler.
import pygame as pg
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
rect = pg.Rect(100, 200, 40, 60)
velocity = (0, 0)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
keys = pg.key.get_pressed()
if keys[pg.K_d]:
rect.x += 4
if keys[pg.K_a]:
rect.x -= 4
screen.fill((40, 40, 40))
pg.draw.rect(screen, (150, 200, 20), rect)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()