【问题标题】:Smooth Keyboard Movement in PygamePygame 中的平滑键盘移动
【发布时间】:2012-12-14 18:53:34
【问题描述】:

我正在使用此代码让玩家精灵在按下箭头键时在屏幕上移动:

import pygame, sys, time
from pygame.locals import *

pygame.init()

FPS=30
fpsClock=pygame.time.Clock()

width=400
height=300
DISPLAYSURF=pygame.display.set_mode((width,height),0,32)
pygame.display.set_caption('Animation')
background=pygame.image.load('bg.png')


UP='up'
LEFT='left'
RIGHT='right'
DOWN='down'

sprite=pygame.image.load('down.png')
spritex=200
spritey=130
direction=DOWN


pygame.mixer.music.load('bgm.mp3')
pygame.mixer.music.play(-1, 0.0)
while True:
    DISPLAYSURF.blit(background,(0,0))

    DISPLAYSURF.blit(sprite,(spritex,spritey))

    for event in pygame.event.get():
        if event.type==QUIT:
            pygame.quit()
            sys.exit()

        if event.type == KEYDOWN:
            if (event.key == K_LEFT):
                spritex-=5
                sprite=pygame.image.load('left.png')
            elif (event.key == K_RIGHT):
                spritex+=5
                sprite=pygame.image.load('right.png')
            elif (event.key == K_UP):
                spritey-=5
                sprite=pygame.image.load('up.png')
            elif (event.key == K_DOWN):
                spritey+=5
                sprite=pygame.image.load('down.png')

    pygame.display.update()
    fpsClock.tick(FPS)

图像可以实际移动,但按键时只有 5 个像素。我希望图像在按住键时继续移动(并添加与窗口的基本碰撞检测,但这是一个不同的问题)。什么会在按下键时使图像保持移动?

【问题讨论】:

  • 我推荐 4 个空格缩进而不是制表符。

标签: python animation pygame sprite game-physics


【解决方案1】:

我建议使用变量来跟踪哪些箭头键被按下,哪些没有。您可以使用KEYDOWNKEYUP 事件来更新变量。然后,您可以根据按下的键调整每帧精灵的位置。这也意味着您可以通过更改每帧移动的距离来轻松设置精灵在不同方向上的速度。

编辑:

或者按照@monkey 的建议,您可以改用key.get_pressed()

这是一个未经测试的例子:

while True:
    DISPLAYSURF.blit(background,(0,0))

    DISPLAYSURF.blit(sprite,(spritex,spritey))

    for event in pygame.event.get():
        if event.type==QUIT:
            pygame.quit()
            sys.exit()

        if event.type == KEYDOWN:
            if (event.key == pygame.K_LEFT):
                sprite=pygame.image.load('left.png')
            elif (event.key == pygame.K_RIGHT):
                sprite=pygame.image.load('right.png')
            elif (event.key == pygame.K_UP):
                sprite=pygame.image.load('up.png')
            elif (event.key == pygame.K_DOWN):
                sprite=pygame.image.load('down.png')

    keys_pressed = pygame.key.get_pressed()

    if keys_pressed[pygame.K_LEFT]:
        spritex -= 5

    if keys_pressed[pygame.K_RIGHT]:
        spritex += 5

    if keys_pressed[pygame.K_UP]:
        spritey -= 5

    if keys_pressed[pygame.K_DOWN]:
        spritey += 5

    pygame.display.update()
    fpsClock.tick(FPS)

【讨论】:

  • 如果您使用key.get_pressed(),您不需要为每个键添加额外的变量。如果按下[K_LEFT],您的逻辑将是:做事。
  • OP 一次只会在一个主要方向上移动,但如果按下多个按钮,您的解决方案将在多个方向上移动。
  • @Sam Mussmann:我假设需要多个方向,但可以通过使用单个 if 语句来调整精灵的位置(elif keys_pressed... 而不是if keys_pressed...)轻松更改它。
  • 我比我自己更喜欢这个解决方案。我什至没有考虑沿对角线移动。
【解决方案2】:

我建议使用 set_repeat 函数。持有的键会定期生成多个事件(由函数的参数设置)。这允许您使用未经修改的代码(不需要额外的变量)。

函数原型:

set_repeat(延迟,间隔)

第一个参数delay是第一个重复的pygame.KEYDOWN被发送之前的毫秒数。之后,另一个 pygame.KEYDOWN 将每间隔毫秒发送一次。如果未传递任何参数,则禁用键重复。

只需在主循环之前使用此函数即可。

 pygame.key.set_repeat(10,10)

来源:http://www.pygame.org/docs/ref/key.html#pygame.key.set_repeat

【讨论】:

  • 谢谢 - 这个解决方案实现起来要简单得多
【解决方案3】:

我是这样做的:

import pygame, sys, time
from pygame.locals import *

pygame.init()

FPS=30
fpsClock=pygame.time.Clock()

width=400
height=300
DISPLAYSURF=pygame.display.set_mode((width,height),0,32)
pygame.display.set_caption('Animation')
background=pygame.image.load('bg.png')


UP='up'
LEFT='left'
RIGHT='right'
DOWN='down'

sprite=pygame.image.load('down.png')
spritex=200
spritey=130
direction=None

def move(direction, sprite, spritex, spritey):
    if direction:
        if direction == K_UP:
            spritey-=5
            sprite=pygame.image.load('up.png')
        elif direction == K_DOWN:
            spritey+=5
            sprite=pygame.image.load('down.png')
        if direction == K_LEFT:
            spritex-=5
            sprite=pygame.image.load('left.png')
        elif direction == K_RIGHT:
            spritex+=5
            sprite=pygame.image.load('right.png')
    return sprite, spritex, spritey

pygame.mixer.music.load('bgm.mp3')
pygame.mixer.music.play(-1, 0.0)
while True:
    DISPLAYSURF.blit(background,(0,0))

    DISPLAYSURF.blit(sprite,(spritex,spritey))

    for event in pygame.event.get():
        if event.type==QUIT:
            pygame.quit()
            sys.exit()

        if event.type == KEYDOWN:
            direction = event.key
        if event.type == KEYUP:
            if (event.key == direction):
                direction = None
    sprite, spritex, spritey = move(direction, sprite, spritex, spritey)

    pygame.display.update()
    fpsClock.tick(FPS)

【讨论】:

  • 我想你只需要一个if (event.key == direction)
  • 另外,如果direction 是我们想要的之一,你不能设置direction = event.key 吗?用一组检查成员资格?
  • 甚至没有必要,因为移动功能在其他情况下不会做任何事情。
  • 虽然如果你按住左箭头,然后按下并释放'a'键,这可能会表现得很奇怪。
  • 是的,如果你按下任何其他键,它就会停止移动。
【解决方案4】:

我会通过在循环内采取稍微不同的行动来做到这一点。

要更新精灵,我会首先检查KEYDOWN 事件,然后根据它设置direction。然后,我将根据direction 更新spritespritexspritey。然后,我会检查KEYUP 事件,并在此基础上设置direction(如果合适)。

下面是我的编码方式:

sprite=pygame.image.load('down.png')
spritex=200
spritey=130
direction='down'

dir_from_key = {
  K_LEFT: 'left',
  K_RIGHT: 'right',
  K_UP: 'up',
  K_DOWN: 'down'
}

pygame.mixer.music.load('bgm.mp3')
pygame.mixer.music.play(-1, 0.0)
while True:
    DISPLAYSURF.blit(background,(0,0))

    DISPLAYSURF.blit(sprite,(spritex,spritey))

    # Get all the events for this tick into a list
    events = list(pygame.event.get()) 

    quit_events = [e for e in events if e.type == QUIT]
    keydown_events = [e for e in events if e.type == KEYDOWN 
                                           and e.key in dir_from_key]
    keyup_events = [e for e in events if e.type == KEYUP 
                                         and e.key in dir_from_key]

    # If there's no quit event, then the empty list acts like false
    if quit_events:
        pygame.quit()
        sys.exit()

    # Non-last key down events will be overridden anyway
    if keydown_events:
      direction = dir_from_key[keydown_events[-1].key]

    # Change location and image based on direction
    if direction == 'left':
      spritex-=5
      sprite=pygame.image.load('left.png')
    elif direction == 'right':
      spritex+=5
      sprite=pygame.image.load('right.png')
    elif direction == 'up':
      spritey-=5
      sprite=pygame.image.load('up.png')
    elif direction == 'down':
      spritey+=5
      sprite=pygame.image.load('down.png')

   # If there's a keyup event for the current direction.
   if [e for e in keyup_events if dir_from_key[e.key] == direction]:
      direction = None

   pygame.display.update()
   fpsClock.tick(FPS)

【讨论】:

    猜你喜欢
    • 2016-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    • 2015-01-05
    • 1970-01-01
    • 2014-05-18
    • 1970-01-01
    相关资源
    最近更新 更多