Python : pygame.key.get_pressed not working - python

I know that there are already some questions posted regarding the same issue but the solutions proposed didn't help me.
I want to monitor the state of the arrow keys (pressed/not pressed) at any given time so I have the following code:
import pygame
pygame.init()
a=[0,0,0,0]
while True:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
a[0]=1;
else:
a[0]=0;
if keys[pygame.K_RIGHT]:
a[1]=1;
else:
a[1]=0;
if keys[pygame.K_UP]:
a[2]=1;
else:
a[2]=0;
if keys[pygame.K_DOWN]:
a[3]=1;
else:
a[3]=0;
print a
pygame.event.pump()
So, basically, I keep printing a list a of 4 numbers, each representing an arrow key (1 if pressed, 0 otherwise).
However all values of the list are always zero even if i keep pressing the arrow keys for long.
I also tried printing the whole keys array : Turns out all entries are zeros again, no matter which keys I press and for how long
Any help would be greatly appreciated...
Thanks !
EDIT: Forgot to mention that I am using python 2.7 on windows 7

First off, if you haven't actually created a pygame window, no events will be passed to pygame and therefore the result of pygame.key.get_pressed() won't update. Pygame only receives events on the currrent pygame window. You're probably looking at the console, which is not receiving events. I added pygame.display.set_mode((100,100)) just after pygame.init() and then ran the program. I clicked inside the pygame window. Then the console start displaying the appropriate ones in the console.
Also suggest adding something to pause the loop like time.sleep and something like event checking to break out of it. (proper exiting)

Related

How to get a .Rect to follow another based on the x,y x direction and y direction on the one in front?

I've been working on a snake code for quite a while now. It is still rather primitive and very very basic. I have gotten the collisions to work, food generation and very basic movement. What I'm struggling on is figuring out the movement. Whenever you press WASD or the Arrow Keys it would move the head, and the "body" of the snake follows the part in front of it. So snakecol[1] follows snakecol[0] and so on.
Thank you in advance for any tips and pointers on how to improve my code.
#W to move up, A to move to the left, S to move down, D to move right.
#Snake by Juan Jaramillo
import pygame
import sys
import random
import math
import time
pygame.init()
screen=pygame.display.set_mode((500,500))
point=3
def collision():
global foodx
global foody
global x
global y
global xd
global yd
global point
global snakecol
if snakecol[0].colliderect(foodcol):
foodx=random.randint(0,24)*20
foody=random.randint(0,24)*20
point+=1
snakecol.append(snakecol[len(snakecol)-1])
if xd==20:
snakecol[len(snakecol)-1].x-=20
if xd==-20:
snakecol[len(snakecol)-1].x+=20
if yd==20:
snakecol[len(snakecol)-1].y-=20
if yd==-20:
snakecol[len(snakecol)-1].y==20
print "Snake is",point,"long."
red=(255,0,0)
blue=(0,0,255)
green=(0,255,0)
black=(0,0,0)
block1=0
block2=1
count=0
screen.fill(black)
randFood=random.randint(0,24)
x=60
y=0
foodx=randFood*20
foody=randFood*20
snakecol=list()
snakecol.append(pygame.Rect(x,y,20,20))
snakecol.append(pygame.Rect(x-20,y,20,20))
snakecol.append(pygame.Rect(x-40,y,20,20))
foodcol=pygame.Rect(foodx,foody,20,20)
xd=[20]
yd=[0]
##snakecol=pygame.Rect(x,y,20,20)
foodcol=pygame.Rect(foodx,foody,20,20)
done=False
while not done:
screen.fill(black)
collision()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
#controls
if block1==1:
if(pygame.key.get_pressed()[pygame.K_a]) or (pygame.key.get_pressed()[pygame.K_LEFT]):
yd[0]=0
xd[0]=-20
block1=0
block2=1
if block1==1:
if(pygame.key.get_pressed()[pygame.K_d]) or (pygame.key.get_pressed()[pygame.K_RIGHT]):
yd[0]=0
xd[0]=20
block1=0
block2=1
if block2==1:
if(pygame.key.get_pressed()[pygame.K_w]) or (pygame.key.get_pressed()[pygame.K_UP]):
xd[0]=0
yd[0]=-20
block1=1
block2=0
if block2==1:
if(pygame.key.get_pressed()[pygame.K_s]) or (pygame.key.get_pressed()[pygame.K_DOWN]):
xd[0]=0
yd[0]=20
block1=1
block2=0
#stop moving paddle
for m in range(0,len(snakecol)):
if snakecol[m].x<-20:
snakecol[m].x=500
if snakecol[m].x>500:
snakecol[m].x=-20
if snakecol[m].y<-20:
snakecol[m].y=500
if snakecol[m].y>500:
snakecol[m].y=-20
for m in range(0,len(snakecol)):
snakecol.pop
pygame.draw.rect(screen,(255,255,255),snakecol[m],0)
pygame.draw.rect(screen,(0,0,0),snakecol[m],1)
snakecol[m].x+=xd[0]
snakecol[m].y+=yd[0]
foodcol.x=foodx
foodcol.y=foody
pygame.draw.rect(screen,(255,255,255),(foodx,foody,20,20),0)
pygame.draw.rect(screen,(0,0,0),(foodx,foody,20,20),1)
pygame.display.flip()
time.sleep(0.4)
count+=1
pygame.quit()
The body blocks don't need to know the direction. You can just append a new head block (with the next x, y coords) to the list and remove the last block.
You could also use a collections.deque, pronounced "deck", a double ended queue which allows fast appends and pops on either end (although efficiency isn't really needed here, the code just looks a bit nicer).
A few more suggestions, you should check out how functions, classes and Pygame sprites work. There's a nice, free book about Python and Pygame called Program Arcade Games. Also, you shouldn't use global variables for everything, since they can make code really hard to understand (use classes).
Edit: To emphasize my answer above: Don't move the rects (the parts of the snake) in your list directly by changing their x and y values. Just pop or remove the last rect and append a new head rect. This will create the illusion of movement but the rects actually all stay at the same position.
I mentioned the deque, because it has efficient methods for popping and appending at the left end. For lists this is very inefficient, but I think it won't matter in your case, because the list won't grow too much and computers nowadays are very powerful.
Some code review (this should rather be in https://codereview.stackexchange.com/ though):
Line 132: You don't call pop because you forgot the parentheses. But if you actually called it, the snakecol list would shrink and the game would crash.
Handle the event loop first, then the game logic (e.g. collisions) and then the drawing. In a game class you would use different methods for these parts of the program.
You call pygame.key.get_pressed() several times. Instead assign the keys list to a variable keys = pygame.key.get_pressed() and use this variable later in the loop.
time.sleep is usually not used in Pygame (the game controls will seem to be unresponsive). There's the pygame.time.Clock class which you can use to limit the framerate and you can use a timer variable to keep track of when the snake can move. Instantiate a clock before the main loop clock = pygame.time.Clock() and in the loop you call clock.tick(enter_max_fps_here) every frame.

I'm trying to use pygame and need and interface [duplicate]

This question already has answers here:
How can I create a text input box with Pygame?
(5 answers)
Closed 2 years ago.
I'm making a program and I'd like to run it using pygame. The key thing is that I need an space for the user to input numbers and at the screen I need to print an array, which may vary in size (always 3 columns, but the user controls the number of lines), but I want it to always been fully shown in the screen. How can I make both things?
You can't expect people to write down code from scratch to accomplish what you want. If it is just advice you need, I can give some.
Pygame has no formal input field or input box introduced. If you want to implement such thing in pygame specifically, you have to keep record of the input keys(keyboard input). And insert the inputs in a string or list, then display them yourself. But you have to implement the methodology of the inputbox you designed, like you should have a condition for backspace where it deletes the last element of the list. Pygame does not do this formally, but you can write something like this.
However, what you need seems like a gui. Which gives a better way of taking inputs, making input fields, giving properties to the program window and the input boxes, making buttons etc.. In this case, if you change your mind, I would suggest Wxpython.
If you want to create a very simple text input box on your own, you could try to define an area with a pygame.Rect, then check if the mouse collides with the rect to select it and use the .unicode attribute of the keyboard events to attach the characters to a list or string which you can display on the screen.
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
your_input_string += event.unicode
There are also some GUI libraries for Pygame like SGC which is pretty easy to use. Alternatives (on pygame.org) are Albow, PGU and OcempGUI (the latter works only with Python 2.7).
This can be done using pygame_gui. Text input is available through a UITextEntryLine instance, while printing an array could be done using a UITextBox. You'll first need to set up the environment as in the quick start guide.
Create a UITextEntryLine instance:
from pygame.rect import Rect
from pygame_gui.elements.ui_text_entry_line import UITextEntryLine
text_input = UITextEntryLine(relative_rect=Rect(0, 0, 100, 100), manager=manager)
Input can be restricted to only numbers using set_allowed_characters:
text_input.set_allowed_characters('numbers')
Adding a check to the event queue allows for getting text input when enter is pressed:
for event in pygame.event.get():
if event.type == pygame.USEREVENT:
if event.user_type == pygame_gui.UI_TEXT_ENTRY_FINISHED:
if event.ui_element == text_input:
entered_text = text
A UITextBox can be set to a custom height by setting the height to -1:
from pygame_gui.elements.ui_text_box import UITextBox
text_box = UITextBox(relative_rect=Rect(0, 0, 100, -1), manager=manager, text='foobar')

event IDs and pygame.time.set_timer

i'm trying to make a simple basic program with pygame. one of the things im trying to make it do is create a randomly sized rectangle somewhere random on the screen in 6 seconds.
i'm very new to all of this, and I am also pretty new to python 2.7(I was learning 3.5 in class)
so far I have:
mob2_spawn = 0
def create_mob():
mob2 = pygame.Rect(random.randint(0,800), random.randint(0,600), random.randint(20,60), random.randint(30,50))
pygame.draw.rect(window_surface, mob_color, mob2)
pygame.display.update()
mob2_spawn = 1
if mob_spawn == 0:
pygame.time.set_timer(25,6000)
mob2_spawn = 1
how do I attach an event ID to something? I understand that the first variable in pygame.time.set_timer is the event id, and should be an integer between 25 and 32. and essentially the timer should run that function associated with that event id every X milliseconds correct
You need to check for an event, for example a button press. First you need to make pygame check for any button presses:
keystate = pygame.key.get_pressed()
Then you need to put this in your code, so that you have an event in your timer:
pygame.time.set_timer(keystate[pygame.K_SPACE], (25, 6000))
That's at least what I think should happen, by the way i'm using the example with the space button.
I hope it works for you!

Resize pygame window without losing keyboard state

I'm facing a problem with pygame 1.9.2 based on SDL 1.2.15: the only mean of resizing window programmatically I see is pygame.display.set_mode(...). But when I call this method my keyboard state is reset, so all currently pressed keys and modifiers send KEYUP event, repeated keys are stopped too.
When the window is resized manually by user keyboard state is perfectly normal. The event queue is paused for the time of resizing, then VIDEORESIZE and VIDEOEXPOSE events come up and keys are still pressed, if they were so.
There are few questions:
Is there a way to keep normal keyboard state while resizing window?
If not, I would like to at least keep modifier keys but I can not just use key.set_mods() because I am unable to get the moment when user releases key.
At last is there a way to invoke resizing of SDL window directly?
Example program demonstrates undesired behaviour. Left and right arrows resize window to same size, yet if they are pressed, there is only one keypress. Other keys are repeated normally if held. Output is event log for everything that happens.
import pygame
import sys
# same size all the time
size = (200, 200)
pygame.init()
pygame.display.set_mode(size, pygame.RESIZABLE)
# if left or right arrow key is held nothing will happen despite this line
pygame.key.set_repeat(500, 200)
run = True
while run:
for event in pygame.event.get():
out = '%s\t%s'%(event.type, str(event.dict))
if event.type == pygame.QUIT:
pygame.display.quit()
run = False
if event.type == pygame.KEYDOWN:
# mods are also reset on set_mode() call
out += ', mods = %i' % (pygame.key.get_mods())
if event.key == pygame.K_LEFT:
pygame.display.set_mode(size, pygame.RESIZABLE)
if event.key == pygame.K_RIGHT:
pygame.display.set_mode(size, pygame.RESIZABLE)
print(out)
pygame.time.Clock().tick(60)
Tested on Win machine but soon will report if linux fails too.
UPD: I've been digging into source of pygame and can not see why, but the documentation bundled with sources of pygame states, that Pygame can only have a single display active at any time. Creating a new one with pygame.display.set_mode() will close the previous display which implies that there is no way to resize window, only to recreate it. Seems a little strange to me.
UPD: I have changed my progam behaviour so that resize does not actually happen until user releases keyboard completely. It works well and does not break usability.
Nevertheless, it would be great to know if there exists a solution to stated problem.
One solution is, like self. has mentioned, to store the states of the keys so that instead of using only the events, you could ignore this particular key up event. This could, however, have one problem. If you are trying to create a key control to resize the screen, which you probably are doing, then you will also be ignoring the key up event that is real. Because this kind of control is rarely implemented, there does not seem to be any kind of clean solution, like a function to just change the screen, or one to suppress the false key events. However, you could find a way around the key event problem. There are really two viable solutions. The first one (and probably the worse of the two) is to create a way to identify the fake events, and selectively ignore the key up events. Probably the easiest way to do this is to resize the screen periodically during a fixed amount of time, so that you can expect a false keyboard event at this time, and ignore it. Here is an example of the code to block a resize every second (specifically, it assumes a screen update occurs every time the system time has an exact second value, no fractions of a second) for the a key:
import pygame
import datetime
a_keydown = False
for event in pygame.event.get():
if item.type == pygame.KEYDOWN and item.key == pygame.K_a:
a_keydown = True
print "keydown event"
if item.type == pygame.KEYUP and item.key == pygame.K_a:
if datetime.datetime.now().time()[4] > 15: #leaves a window of fifteen microseconds for the screen resize, this may need to be adjusted
a_keydown = False
print "key up event"
The better of the two solutions is not this, however. Assuming the keyup event created by set_mode exists soley in python, you could get key events from elsewhere, like pywin32 for example. Try using the win32api module, and something like the GetKeyState() function for what you need. This will give you the last known state of a key. Not quite as convenient as pythons event stream, but it may be your best solution, as pygame doesn't supply an elegant solution to this.

Pygame not recognising 1 key?

I have been making a game using pygame in python and it refuses to identify the 1 key.
if event.type == KEYDOWN and event.key == K_1:
print("pass")
started = True
I added the "pass" to check if something else is wrong but nothing happens. I have used a few other keys like up, down, w, s and enter which work but it won't recognize any numbers.
If it helps, I am using a Trust Xpress wireless keyboard.
In regard to Dominic's question , I have tried both number pad and standard keys.
Your problem probably has nothing to do with your keyboard.
You probably just left numb lock off and are using the keypad.
If not, get the window to print all events and see if anything comes up when you press the 1 key.
It should be 49, but if it's not, just use whatever it is.
If nothing comes up at all, and you can't use the keyboard elsewhere, then it is something wrong with your keyboard.

Categories