Python Pygame 中的平滑键盘移动
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14087609/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Smooth Keyboard Movement in Pygame
提问by oracleCreeper
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. 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?
图像能够实际移动,但按下键时只能移动 5 个像素。我希望图像在按住键的同时保持移动(并添加与窗口的基本碰撞检测,但这是一个不同的问题)。当按键被按下时,什么会使图像保持移动?
采纳答案by grc
I suggest using variables to keep track of which arrow keys are pressed and which are not. You can use the KEYDOWNand KEYUPevents to update the variables. 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.
我建议使用变量来跟踪哪些箭头键被按下,哪些没有被按下。您可以使用KEYDOWN和KEYUP事件来更新变量。然后您可以根据按下的键调整每帧精灵的位置。这也意味着您可以通过更改每帧移动的距离来轻松设置精灵在不同方向上的速度。
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)
回答by Sam Mussmann
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 KEYDOWNevent and then set directionbased on that. Then, I would update sprite, spritex, and spriteybased on direction. Then, I would check for KEYUPevents and set directionbased on that, if appropriate.
为了更新精灵,我会首先检查一个KEYDOWN事件,然后direction根据它进行设置。然后,我将更新sprite,spritex以及spritey基于direction。然后,如果合适,我会检查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)
回答by jgritty
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)
回答by agent_Jay
I would suggest using the set_repeat function. 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).
我建议使用 set_repeat 函数。持有的键会定期生成多个事件(由函数的参数设置)。这允许您使用未经修改的代码(不需要额外的变量)。
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. After that another pygame.KEYDOWN will be sent every interval milliseconds. If no arguments are passed the key repeat is disabled.
第一个参数 delay 是发送第一个重复的 pygame.KEYDOWN 之前的毫秒数。之后,另一个 pygame.KEYDOWN 将每间隔毫秒发送一次。如果没有传递参数,则禁用键重复。
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

