python 如何在Pygame中有效地持有密钥?

g6ll5ycj  于 2023-06-20  发布在  Python
关注(0)|答案(8)|浏览(125)

我发现了两个相关的问题:

但我想说的具体点。怎么做?

while not done:
    for e in event.get():
        if e.type == KEYDOWN:
            keys = key.get_pressed()
            if e.type == QUIT or keys[K_ESCAPE]:
                done = True
            if keys[K_DOWN]:
                print "DOWN"

当我按下向下箭头时,它会打印,但它只打印一次。如果我想下次打印,我需要再按一次。
如果我使用while关键字,

while keys[K_DOWN]:
    print "DOWN"

我得到了一个无限的循环因为一些模糊的原因。
这个逻辑替代方案也是无用的:

if ((e.type == KEYDOWN) and keys[K_DOWN]):
    print "DOWN"

还有另一个用来清理事件的方法,你可以使用while:

while not done:
    for e in event.get():
        if e.type == KEYDOWN:
            keys = key.get_pressed()
            if e.type == QUIT or keys[K_ESCAPE]:
                done = True
            while keys[K_DOWN]:
                print "DOWN"
                event.get()
                keys = key.get_pressed()

但是你按下向下键不到一秒钟,它就打印了数千次。(移动一个球员是不可能的,为此调整时钟似乎不是处理它的正确方法(我尝试过,但我失败得很惨)。
按下并执行块数千次是无用的。我想要的,是按下键,在我不释放的情况下继续进行动作,在规定的游戏时钟速度内。

bis0qfac

bis0qfac1#

不要混淆event.get()key.get_pressed()
如果您按下或释放一个键,事件将被放入事件队列,您可以使用event.get()查询。如果您实际感兴趣的是某个键被物理按下或释放(这些是实际的键盘事件),请执行此操作。请注意,KEYDOWN得到多次添加到队列,这取决于键重复设置)。
此外,在处理KEYDOWN事件时,不需要查询所有键的状态,因为您已经通过检查event.key知道哪个键被按下了
如果你对一个键是否被按住感兴趣(忽略你可能想要的key-repeat),那么你应该简单地使用key.get_pressed()。使用一堆标志是不必要的,而且会使代码变得混乱。
因此,您的代码可以简化为:

while not done: 
    keys = key.get_pressed() 
    if keys[K_DOWN]: 
        print "DOWN" 
    for e in event.get(): 
        pass # proceed other events. 
             # always call event.get() or event.poll() in the main loop
jbose2ul

jbose2ul2#

我不熟悉Pygame,但是,正如我所看到的,它的程序应该有一个基于事件的架构。除非您获取传入的事件并处理它们,否则什么也不会发生。这就是为什么你的简单循环变成无限循环的原因:它只是不处理事件。

while keys[K_DOWN]: # Nobody updates the keys, no events are processed
    print "DOWN"

关于get_pressed()调用。它返回的是一个键列表。所以,你试图循环,直到键被释放。这是个问题根据this,即使队列中没有事件,pygame.event.get()也会立即返回。调用get()意味着:我的代码仍然有要做的事情,但我不想阻止事件,所以请在我继续之前处理挂起的事件。如果你的代码只是在等待一个事件,那就意味着它没有什么要做的。
事件的WAIT(不阻塞Pygame的内部循环)函数是pygame.event.wait()(逻辑是:我在代码中没有什么要做的,直到发生一些事情)。但是,如果使用它,则必须从事件本身而不是从get_pressed()获取有关按键按下或释放的信息。
下面是文档页面注解的示例:

for event in pygame.event.get() :
  if event.type == pygame.KEYDOWN :
    if event.key == pygame.K_SPACE :
      print "Space bar pressed down." #Here you should put you program in the mode associated with the pressed SPACE key
    elif event.key == pygame.K_ESCAPE :
      print "Escape key pressed down."
  elif event.type == pygame.KEYUP :
    if event.key == pygame.K_SPACE :
      print "Space bar released."
    elif event.key == pygame.K_ESCAPE :
      print "Escape key released." #Time to change the mode again
jexiocij

jexiocij3#

我想用一种稍微不同的方法来解决这个问题。不是检查键是否被按下并在按下时采取一些操作,而是在键按下时设置一个标志,并在键按下时取消设置。然后在更新玩家位置的功能中,检查旗帜并相应地更新。下面的pseudo-Python解释了我的意思:

if down_key_pressed:
    down_flag = True
elif down_key_released:
    down_flag = False
elif right_key_pressed:
    etc...

这应该在接受玩家输入的单独循环中完成。在update_player_position()中,你可以:

if down_flag:
    move_player_down()
elif right_flag:
    move_player_right()

这个例子假设了四个方向的移动,但是您可以很容易地将它扩展到八个方向,只需使用if down_flag and right_flag

bq3bfh9z

bq3bfh9z4#

如果使用pygame.key.set_repeat(# millisecond)设置每个按键事件的时间限制,则可以重复获取keydown事件。引用:当键盘重复被启用时,按住的键将生成多个pygame.KEYDOWN事件。延迟是第一次重复pygame之前的毫秒数。KEYDOWN将被发送。之后,每隔毫秒发送另一个pygame.KEYDOWN。如果没有传递参数,则禁用重复键。**当pygame初始化时,密钥重复被禁用。**请参阅以下链接以了解详细信息http://www.pygame.org/docs/ref/key.html#pygame.key.set_repeat

fnatzsnv

fnatzsnv5#

我使用了一种不同的方法来按住一个键,这是我在向左或向右移动对象的特定任务中使用的。
我不关心计算机是否知道一个键实际上被按下了。
当我按下一个键时,我为该键定义的变量(例如:左箭头)设置为True。直到该键被取消按下(带有事件pygame.KEYUP),“向左移动”才被执行。

6pp0gazn

6pp0gazn6#

Dominik的解决方案是完美的(将event.get()与键盘的分离)。它的工作完美!最后,pygame的输入没有问题了。
标志:

flag = False # The flag is essential.
while not done:
    for e in event.get(): # At each frame it loops through all possible events.
        keys = key.get_pressed() # It gets the states of all keyboard keys.
        if e.type == QUIT:
            done = True
        if e.type == KEYDOWN: # If the type is KEYDOWN (DIFFERENT FROM "HELD").
            if keys[K_DOWN]: # And if the key is K_DOWN:
                flag = True # The flag is set to true.
        elif e.type == KEYUP: # The very opposite.
            if keys[K_DOWN]:
                flag = False
    if flag == True: # DON'T USE "while flag == true", it'll crash everything. At every frame, it'll check if the flag is true up there. It's important to remember that the KEYDOWN worked ONLY ONCE, and it was enough to set that flag. So, at every frame, THE FLAG is checked, NOT THE KEYDOWN STATE. Every "player movement" while a key is being held MUST be done through flags.
        print "DOWN"
tgabmvqs

tgabmvqs7#

如果我们参考pygame文档,有一个函数名为:

pygame.key.set_repeat()

这将设置按住键时的行为,默认行为是仅触发一个事件。如果要多次触发事件,请在调用

pygame.init()

要获得所需的效果,可以传入一个参数,该参数表示pygame将重复按键事件的间隔。
不要像以前那样使用while语句,因为它只需要关键事件为真一次,就可以将程序锁定在无休止的迭代中。

rsl1atfo

rsl1atfo8#

这就是我是怎么做的,好,去www.cswonders.com,它可能会帮助你。转到级别3,然后转到3.6,并完成教程。我从那里学到的。这是我的代码。

def update(self):
    self.speedx = 0
    self.speedy = 0
    # If left or right key is pressed, move left or right
    pressed_key = pygame.key.get_pressed()
    if pressed_key[pygame.K_LEFT]: 
        self.speedx = -10          
    if pressed_key[pygame.K_RIGHT]:
        self.speedx = 10
    if pressed_key[pygame.K_UP]:
        self.speedy = -10
    if pressed_key[pygame.K_DOWN]:
        self.speedy = 10

    self.rect.x += self.speedx
    self.rect.y += self.speedy

    # No further move if off screen
    if self.rect.right > SCREEN_WIDTH:
        self.rect.right = SCREEN_WIDTH
    if self.rect.left < 0:
        self.rect.left = 0

相关问题