Reputation: 901
I am currently making a pong game in python:
However, say the ball is coming at pink, and the yellow guy decides to spam his w
and s
keys. Then his paddle will start moving (fine), but then the pink one will stop (not fine).
Is it possible for python to listen to two event keys simultaneously?
Here is the code:
import pygame, sys
from pygame.locals import *
pygame.init()
DISPLAYSURF = pygame.display.set_mode((1439, 790))
YELLOW = (255, 255, 0)
PINK = (255, 0, 255)
BLUE = (120, 214, 208)
y1, y2 = (0, 0)
circx, circy = (1439//2, 790//2)
diffx, diffy = (15, 15)
pygame.key.set_repeat(1, 10)
while True:
if (0 <= circy <= 780) == False:
diffy*=-1
if circx <= 60 and y1-10 <= circy <= y1+75:
diffx*=-1
if circx >= 1439-60 and y2-10 <= circy <= y2+75:
diffx*=-1
if (0 <= circx <= 1439) == False:
circx, circy = (720, 395)
DISPLAYSURF.fill((0, 0, 0))
pygame.draw.rect(DISPLAYSURF, YELLOW, (50, y1, 10, 75))
pygame.draw.rect(DISPLAYSURF, PINK, (1439-60, y2, 10, 75))
pygame.draw.circle(DISPLAYSURF, BLUE, (circx, circy), 10)
circx+=diffx
circy+=diffy
try:
for event in pygame.event.get():
if event.type == QUIT or event.key == pygame.K_ESCAPE or event.key == pygame.K_q:
pygame.quit()
sys.exit()
if event.key == pygame.K_w:
y1-=15
if event.key == pygame.K_s:
y1+=15
if event.key == pygame.K_UP:
y2-=15
if event.key == pygame.K_DOWN:
y2+=15
except AttributeError:
pass
pygame.display.flip()
How do I make it independently handle each key press if there are 2 simultaneous ones?
Upvotes: 2
Views: 4084
Reputation: 13
In a game that I'm making, where the character can move in all directions, I made it so that when you press a key, rather than directly changing the character's x and y, it simply makes one of the variables moveLeft, moveRight, moveUp, or moveDown (depending on which key is pressed) True. Then you have to make a seperate thing that turns it off when the key is lifted. Later in the loop it checks whether each variable is True, and moves the character based on which keys are pressed. Plus, I don't understand why the Try loop is there.
You could change the main loop to this:
p1moveup = False
p1movedown = False
p2moveup = False
p2movedown = False
while True:
if (0 <= circy <= 780) == False:
diffy*=-1
if circx <= 60 and y1-10 <= circy <= y1+75:
diffx*=-1
if circx >= 1439-60 and y2-10 <= circy <= y2+75:
diffx*=-1
if (0 <= circx <= 1439) == False:
circx, circy = (720, 395)
DISPLAYSURF.fill((0, 0, 0))
pygame.draw.rect(DISPLAYSURF, YELLOW, (50, y1, 10, 75))
pygame.draw.rect(DISPLAYSURF, PINK, (1439-60, y2, 10, 75))
pygame.draw.circle(DISPLAYSURF, BLUE, (circx, circy), 10)
circx+=diffx
circy+=diffy
for event in pygame.event.get():
if event.type == QUIT or event.key == pygame.K_ESCAPE or event.key == pygame.K_q:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
p1moveup = True
if event.key == pygame.K_s:
p1movedown = True
if event.key == pygame.K_UP:
p2moveup = True
if event.key == pygame.K_DOWN:
p2movedown = True
if event.type === pygame.KEYUP:
if event.key == pygame.K_w:
p1moveup = False
if event.key == pygame.K_s:
p1movedown = False
if event.key == pygame.K_UP:
p2moveup = False
if event.key == pygame.K_DOWN:
p2movedown = False
if p1moveup == True:
y1-=15
if p1movedown == True:
y1+=15
if p2moveup == True:
y2-=15
if p2movedown == True:
y2+=15
pygame.display.flip()
Upvotes: 0
Reputation: 901
As I said above, I used pygame.key.set_repeat(1, 10)
only so that even while the key was held down the event would occur.
I discovered an alternate way to do the same, using pygame.key.get_pressed()[pygame.DESIRED_KEY]
.
pygame.key.get_pressed()
returns a tuple such as the following:
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
When a specific key is pressed down, then the 0
turns into a 1
, enabling us to use if pygame.key.get_pressed()[pygame.DESIRED_KEY]
.
Here is your edited code:
import pygame, sys
from pygame.locals import *
pygame.init()
DISPLAYSURF = pygame.display.set_mode((1439, 790))
YELLOW = (255, 255, 0)
PINK = (255, 0, 255)
BLUE = (120, 214, 208)
y1, y2 = (0, 0)
circx, circy = (1439//2, 790//2)
diffx, diffy = (15, 15)
pygame.key.set_repeat(1, 10)
while True:
if pygame.key.get_pressed()[pygame.K_UP]:
y1-=15
if pygame.key.get_pressed()[pygame.K_DOWN]:
y1+=15
if pygame.key.get_pressed()[pygame.K_w]:
y2-=15
if pygame.key.get_pressed()[pygame.K_s]:
y2+=15
if (0 <= circy <= 780) == False:
diffy*=-1
if circx <= 60 and y1-10 <= circy <= y1+75:
diffx*=-1
if circx >= 1439-60 and y2-10 <= circy <= y2+75:
diffx*=-1
if (0 <= circx <= 1439) == False:
circx, circy = (720, 395)
DISPLAYSURF.fill((0, 0, 0))
pygame.draw.rect(DISPLAYSURF, YELLOW, (50, y1, 10, 75))
pygame.draw.rect(DISPLAYSURF, PINK, (1439-60, y2, 10, 75))
pygame.draw.circle(DISPLAYSURF, BLUE, (circx, circy), 10)
circx+=diffx
circy+=diffy
try:
for event in pygame.event.get():
if event.type == QUIT or event.key == pygame.K_ESCAPE or event.key == pygame.K_q:
pygame.quit()
sys.exit()
except AttributeError:
pass
pygame.display.flip()
Upvotes: 0
Reputation: 26160
After some research, I think this is actually an SDL event queue overflow problem. SDL is a C event library that PyGame's event system is built on top of. From what I've read, the event queue has a 128 event limit, after which new events being added are simply dropped until the queue is flushed.
Your rendering logic isn't very efficient, and you've bound your input poll rate to your rendering logic (you re-render the entire screen, paddles, and ball every game loop, and then you poll the event queue, so you can't empty the event queue any faster than you can render an entire frame from scratch). I think what you need to do here is improve your render logic (look at how you can erase/redraw just portions of a sprite instead of flushing the entire buffer) and unbind event polling from rendering by putting rendering in a separate thread.
Upvotes: 1
Reputation: 54273
I agree with SilasRay that this is almost certainly NOT an issue with thread blocking, but if it is: this should fix it (therefore if it doesn't, it's an issue with your keyboard or the SDL layer that Silas mentioned). It's kind of important to be making objects out of your Paddles anyway, so think about doing that part anyhow. The thread section is in paddlelisten()
.
import threading
class Paddle(object):
def __init__(self, posx, color):
self.posx = posx
self.posy = 0
self.color = color
@property
def pos():
return (self.posx, self.posy, 10, 75)
def main():
# the logic for the program
p1_paddle = Paddle(50, YELLOW)
p2_paddle = Paddle(1439-60, PINK)
def paddlelisten(paddle, upkey, downkey):
if event.key == upkey:
paddle.posy -= 15
if event.key == pygame.downkey:
paddle.posy += 15
t1 = threading.Thread(target=lambda: paddlelisten(p1_paddle, pygame.K_w, pygame.K_s))
t2 = threading.Thread(target=lambda: paddlelisten(p2_paddle, pygame.K_UP, pygame.K_DOWN))
for t in [t1, t2]:
t.daemon = True
t.start()
while True:
# game loop
pygame.draw.rect(DISPLAYSURF, p1_paddle.color, p1_paddle.pos)
pygame.draw.rect(DISPLAYSURF, p2_paddle.color, p2_paddle.pos)
Upvotes: 1
Reputation: 1109
I think you need to use threads otherwise the program is always sequencial.
Check this example:
Make 2 functions run at the same time
Try to put the while True
in each thread's function so that both responde to commands.
Upvotes: 0