Pygame Key Hold Down - python

while True:
pencere = pygame.display.set_mode((800,600))
pygame.display.set_caption("Oyun")
for olay in pygame.event.get():
if olay.type == pygame.QUIT:
pygame.quit()
sys.exit()
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
y -= 3
if keys[pygame.K_DOWN]:
y += 3
if keys[pygame.K_LEFT]:
x -= 3
if keys[pygame.K_RIGHT]:
x += 3
pencere.fill(beyaz)
pygame.draw.rect(pencere, mavi, (x, y, 40, 60))
pygame.display.update()
When i press navigate buttons, the rectangle goes 3 pixel. But how would I make it so when I hold the keys down?

You are reinitialising the pygame window every time round your loop with set_mode. Apparently this resets keyboard input too. (I'm actually surprised this doesn't make the whole window flicker or have other obvious effects.) You should only call set_mode once and you should do it before your main loop.

You can do
import time
key_1 = pygame.key.get_pressed()
time.sleep(0.5)
key_2 = pygame.key.get_pressed()
if key_1 == key_2:
if key_1[pygame.K_UP]:
y -= 3
if key_1[pygame.K_DOWN]:
y += 3
if key_1[pygame.K_LEFT]:
x -= 3
if key_1[pygame.K_RIGHT]:
x += 3
So x and y are updated only if one of the navigation keys is hold down

I use a feature like this a lot in my pygame projects.
The basis of it is to set a variable to True if a key is pressed and false if it is released. When you call a function like move(), you will check if the movement variables are True or False.
If you pressed the right and left arrows at the same time, there would be no movement.
This is just some of the code I use. Since you are using up and down aswell, you should just add more event checks for up and down and the code should be good to go.
Code:
running = True
directions = {"right": False, "left": False}
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
directions['right'] = True
elif event.key == pygame.K_LEFT:
directions['left'] = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
directions['right'] = False
elif event.key == pygame.K_LEFT:
directions['left'] = False
if directions['right']:
x += 3
if directions['left']:
x -= 3

Related

Key to be pressed multiple times to move image in pygame [duplicate]

This question already has answers here:
Pygame - Mouse clicks not getting detected
(2 answers)
Closed 2 years ago.
While I was learning how to move images in pygame, when I held down a key(any one: up, down, left, right) to move my image(a racecar), the image only moved once, even though holding down the key should've made the image move move in that particular directions continuously, but it only moved one unit. The fix that I found was that the declaration of the variables used to change the original position (x_vary and y_vary, original position: x and y) were not be added in the main while loop of my game.
My question is why? Why does it make a difference where I declare x_vary and y_vary
Here is the unfixed code:
import pygame
pygame.init()
clock = pygame.time.Clock()
game_window = pygame.display.set_mode((800, 600))
game_icon = pygame.image.load('icon2.jpg')
game_caption = pygame.display.set_caption('Racecar Game')
x = 800 * 0.45
y = 600 * 0.08
racecar = pygame.image.load('racecar.png')
def car(x, y):
game_window.blit(racecar,(x,y))
game_run = False
while game_run == False:
x_vary = 0
y_vary = 0
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_run = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_vary = -10
elif event.key == pygame.K_RIGHT:
x_vary = +10
elif event.key == pygame.K_UP:
y_vary = -10
elif event.key == pygame.K_DOWN:
y_vary = +10
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_UP or event.key == pygame.K_DOWN:
x_vary = 0
y_vary = 0
x += x_vary
y += y_vary
game_window.fill((128, 0, 0))
car(x, y)
pygame.display.update()
clock.tick(60)
pygame.quit()
quit()
The keyboard events (pygame.KEYDOWN, pygame.KEYUP) occur only one time when a key is pressed, respectively released.
If x_vary = 0 and y_vary = 0 are declared in the main application loop, then they are set when a button is pressed, but they are reinitialized (0) immediately in the next frame. You've to presse a button again to set them.
If x_vary = 0 and y_vary = 0 are declared before the main application loop, then they keep the value, which is set when a button is pressed. If a button is released, then both are set 0.
Use pygame.key.get_pressed(), to evaluate if the state of a key is pressed. pygame.key.get_pressed() get the state of all keyboard buttons and a the state of a key is True as long the keyboard is pressed down. e.g.:
game_run = False
while game_run == False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_run = True
keys = pygame.key.get_pressed()
x_vary, y_vary = 0, 0
if keys[pygame.K_LEFT]:
x_vary = -10
if keys[pygame.K_RIGHT]:
x_vary = +10
if keys[pygame.K_UP]:
y_vary = -10
if keys[pygame.K_DOWN]:
y_vary = +10
x += x_vary
y += y_vary
game_window.fill((128, 0, 0))
car(x, y)
pygame.display.update()
clock.tick(60)

Creating borders while using 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

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.

How do I make a game object move continuously as long as the key is pressed?

I am trying to make a game object (here, the welcome text) move as long as the key is pressed on the keyboard. But in this code of mine,
import pygame , sys
from pygame.locals import *
pygame.init()
WHITE = (255 , 255 , 255)
RED = (255 , 0 , 0)
DISPLAYSURF = pygame.display.set_mode((800 , 400))
pygame.display.set_caption('Welcome Tanks')
#render(text, antialias, color, background=None)
fontObj = pygame.font.SysFont('serif' , 40)
text = fontObj.render('Welcome Folks' , True , RED )
x = 150
y = 29
while True:
DISPLAYSURF.fill(WHITE)
DISPLAYSURF.blit(text ,(x , y))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit(0)
elif event.type == KEYDOWN or event.type == KEYUP:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit(0)
elif event.key == K_DOWN:
y += 15
elif event.key == K_UP:
y -= 15
elif event.key == K_RIGHT:
x += 14
elif event.key == K_LEFT:
x -= 15
else:
x = 150
y = 29
pygame.display.update()
The object moves only once, even though the key is continuously pressed for a long time. In other words, the object changes its position only once when the keyboard button is pressed. I want it to move continuously while I hold the key.
Which event should I look for instead of event.KEYDOWN?
I suggest you to use the key.get_pressed(), e.g.
while True:
DISPLAYSURF.fill(WHITE)
DISPLAYSURF.blit(text ,(x , y))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit(0)
elif event.type == KEYDOWN or event.type == KEYUP:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit(0)
if pygame.key.get_pressed()[K_LEFT]:
x -= 15
if pygame.key.get_pressed()[K_RIGHT]:
x += 14
if pygame.key.get_pressed()[K_UP]:
y -= 15
if pygame.key.get_pressed()[K_DOWN]:
y += 15
pygame.display.update()
pygame.key.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.
Also you can take a look at doc
keyState = pygame.key.get_pressed()
Declare that, and then you use keystate:
if KeyState()[K_DOWN]:
y += 15
You could try:
if key.get_pressed()
down = True
while down = True:
y+= 15
Then get FPS clock so it does not just flow over the screen!

Character only maintains movement while mouse is moving on screen?

My while loops only maintains the movement for the sprite while the cursor is moving inside of the screen. I've tried reorganizing some of the screen.blits and display.update() and display.flip(). I can't seem to figure out why the character stops after a change in one pixel instead of continuing like it I intended.
background_image = 'Terrain_Grass_First.png'
import pygame, sys
from pygame.locals import *
pygame.init()
pygame.display.set_caption('Hans')
screen_width = 600
screen_height = 400
screen = pygame.display.set_mode((screen_width, screen_height),0,32)
pygame.mouse.set_visible(False)
sprite = pygame.image.load('Hans_front_still.png').convert_alpha()
x,y = (0,0)
movex, movey = (0,0)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == K_w:
y = -1
elif event.key == K_a:
x = -1
elif event.key == K_s:
y = +1
elif event.key == K_d:
x = +1
elif event.type == KEYUP:
if event.key == K_w:
y = 0
elif event.key == K_a:
x = 0
elif event.key == K_s:
y = 0
elif event.key == K_d:
x = 0
movex += x
movey += y
screen.fill((0,0,0))
screen.blit(sprite,(movex,movey))
pygame.display.flip()
Your loop blocks on pygame.event.get.
You don't schedule any events of your own.
So, you do nothing until the OS has an event (mouse move, redraw, etc.) to give you.
And, even if you fixed that, you're calling movex += x once per event. So, when the OS is throwing a lot of events at you, your sprite will go zipping madly across the screen, but when the events are coming more slowly, it will crawl along. That's almost never what you want.
An easy fix for both problems is to just schedule your own events. For example, with pygame.time.set_timer(), you can make sure you get an event every, say, 250 milliseconds, and you can only move the sprite on those events. For example:
timer_event = pygame.USEREVENT + 1
pygame.time.set_timer(timer_event, 250)
while True:
for event in pygame.event.get():
# ...
elif event.type == timer_event:
movex += x
movey += y
Another alternative is to design your game with a fixed framerate.
A trivial example looks like this:
FRAME_TIME = 50 # 50ms = 20fps
next_frame_time = pygame.time.get_ticks() + FRAMES
while True:
while True:
event = pygame.event.poll()
if event.type == pygame.NOEVENT:
break
elif # ...
pygame.display.flip()
now = pygame.time.get_ticks()
if now < next_frame_time:
pygame.time.wait(next_frame_time - now)
next_frame_time += FRAMES
Now you can just move every 5th frame.
A realistic example has to deal with missed frames, too many events in the queue, choose between wait and delay appropriately, etc.
But I'd go with the event-driven version with a timer instead of a fixed-framerate version in most cases, especially if you're already going down that line.
The only problem is your Indentation!
The fifth and sixth lines from the bottom have wrong indentation, and you need to delete them.
These two lines:
movex += x
movey += y
should be:
movex += x
movey += y
And it works

Categories