Two keypresses processed in each frame (pygame snake game) - python

I am making a snake game, and I want to make sure that if you want to turn twice (for example a 180 degree turn), if both keys are pressed in the same frame, the next key press will be processed in the next frame, so that the snake actually turns twice over two frames instead of changing direction twice in the same frame, which could cause it to turn into itself and die. So basically, one turn per frame.
import pygame, sys
from pygame.locals import *
from sys import exit
import keyboard
import random
import time
class body:
def __init__(self,properties=[0,0,20,20],colour=-1):
self.properties=properties
self.colour=colour
self.next=None
class fruit:
def __init__(self,centre=[0,0],size=10):
self.centre=centre
self.size=size
def drawSnake(window,snake):
pygame.draw.rect(window,(0,0,0),snake.properties)
snake.colour=snake.colour*-1
temp=snake.next
while temp:
# Alternate snake colour
if temp.colour==-1:
colour=(0,150,0)
else:
colour=(0,100,0)
temp.colour=temp.colour*-1
pygame.draw.rect(window,colour,temp.properties)
temp=temp.next
return snake
def drawApple(window,snake,size):
numApples=500/(size*2)
bound=numApples-1
apple=fruit([(random.randint(0,bound)*(500/numApples))+size,(random.randint(0,bound)*(500/numApples))+size],size)
#apple=fruit([290,250],10)
pygame.draw.circle(window,"red",apple.centre,apple.size)
return apple
def newGame():
# Draw initial snake and apple
window.fill((255, 255, 255))
snake=body([240,240,20,20],-1)
snake=drawSnake(window,snake)
apple=drawApple(window,snake,10)
return snake,apple
def die(snake):
pygame.draw.rect(window,(180,0,0),[snake.properties[0],snake.properties[1],snake.properties[2],snake.properties[3]])
pygame.display.update()
time.sleep(1)
def getDirection(key,direction):
print(key)
if key == pygame.K_w:
if direction!=[0,20]:
direction=[0,-20]
if key == pygame.K_a:
if direction!=[20,0]:
direction=[-20,0]
if key == pygame.K_s:
if direction!=[0,-20]:
direction=[0,20]
if key == pygame.K_d:
if direction!=[-20,0]:
direction=[20,0]
return direction
def move(snake,apple,direction,length):
# New body piece location
x=snake.properties[0]+direction[0]
y=snake.properties[1]+direction[1]
# If snake crashed, restart
if x<0 or y<0 or x>480 or y>480:
die(snake)
snake,apple=newGame()
return snake,apple,0,False
# Check if collision with body
temp=snake
# Create new body piece with other colour and add to front of list
newBody=body([x,y,20,20],snake.colour*-1)
newBody.next=snake
snake=newBody
# If apple is eaten
if [x,y]==[apple.centre[0]-10,apple.centre[1]-10]:
# Add 1 to length, spawn new apple, do not remove end body piece
length+=1
apple=drawApple(window,snake,10)
while temp:
# Check if apple spawned in body
if temp.properties[0]==apple.centre[0]-10 and temp.properties[1]==apple.centre[1]-10:
apple=drawApple(window,snake,10)
temp=snake.next
temp=temp.next
else:
# Remove end body piece
temp=snake
while temp.next:
# Check if collision with body
if temp.next.properties[0]==x and temp.next.properties[1]==y:
die(snake)
snake,apple=newGame()
return snake,apple,0,False
previous=temp
temp=temp.next
pygame.draw.rect(window,"white",temp.properties)
previous.next=None
return snake,apple,length,True
# Make window
pygame.init()
window=pygame.display.set_mode((500, 500))
snake,apple=newGame()
length=0
delay=0.1
clock=pygame.time.Clock()
pygame.display.update()
prevEvents=[]
while True:
# Wait until a key is pressed to start the game
pressed_keys=pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
# Key is pressed, get direction and start main game loop
direction=getDirection(event.key,[])
game=True
## MAIN GAME LOOP
while game:
# Set FPS
clock.tick(1)
# Get current event queue
events=pygame.event.get()
print("events1: ",events)
print()
# Add current event queue to previous events which were not processed as a key was pressed in the last frame
prevEvents.extend(events)
events=prevEvents
prevEvents=[]
print("events2: ",events)
print()
if events!=None:
i=1
for event in events:
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
# Key was pressed, get new direction of snake
direction=getDirection(event.key,direction)
# Save rest of event queue for next frame to process
prevEvents=events[i:len(events)+1]
print("prevEvents: ",prevEvents)
print()
# Make events nothing to exit this loop, move the snake and get to the next frame
events=[]
i+=1
# Move and draw snake
snake,apple,length,game=move(snake,apple,direction,length)
snake=drawSnake(window,snake)
pygame.display.update()
I am new to pygame, so any help is appreciated.

Store the keys pressed in a queue:
direction_queue = []
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
direction_queue.append('L')
if event.key == pygame.K_d:
direction_queue.append('R')
if event.key == pygame.K_w:
direction_queue.append('U')
if event.key == pygame.K_s:
direction_queue.append('D')
Process the keys one after the other in the application loop:
if direction_queue:
direction = direction_queue[0]
direction_queue.pop(0)
Minimal example:
import pygame
pygame.init()
COLUMNS, ROWS, TIESIZE = 20, 20, 20
window = pygame.display.set_mode((COLUMNS*TIESIZE, ROWS*TIESIZE))
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 50)
snake_x, snake_y = 9, 9
key_map = {pygame.K_a: 'L', pygame.K_d: 'R', pygame.K_w: 'U', pygame.K_s: 'D'}
direction_map = {'L': (-1, 0), 'R': (1, 0), 'U': (0, -1), 'D': (0, 1)}
direction_queue = []
direction = 'R'
run = True
while run:
clock.tick(5)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key in key_map:
direction_queue.append(key_map[event.key])
text_surf = font.render(str(direction_queue), True, 'black')
if direction_queue:
direction = direction_queue[0]
direction_queue.pop(0)
snake_x = (snake_x + direction_map[direction][0]) % COLUMNS
snake_y = (snake_y + direction_map[direction][1]) % ROWS
window.fill("white")
for c in range (1, COLUMNS):
pygame.draw.line(window, "gray", (c*TIESIZE, 0), (c*TIESIZE, window.get_height()))
for r in range (1, ROWS):
pygame.draw.line(window, "gray", (0, r*TIESIZE), (window.get_width(), r*TIESIZE))
rect = pygame.Rect(snake_x*TIESIZE, snake_y*TIESIZE, TIESIZE, TIESIZE)
pygame.draw.rect(window, "red", rect)
window.blit(text_surf, (10, 340))
pygame.display.flip()
pygame.quit()
exit()

Related

Pygame - How can I allow my users to change their input keys? (Custom Keybinding)

I'm trying to make a game and want the user to change their input keys, e.g. they press the A key and that changes the MoveUp variable to the A key so that when they press A in the game they move upwards. Any help or advice would be greatly appreciated.
global MoveUp # MoveUp = pygame.K_UP
while not Fin:
for event in pygame.event.get():
pressed = pygame.key.pressed()
if event.type == pygame.KEYDOWN:
MoveUp = pressed
KeysLoop()
The current problem with this code is that it gives me a list that corresponds to the key pressed, I need a key identifier so that I can use MoveUp to move my sprite later on.
You can create a dictionary with the action names as the dict keys and the pygame keys (pygame.K_LEFT, etc.) as the values. For example:
input_map = {'move right': pygame.K_d, 'move left': pygame.K_a}
That allows you to assign other pygame keys to these actions (in the event loop of your assignment menu):
if event.type == pygame.KEYDOWN:
# Assign the pygame key to the action in the keys dict.
input_map[selected_action] = event.key
Then, in the main while loop, you can use the action names to check if the corresponding keyboard key is pressed:
pressed_keys = pygame.key.get_pressed()
if pressed_keys[input_map['move right']]:
In the following example you can access the assignment_menu by clicking the ESCAPE key. It's a separate function with its own while loop in which I create a table of the actions and pygame keys which you can select with the mouse. If an action is selected and the user presses a key, I update the input_map dict and return it to the main game function when the user presses Esc again.
import sys
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
FONT = pg.font.Font(None, 40)
BG_COLOR = pg.Color('gray12')
GREEN = pg.Color('lightseagreen')
def create_key_list(input_map):
"""A list of surfaces of the action names + assigned keys, rects and the actions."""
key_list = []
for y, (action, value) in enumerate(input_map.items()):
surf = FONT.render('{}: {}'.format(action, pg.key.name(value)), True, GREEN)
rect = surf.get_rect(topleft=(40, y*40+20))
key_list.append([surf, rect, action])
return key_list
def assignment_menu(input_map):
"""Allow the user to change the key assignments in this menu.
The user can click on an action-key pair to select it and has to press
a keyboard key to assign it to the action in the `input_map` dict.
"""
selected_action = None
key_list = create_key_list(input_map)
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
sys.exit()
elif event.type == pg.KEYDOWN:
if selected_action is not None:
# Assign the pygame key to the action in the input_map dict.
input_map[selected_action] = event.key
selected_action = None
# Need to re-render the surfaces.
key_list = create_key_list(input_map)
if event.key == pg.K_ESCAPE: # Leave the menu.
# Return the updated input_map dict to the main function.
return input_map
elif event.type == pg.MOUSEBUTTONDOWN:
selected_action = None
for surf, rect, action in key_list:
# See if the user clicked on one of the rects.
if rect.collidepoint(event.pos):
selected_action = action
screen.fill(BG_COLOR)
# Blit the action-key table. Draw a rect around the
# selected action.
for surf, rect, action in key_list:
screen.blit(surf, rect)
if selected_action == action:
pg.draw.rect(screen, GREEN, rect, 2)
pg.display.flip()
clock.tick(30)
def main():
player = pg.Rect(300, 220, 40, 40)
# This dict maps actions to the corresponding key scancodes.
input_map = {'move right': pg.K_d, 'move left': pg.K_a}
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_ESCAPE: # Enter the key assignment menu.
input_map = assignment_menu(input_map)
pressed_keys = pg.key.get_pressed()
if pressed_keys[input_map['move right']]:
player.x += 3
elif pressed_keys[input_map['move left']]:
player.x -= 3
screen.fill(BG_COLOR)
pg.draw.rect(screen, GREEN, player)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
main()
pg.quit()
When you get event KEYDOWN then you have pressed key in event.key
while not Fin:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN
MoveUp = event.key
BTW: Every event may have different fields. You can see all on yellow list in documentation: event

pygame moving left and right issue

I have started making something on pygame but I have encountered an issue when moving left or right. if I quickly change from pressing the right arrow key to pressing the left one and also let go of the right one the block just stops moving. this is my code
bg = "sky.jpg"
ms = "ms.png"
import pygame, sys
from pygame.locals import *
x,y = 0,0
movex,movey=0,0
pygame.init()
screen=pygame.display.set_mode((664,385),0,32)
background=pygame.image.load(bg).convert()
mouse_c=pygame.image.load(ms).convert_alpha()
m = 0
pygame.event.pump()
while 1:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type==KEYDOWN:
if event.key==K_LEFT:
movex =-0.5
m = m + 1
if event.key==K_RIGHT:
movex=+0.5
m = m + 1
elif event.type == KEYUP:
if event.key==K_LEFT and not event.key==K_RIGHT:
movex = 0
if event.key==K_RIGHT and not event.key==K_LEFT:
movex =0
x+=movex
y=200
screen.blit(background, (0,0))
screen.blit(mouse_c,(x,y))
pygame.display.update()
is there a way I can change this so if the right arrow key is pressed and the left arrow key is released that it will go right instead of stopping?
P.S
I am still learning pygame and am very new to the module. I'm sorry if this seems like a stupid question but i couldn't find any answers to it.
Your problem is that when you test the KEYDOWN events with
if event.key==K_LEFT and not event.key==K_RIGHT:
you always get True, because when event.key==K_LEFT is True,
it also always is not event.key==K_RIGHT (because the key of the event is K_LEFT after all).
My approach to this kind of problem is to separate
the intent from the action. So, for the key
events, I would simply keep track of what action
is supposed to happen, like this:
moveLeft = False
moveRight = False
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_LEFT: moveLeft = True
if event.key == K_RIGHT: moveRight = True
elif event.type == KEYUP:
if event.key == K_LEFT: moveLeft = False
if event.key == K_RIGHT: moveRight = False
Then, in the "main" part of the loop, you can
take action based on the input, such as:
while True:
for event in pygame.event.get():
...
if moveLeft : x -= 0.5
if moveRight : x += 0.5
the problem is that you have overlapping key features; If you hold down first right and then left xmove is first set to 1 and then changes to -1. But then you release one of the keys and it resets xmove to 0 even though you are still holding the other key. What you want to do is create booleans for each key. Here is an example:
demo.py:
import pygame
window = pygame.display.set_mode((800, 600))
rightPressed = False
leftPressed = False
white = 255, 255, 255
black = 0, 0, 0
x = 250
xmove = 0
while True:
window.fill(white)
pygame.draw.rect(window, black, (x, 300, 100, 100))
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
rightPressed = True
if event.key == pygame.K_LEFT:
leftPressed = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
rightPressed = False
if event.key == pygame.K_LEFT:
leftPressed = False
xmove = 0
if rightPressed:
xmove = 1
if leftPressed:
xmove = -1
x += xmove
pygame.display.flip()
One way could be to create a queue that keeps track of the button that was pressed last. If we press the right arrow key we'll put the velocity first in the list, and if we then press the left arrow key we put the new velocity first in the list. So the button that was pressed last will always be first in the list. Then we just remove the button from the list when we release it.
import pygame
pygame.init()
screen = pygame.display.set_mode((720, 480))
clock = pygame.time.Clock()
FPS = 30
rect = pygame.Rect((350, 220), (32, 32)) # Often used to track the position of an object in pygame.
image = pygame.Surface((32, 32)) # Images are Surfaces, so here I create an 'image' from scratch since I don't have your image.
image.fill(pygame.Color('white')) # I fill the image with a white color.
velocity = [0, 0] # This is the current velocity.
speed = 200 # This is the speed the player will move in (pixels per second).
dx = [] # This will be our queue. It'll keep track of the horizontal movement.
while True:
dt = clock.tick(FPS) / 1000.0 # This will give me the time in seconds between each loop.
for event in pygame.event.get():
if event.type == pygame.QUIT:
raise SystemExit
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
dx.insert(0, -speed)
elif event.key == pygame.K_RIGHT:
dx.insert(0, speed)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
dx.remove(-speed)
elif event.key == pygame.K_RIGHT:
dx.remove(speed)
if dx: # If there are elements in the list.
rect.x += dx[0] * dt
screen.fill((0, 0, 0))
screen.blit(image, rect)
pygame.display.update()
# print dx # Uncomment to see what's happening.
You should of course put everything in neat functions and maybe create a Player class.
I know my answer is pretty late but im new to Pygame to and for beginner like me doing code like some previous answer is easy to understand but i have a solution to.I didn`t use the keydown line code, instead i just put the moving event code nested in the main game while loop, im bad at english so i give you guy an example code.
enter code here
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.K_ESCAPE:
run = False
win.blit(bg, (0, 0))
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]:
x -= 5
if pressed[pygame.K_RIGHT]:
x += 5
if pressed[pygame.K_UP]:
y -= 5
if pressed[pygame.K_DOWN]:
y += 5
win.blit(image,(x,y))
pygame.display.update()
pygame.quit()
This will make the image move rapidly without repeating pushing the key, at long the code just in the main while loop with out inside any other loop.

Continuous movement of a box in pygame

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()

constant movement in pygame

This is my first pygame code not much, pretty straight forward. When I want to move my player it works but I would love to have the movement steadily. Like when I press left I want it to move left. At the moment I have to press every time the left button so the player moves to the left. Do you have any suggestions how to do that?
import pygame, sys
pygame.init()
window_size = ( 400, 400 )
white = ( 255, 255, 255 )
class Player():
image = pygame.image.load( 'foo.png')
rect = image.get_rect()
player = Player()
screen = pygame.display.set_mode( window_size )
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
move = (-10, 0 )
player.rect = player.rect.move(move)
if event.key == pygame.K_RIGHT:
move = ( 10, 0 )
player.rect = player.rect.move(move)
if event.key == pygame.K_UP:
move = ( 0,-10 )
player.rect = player.rect.move(move)
if event.key == pygame.K_DOWN:
move = ( 0, 10 )
player.rect = player.rect.move(move)
screen.fill( white )
screen.blit( player.image, player.rect )
pygame.display.flip()
Edit My approach to Aarons answer:
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]:
move = ( 2, 0 )
player.rect = player.rect.move(move)
if pressed[pygame.K_RIGHT]:
move = ( 2, 0 )
player.rect = player.rect.move(move)
if pressed[pygame.K_UP]:
move = ( 0,-2 )
player.rect = player.rect.move(move)
if pressed[pygame.K_DOWN]:
move = ( 0, 2 )
player.rect = player.rect.move(move)
You could track both KEYUP and KEYDOWN events then store a pressed state for each of the keys you are tracking.
Now instead of moving the player whenever the user presses a key, you test the state of the key to see if it is pressed and apply movement to the player if it is.
As a simplified example:
pressed_keys = {
'left': false,
...define other keys...
}
while not done:
# Check for key events
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
pressed_keys['left'] = True
...check other keys...
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
pressed_keys['left'] = False
...check other keys...
# Move the player
if pressed_keys['left']:
...move player left...
Looking at Sloth's answer on a similar question. It seems that you have two potential approaches, either making use of set_repeat or get_pressed.
set_repeat
When the keyboard repeat is enabled, keys that are held down will generate multiple pygame.KEYDOWN events. The delay is the number of milliseconds before the first repeated pygame.KEYDOWN will be sent. After that another pygame.KEYDOWN will be sent every interval milliseconds. If no arguments are passed the key repeat is disabled.
Source
Something like this would do the job:
# set_repeat(delay, interval)
pygame.key.set_repeat(1, 10)
# A delay of 0 disables the repeat.
# The lower the interval, the faster the movement would be.
get_pressed
Returns a sequence of boolean values representing the state of every key on the keyboard. Use the key constant values to index the array. A True value means the that button is pressed.
Getting the list of pushed buttons with this function is not the proper way to handle text entry from the user. You have no way to know the order of keys pressed, and rapidly pushed keys can be completely unnoticed between two calls to pygame.key.get_pressed(). There is also no way to translate these pushed keys into a fully translated character value. See the pygame.KEYDOWN events on the event queue for this functionality.
Source
Something like this should fit into your code nicely:
pressed = pygame.key.get_pressed()
if pygame.K_LEFT in pressed:
# move left
if pygame.K_RIGHT in pressed:
# move right
Solution implemented into #ZedsWhatSheSaid's code, also added PEP-8 formatting:
import pygame
import sys
pygame.init()
window_size = (400, 400)
white = (255, 255, 255)
class Player():
image = pygame.image.load('foo.png')
rect = image.get_rect()
player = Player()
screen = pygame.display.set_mode(window_size)
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
pressed = pygame.key.get_pressed()
if pygame.K_LEFT in pressed:
move = (-10, 0)
player.rect = player.rect.move(move)
if pygame.K_RIGHT in pressed:
move = (10, 0)
player.rect = player.rect.move(move)
if pygame.K_UP in pressed:
move = (0, -10)
player.rect = player.rect.move(move)
if pygame.K_DOWN in pressed:
move = (0, 10)

Pygame how to "place" an image when you press a key

import pygame, random, time
class Game(object):
def main(self, screen):
bg = pygame.image.load('data/bg.png')
select = pygame.image.load('data/select.png')
block1 = pygame.image.load('data/enemy1.png')
clock = pygame.time.Clock()
while 1:
clock.tick(30)
spriteList = []
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
return
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
spriteList.append(block1, (0, 0))
mouse = pygame.mouse.get_pos()
print(mouse)
screen.fill((200, 200, 200))
screen.blit(bg, (0, 0))
screen.blit(select, (mouse))
for sprite in spriteList:
screen.blit(sprite[0], sprite[1])
pygame.display.flip()
if __name__ == '__main__':
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
pygame.init()
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Sandbox')
Game().main(screen)
I'm trying to make it so where you move the mouse a box follows it. Then when you click the space key, "place" an image where you pressed space and then leave it there and be able to place another image somewhere else without effecting the first one. I tried using spriteList but I am kind of confused on where to go from here.
And when I run it I get an error saying: .append() takes one argument (2 given)
Add a tuple to your list. Also, store the mouse position, not (0, 0). Change
spriteList.append(block1, (0, 0))
to
spriteList.append((block1, mouse))
Also, you could rewrite
for sprite in spriteList:
screen.blit(sprite[0], sprite[1])
to
for (img, pos) in spriteList:
screen.blit(img, pos)

Categories