【问题标题】:How do I make two keys respond at the same time?如何让两个键同时响应?
【发布时间】:2014-06-30 14:41:35
【问题描述】:

我目前正在用python制作乒乓球游戏:

但是,假设球是粉红色的,黄色的人决定向他的ws 密钥发送垃圾邮件。然后他的桨将开始移动(很好),但随后粉红色的会停止(不好)。

python可以同时监听两个事件键吗?

代码如下:

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

如果同时有 2 个按键,我如何让它独立处理每个按键?

【问题讨论】:

  • 我相信你会想看看threading
  • 您确定这是 Python 问题而不是键盘问题吗?您的代码应该在每个游戏循环中独立处理所有 4 个事件,但如果您的键盘只能同时发送 2 次按键,它就不会执行任何操作。
  • 没错。如果同时有 2 个按键,我如何让它独立处理每个按键?

标签: python python-2.7 pygame


【解决方案1】:

我同意 SilasRay 的观点,几乎可以肯定这不是线程阻塞的问题,但如果是:这应该可以解决它(因此,如果没有,这是你的键盘或 Silas 提到的 SDL 层的问题) .无论如何,用你的桨制作物体是很重要的,所以无论如何都要考虑做那部分。线程部分在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)

【讨论】:

  • +1 表示对象建议。通往更高效渲染系统的一个很好的步骤是开始使用 Pygame 的 sprite 和 sprite 组对背景进行选择性 blitting,而不是每次都从头开始重新渲染整个帧。
【解决方案2】:

经过一番研究,我认为这实际上是一个 SDL 事件队列溢出问题。 SDL 是 PyGame 的事件系统建立在其之上的 C 事件库。根据我的阅读,事件队列有 128 个事件限制,之后添加的新事件将被简单地丢弃,直到队列被刷新。

您的渲染逻辑效率不高,并且您已将输入轮询率绑定到渲染逻辑(您在每个游戏循环中重新渲染整个屏幕、球拍和球,然后轮询事件队列,所以你清空事件队列的速度不能比从头开始渲染整个帧的速度快)。我认为你需要在这里做的是改进你的渲染逻辑(看看你如何可以擦除/重绘精灵的一部分而不是刷新整个缓冲区)并通过将渲染放在单独的线程中来解除事件轮询与渲染。

【讨论】:

  • 对于 OP:通常你会运行两个不同的线程,一个命名为例如update 和一个命名的东西,例如draw,第一个处理所有数据处理(事件绑定等),第二个处理在屏幕上的绘制。将 update 函数限制为仅在设定的时间后运行(通常为 60/秒),这样更快的计算机就不会获得优势。
  • @AdamSmith 或者只使用在单独线程中渲染的三重缓冲显示系统,并且只有在 2 个后台缓冲区之一完成渲染后才让主游戏循环翻转到新帧。
【解决方案3】:

我认为你需要使用线程,否则程序总是顺序的。

检查这个例子:

Make 2 functions run at the same time

尝试将while True 放在每个线程的函数中,以便两者都响应命令。

【讨论】:

  • 你能再深入一点吗?
  • 这个想法是让你有两个线程,一个用于处理 player1 键事件,另一个用于处理 player2。
    您的 while true 循环将在主程序上,带有第一个 if 子句,以便它处理退出键。
    player1 while true 循环,在函数内部定义(替换“工作”示例)将具有 S 和 W 键。
    player2 while true 循环,在函数内部定义(替换“工作”示例)将具有 UP 和 DOWN 键。
  • 我不确定它是否这么简单。 @Pimenta,你以前真的在 PyGame 工作过吗?我一直在阅读,看起来问题出在 PyGame 底层的 SDL 事件系统上。 SDL 似乎不能很好地跨线程抽取/刷新。相反,我认为通过在单独的线程中渲染他的 GUI 可能会更好地为 OP 提供服务,然后仅在下一帧准备好时翻转缓冲区,以便键盘采样可以以更高的速率运行(从而回避 SDL 缓冲区大小限制)而不是 GUI 渲染。
  • 您好。 @SilasRay我没有尝试过这个例子。我试图解决多键问题。感谢您的指示。这是另一个使用 PyGame 解决的问题link 当我有时间时,我将自己尝试这个示例并检查我的计算机/键盘的行为。
【解决方案4】:

正如我上面所说,我只使用了pygame.key.set_repeat(1, 10),以便即使按下键,事件也会发生。

我发现了另一种方法来做同样的事情,使用pygame.key.get_pressed()[pygame.DESIRED_KEY]

pygame.key.get_pressed() 返回如下元组:

(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

当按下特定键时,0 会变成1,使我们能够使用if pygame.key.get_pressed()[pygame.DESIRED_KEY]

这是您编辑的代码:

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

【讨论】:

    【解决方案5】:

    在我正在制作的游戏中,角色可以向各个方向移动,我这样做是为了当你按下一个键时,而不是直接改变角色的 x 和 y,它只是使变量之一 moveLeft 、moveRight、moveUp 或 moveDown(取决于按下的键) True。然后你必须做一个单独的东西,当钥匙被抬起时把它关掉。稍后在循环中检查每个变量是否为真,并根据按下的键移动字符。另外,我不明白为什么会有 Try 循环。

    你可以把主循环改成这样:

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

    【讨论】:

      猜你喜欢
      • 2018-08-31
      • 1970-01-01
      • 1970-01-01
      • 2013-04-29
      • 2021-06-21
      • 1970-01-01
      • 1970-01-01
      • 2020-01-04
      • 2017-07-05
      相关资源
      最近更新 更多