简体   繁体   English

Pygame中的光滑键盘运动

[英]Smooth Keyboard Movement in Pygame

I'm using this code to have a player sprite move around a screen when the arrow keys are pressed: 当按下箭头键时,我正在使用此代码让玩家精灵在屏幕上移动:

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)

The image is able to actually move, but only 5 pixels when the key is pressed. 图像能够实际移动,但按下按键时只能移动5个像素。 I want for the image to keep moving while the key is held down (and to add basic collision detection with the window, but that's a different issue). 我希望图像在按住键的同时保持移动(并且在窗口中添加基本的碰撞检测,但这是一个不同的问题)。 What would make the image keep moving while the key is pressed down? 当按下按键时,图像会继续移动的原因是什么?

I suggest using variables to keep track of which arrow keys are pressed and which are not. 我建议使用变量来跟踪哪些箭头键被按下,哪些不是。 You can use the KEYDOWN and KEYUP events to update the variables. 您可以使用KEYDOWNKEYUP事件来更新变量。 Then you can adjust the position of the sprite each frame based on which keys are pressed. 然后,您可以根据按下的键调整每帧精灵的位置。 This also means you can easily set the speed of the sprite in different directions by changing how far it moves each frame. 这也意味着您可以通过改变每帧移动的距离,轻松地在不同方向上设置精灵的速度。

EDIT: 编辑:

Or as @monkey suggested, you can use key.get_pressed() instead. 或者如@monkey建议的那样,您可以使用key.get_pressed()代替。

Here's an untested example: 这是一个未经测试的例子:

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)

I would suggest using the set_repeat function. 我建议使用set_repeat函数。 Held keys generate multiple events, periodically(which is set by the function's parameters).This allows you to use your code unmodified (no need for extra variables). Held键定期生成多个事件(由函数的参数设置)。这允许您不加修改地使用您的代码(不需要额外的变量)。

The function prototype: 功能原型:

set_repeat(delay, interval) set_repeat(延迟,间隔)

The first parameter delay is the number of milliseconds before the first repeated pygame.KEYDOWN will be sent. 第一个参数延迟是第一个重复的pygame.KEYDOWN发送之前的毫秒数。 After that another pygame.KEYDOWN will be sent every interval milliseconds. 之后,每隔一个毫秒发送另一个pygame.KEYDOWN。 If no arguments are passed the key repeat is disabled. 如果没有传递参数,则禁用密钥重复。

Simply use this function before the main loop. 只需在主循环之前使用此功能。

 pygame.key.set_repeat(10,10)

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

I did it like this: 我是这样做的:

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)

I would do this by taking a slightly different course of action inside the loop. 我会通过在循环内采取略微不同的动作来做到这一点。

To update the sprite, I would first check for a KEYDOWN event and then set direction based on that. 要更新精灵,我首先检查KEYDOWN事件,然后根据它设置direction Then, I would update sprite , spritex , and spritey based on direction . 然后,我会根据direction更新spritespritexspritey Then, I would check for KEYUP events and set direction based on that, if appropriate. 然后,我会检查KEYUP事件并根据需要设置direction (如果适用)。

Here's how I might code it: 以下是我编写代码的方法:

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM