make something while keypressed | python - python

i want to show an image as long as i hold a key pressed. If the key isn't pressed (KEYUP) anymore, the image should disappear.
In my code the image appears when i hold the key down, but i does not disappears right away. Anyone knows why the image does not stay visible as long as I hold my key pressed=?
button_pressed = False
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_UP:
button_pressed = True
print"True"
if event.type == KEYUP:
if event.key == K_UP:
button_pressed = False
if button_pressed:
DISPLAYSURF.blit(arrow_left, (20, SCREEN_HEIGHT/2 - 28))
Thanks in advance!!

Once you blittet your image to the screen, it will stay there until you draw something over it. It won't disappear by itself.
An easy solution is to just clear the screen every iteration of your main loop, e.g. something like:
while running:
DISPLAYSURF.fill((0, 0, 0)) # fill screen black
for event in pygame.event.get():
# handle events
pass
# I'm using 'key.get_pressed' here because using the KEYDOWN/KEYUP event
# and a variable to track if a key is pressed totally sucks and people
# should stop doing this :-)
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
# only draw image if K_UP is pressed.
DISPLAYSURF.blit(arrow_left, (20, SCREEN_HEIGHT/2 - 28))
pygame.display.flip()

Related

I want the screen to be cleared/completely black when the enter key is pressed. How would I do that?

I want the screen to change to all black after the enter button is pressed.
I was trying to have the screen clear here, when the enter key gets pressed:
def newScreen(self):
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
pygame.win.fill(self,(0,0,0))
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
win.fill((0,0,0))
Even this will not work if you have a bigger code that is blitting something else on the screen like a background in the while loop as it will again blit the background and black screen would be visible for a micro second thus you will need to define a variable(black_fill is my name) and set its value as False and if not black_fill: than only blit the other images and else: win.fill((0,0,0)).Also when enter is pressed( the way you tracked its clicking by events) just make black_fill as True.
win = pygame.display.set_mode((1000, 500))
black_fill = False
bg = pygame.image.load('any_bg_file')
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
black_fill = True
if not black_fill:
win.blit(bg, (0, 0))
else:
win.fill((0, 0, 0))
pygame.display.flip()

My game won't work when I use the controls, how do I fix it?

I can not get the controls to work, I try to press escape to open a menu I made but it will not open and I do not know if I am checking for events correctly, is there a way I am SUPPOSED to do it?
I tried using the functions for checking for different keys and I went to the spread-sheet that displays all the event names so you can map them at pygame.org but it will not open when I use the escape or also known as:
elif event.type == pygame.K_ESCAPE:
Frame.blit('Textures/GUI/loom.png', (0,0))
Heres the full code:
import pygame
#Textures/Blocks/loom_side.png
pygame.init()
Screen = "None"
DB = 0
Width = 800
Height = 600
Frame = pygame.display.set_mode((Width,Height))
pygame.display.set_caption("HypoPixel")
FPS = pygame.time.Clock()
def Raycast(TTR, RayXPos, RayYPos, RaySizeX, RaySizeY):
RaycastThis = pygame.image.load(TTR)
RaycastThis = pygame.transform.scale(RaycastThis,(RaySizeX,RaySizeY))
Frame.blit(RaycastThis, (RayXPos, RayYPos))
Loop = True
Raycast('Textures/Screens/Skybox/Earth.png',0,0,800,600)
while Loop == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
elif event.type == pygame.K_ESCAPE:
Frame.blit('Textures/GUI/loom.png', (0,0))
pygame.display.update()
FPS.tick(60)
I expected to get the loom GUI that I made. Once I tried to press escape, nothing happened.
pygame.K_ESCAPE is not event type (see pygame.event), but it is a pygame.key.
First check if a key was pressed by comparing the event type to pygame.KEYDOWN:
event.type == pygame.KEYDOWN
Then check if the event.key, which cause the event, is the pygame.K_ESCAPE key:
event.key == pygame.K_ESCAPE
Furthermore, the parameter to Surface.blit() has to be a Surface object rather than a filename.
first load the image to a Surface, by pygame.image.load(), then blit the Surface:
sprite = pygame.image.load('Textures/GUI/loom.png')
Frame.blit(sprite, (0,0))
Of course the your Raycast function can be called to do so:
Raycast('Textures/GUI/loom.png',0,0,800,600)
Your code should look somehow like this:
while Loop == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
Raycast('Textures/GUI/loom.png',0,0,800,600)

Lock mouse in window Pygame

I want to make a FPS game in Pygame in windowed mode.
I need to be able to move my camera around for 360 degrees and more without limitation and with the hidden cursor.
I used Pygame's set_visible and set_pos but it doesn't prevent my mouse going out of the window and blocking on the screen borders.
import pygame
pygame.init()
game_display = pygame.display.set_mode((800,600))
pygame.mouse.set_visible(False)
exit = False
while (not exit):
pygame.mouse.set_pos = (400, 300)
mouse_move = (0,0)
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit = True
if event.type == pygame.MOUSEMOTION:
mouse_move = event.rel
if mouse_move != (0,0):
print(mouse_move)
pygame.quit()
You have to call pygame.event.set_grab(True) as well.
Better allow the users to exit with the Esc or another key, because they won't be able to click the x button anymore to close the window.
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
exit = True

Pygame I can move an image once but don't know how to move it twice

I have a box that i want to move in increments, i know how to move it by an increment but only once. I don't how i'd do this multiple times. anyone got any ideas?
The box:
highlight = pygame.draw.rect(window, (darkYellow),(30, 300, 130, 40),0)
Moving the box (this is to move it once)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit()
if event.type == pygame.KEYDOWN and pygame.K_RIGHT:
highlight = pygame.draw.rect(window, (darkYellow),(260, 300, 130, 40),0)
difficultyText = myFont.render("Difficulty", 1, red)
window.blit(difficultyText, (260, 300))
pygame.display.update()
Takes any key input when i only want it to activate when the key "ARROW DOWN" is pushed
if event.type == pygame.KEYDOWN and pygame.K_DOWN:
window.blit(arrowImg, (5,400))
pygame.display.update()
There are few issues with your code.
You are drawing, rendering text and bliting in your event loop. You should move them out of the loop body.
It seems that you want to have a cursor that will change its position with the right arrow key.
To do this have a variable that will tell you where your cursor is.
Then your draw statement will look like this:
pygame.draw.rect(window, (darkYellow),(30+cursorPos*230, 300, 130, 40),0)
EDIT:
As for why event.type == pygame.KEYDOWN and pygame.K_DOWN is true for all KEY_DOWN events, is because it can be translated to (event.type==pygame.KEYDOWN) and pygame.K_DOWN.
Since pygame.K_DOWN is a non zero value, it is true when evaluated as a boolean value.
To fix this you want to do something like this:
event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN

Pygame: key.get_pressed() does not coincide with the event queue

I'm attempting to work out simple controls for an application using pygame in Python. I have got the basics working, but I'm hitting a weird wall: I am using the arrow keys to control my character. If I hold down one arrow key, then hold down another arrow key (to move diagonally), the character moves as expected. However, if I release the second key that I pressed (while still holding down the first key), the character stops moving, even though I am still holding down that first key. Here is my simple movement code:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if pygame.key.get_pressed()[K_LEFT]:
player.pos = (player.pos[0] - 2, player.pos[1])
if pygame.key.get_pressed()[K_RIGHT]:
player.pos = (player.pos[0] + 2, player.pos[1])
if pygame.key.get_pressed()[K_UP]:
player.pos = (player.pos[0], player.pos[1] - 2)
if pygame.key.get_pressed()[K_DOWN]:
player.pos = (player.pos[0], player.pos[1] + 2)
Now, I was naturally very confused by this. So I tried to print some lines to debug. In the top of the main control loop, I wrote:
print (pygame.key.get_pressed()[K_DOWN], pygame.key.get_pressed()[K_RIGHT])
print pygame.event.get()
...to output a tuple displaying the state of the down and right arrow keys, and then display the pygame event queue. My results baffled me even more. If I move the character diagonally down and right, pressing the down key first and then the right key, then release the right key to make it move simply downward, the character stops moving as before... but this is printed to the shell:
(1, 0)
[]
That is, when I release the right arrow key and still hold down the down arrow key, pygame.key.get_pressed() understands that the down arrow key is still being held down, but there is nothing in the event queue.
Also, earlier in the code (before the control loop) I am invoking
pygame.key.set_repeat(1, 2)
to make the character continue to move while the key is held down.
Any help will be appreciated! Thanks :)
For things like movement, you should not check for events (like KEYDOWN or KEYUP), but check every iteration of your mainloop if your movement keys are pressed (using get_pressed).
In your code, you check the pressed keys only if there's also a KEYDOWN event.
There are also some other things to consider:
You should seperate the key-mapping and the speed of your player, so it will be easier later on to change either of this.
You should determine a movement vector and normalize it first, since otherwise, if your vertical and horizontal movement speed is 10, your diagonal movement speed would be ~14.
Working example:
import pygame
pygame.init()
screen = pygame.display.set_mode((200, 200))
run = True
pos = pygame.Vector2(100, 100)
clock = pygame.time.Clock()
# speed of your player
speed = 2
# key bindings
move_map = {pygame.K_LEFT: pygame.Vector2(-1, 0),
pygame.K_RIGHT: pygame.Vector2(1, 0),
pygame.K_UP: pygame.Vector2(0, -1),
pygame.K_DOWN: pygame.Vector2(0, 1)}
while run:
for e in pygame.event.get():
if e.type == pygame.QUIT: run = False
screen.fill((30, 30, 30))
# draw player, but convert position to integers first
pygame.draw.circle(screen, pygame.Color('dodgerblue'), [int(x) for x in pos], 10)
pygame.display.flip()
# determine movement vector
pressed = pygame.key.get_pressed()
move_vector = pygame.Vector2(0, 0)
for m in (move_map[key] for key in move_map if pressed[key]):
move_vector += m
# normalize movement vector if necessary
if move_vector.length() > 0:
move_vector.normalize_ip()
# apply speed to movement vector
move_vector *= speed
# update position of player
pos += move_vector
clock.tick(60)
just use the events return data, instead of trying to poll, you're already checking if its a keydown event TYPE, now just interrogate the KEY index, like so:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_LEFT:
player.pos = (player.pos[0] - 2, player.pos[1])
rest of code.....
also consider using a separate data structure to store the state of your controls, then just use the events to update that data structure. That will help make the controls a bit more flexible as you wont be relying on the event queue to cause your character to move, which in my experience causes problems like: not being able to push more than two buttons at a time, and odd delay or timing issues with character movements. so something like:
keystates={'up':False, 'down':False, 'left':False, 'right':False}
running=True
#start main pygame event processing loop here
while running:
for event in pygame.event.get():
if event.type == QUIT:
running=False
#check for key down events
if event.type == KEYDOWN:
if event.key == K_UP:
keystates['up']=True
if event.key == K_DOWN:
keystates['down']=True
if event.key == K_LEFT:
keystates['left']=True
if event.key == K_RIGHT:
keystates['right']=True
#check for key up events
if event.type == KEYUP:
if event.key == K_UP:
keystates['up']=False
if event.key == K_DOWN:
keystates['down']=False
if event.key == K_LEFT:
keystates['left']=False
if event.key == K_RIGHT:
keystates['right']=False
#do something about the key states here, now that the event queue has been processed
if keystates['up']:
character.moveUp() #or whatever your call for these are...
if keystates['down']:
character.moveDown()
if keystates['left']:
character.moveLeft()
if keystates['right']:
character.moveRight()
#gracefully exit pygame here
pygame.quit()
You are using event-based input , but in this case you want polling-based input. Then you don't mess with key-repeats.
import pygame
from pygame.locals import *
done = False
player.pos = Rect(0,0,10,10)
while not done:
for event in pygame.event.get():
# any other key event input
if event.type == QUIT:
done = True
elif event.type == KEYDOWN:
if event.key == K_ESC:
done = True
elif event.key == K_F1:
print "hi world mode"
# get key current state
keys = pygame.key.get_pressed()
if keys[K_LEFT]:
player.pos.left -= 10
if keys[K_RIGHT]:
player.pos.left += 10
if keys[K_UP]:
player.pos.top -= 10
if keys[K_DOWN]:
player.pos.left += 10
if keys[K_SPACE]:
print 'firing repeated gun'
My guess is that set repeat doesn't work the way that you think it will. Basically, after your second key goes up, the repeat doesn't happen. This would seem to make sense to me: open up a text editor and hold down the "A" key. "A"s will spill out across the screen. Then, press the "J" key with the "A" key still held down. The "A"s stop. That is a typical key repeat system.
I'm not sure using this "set_repeat" method is going to work out in the end anyway. Basically, any key that the player presses will now "repeat", even if they click "fire" or "jump".
As an alternative, try saving the state when the user presses or releases. Don't use the set_repeat, but do something like the following:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if pygame.key.get_pressed()[K_LEFT]:
player.moving_left = True
if pygame.key.get_pressed()[K_RIGHT]:
player.moving_right = True
if pygame.key.get_pressed()[K_UP]:
player.moving_up = True
if pygame.key.get_pressed()[K_DOWN]:
player.moving_down = True
elif event.type == KEYUP:
if pygame.key.get_pressed()[K_LEFT]:
player.moving_left = False
if pygame.key.get_pressed()[K_RIGHT]:
player.moving_right = False
if pygame.key.get_pressed()[K_UP]:
player.moving_up = False
if pygame.key.get_pressed()[K_DOWN]:
player.moving_down = False
# Somewhere else in your game loop...
if player.moving_left:
player.pos[0] -= 2
if player.moving_right:
player.pos[0] += 2
if player.moving_up:
player.pos[1] -= 2
if player.moving_right:
player.pos[1] += 2

Categories