Pygame中角色的平滑移动

3
我使用pygame库。以下是我为玩家编写的事件处理伪代码:
#generates multiple events for keys that are held down
pygame.key.set_repeat(30,30)

for event in pygame.event.get()

   nextPos = currentPos

   if(keyUp):
       if event.key == w :
         key_w = false
       #do the same for s, a and d

   if(keyDown):
       if event.key == w:
         key_w = true
       #same for s,a and d

   if(key_w):
      #update nextPos

   #do same for key_s, key_a and key_d

   currentPos = nextPos

问题在于有时当我在屏幕上移动鼠标,并且同时按键时,在处理鼠标事件的同时,按键事件被排队,这些多个按键会一起执行,导致玩家似乎跳了一个巨大的距离。

如果我根本不移动鼠标,则不会出现此问题。

5个回答

1

更新我的回答:

我检查了我的游戏代码,看看我如何处理每一帧的按键,似乎我不是从事件中获取按键信息,而是使用pygame.key.get_pressed():

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            gl.loop_main_loop = False # exit main loop and terminate 
    keys = pygame.key.get_pressed()
    for key, state in enumerate(keys):
        if (key in self.key_handlers) and state:
            self.key_handlers[key]() # call key handler proc

这意味着我每帧只处理一次相关的键。鼠标可以按照我下面描述的方式读取。

如果你的游戏没有固定的帧率,记得在移动向量计算中使用增量时间。


也许更好的想法是在每个进程中首先处理所有键盘事件,并构建自己的键状态表示,即告诉您哪些对您重要的键(例如WSAD)处于按下或释放状态的结构。当该帧中的所有事件都已处理完毕后,使用您的键状态数据运行移动代码。
不要使用mousemotion事件跟踪您的鼠标,而是直接使用pygame.mouse.get_pos()和pygame.mouse.get_pressed()读取位置和按钮。
您的移动代码还应考虑到游戏以可变帧速率运行的事实(除非您强制pygame保持帧速率恒定),并在您的移动向量计算中使用时间差。

1
我使用以下方法...
我初始化坐标变量...
x = 300
y = 300
pX = 0
pY = 0

在这种情况下,x和y是玩家精灵实际使用的坐标,而pX和pY则由事件处理程序使用。
然后我在事件处理程序中使用以下代码...
for event in pygame.event.get(): 
    if event.type == pygame.QUIT: 
        sys.exit(0)

    if event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT:
        pX -= 2
    if event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
        pX += 2
    if event.type == pygame.KEYDOWN and event.key == pygame.K_UP:
        pY -= 2
    if event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN:
        pY += 2       

    if event.type == pygame.KEYUP and event.key == pygame.K_LEFT:
        pX += 2
    if event.type == pygame.KEYUP and event.key == pygame.K_RIGHT:
        pX -= 2
    if event.type == pygame.KEYUP and event.key == pygame.K_UP:
        pY += 2
    if event.type == pygame.KEYUP and event.key == pygame.K_DOWN:
        pY -= 2

最后,在处理玩家坐标的主游戏循环中,我放置了...
x += pX
y += pY

0

我不会使用pygame.event.get()

在我看来,最好的玩家移动输入是pygame.key.get_pressed()

我会这样格式化:

while True:
    keys = pygame.key.get_pressed()
    if keys[K_a]:
        player.pos.x -= 10
    if keys[K_d]:
        player.pos.x += 10
    if keys[K_w]:
        player.pos.y -= 10
    if keys[K_s]:
        player.pos.y += 10

这样,系统就会在每一帧中检查按下的键盘按键。

0
也许事件队列不是最好的解决方案,可能每帧轮询一次会更好?

即使我每帧只轮询一次,直到我移动鼠标为止都能正常工作。当我开始移动鼠标并同时按下键时,玩家会停留在同一位置。4-5秒后,它会根据我之前按下的键重新开始移动。 - Karan
好的,问题已经部分解决了。我通过使用pygame.event.set_blocked将鼠标移动从事件队列中删除了。但现在我想用鼠标单击来射击子弹(这是一款射击游戏)。这也导致了相同的问题,尽管在这种情况下,由于鼠标单击引起的事件数量很少,玩家只会跳跃一个小距离。 - Karan

0

很遗憾我现在无法进行测试,但请执行以下代码:

import pygame, sys

clock = pygame.time.Clock()

playerX,playerY = 100,100 # Change 100 to the starting point you want
playerXc,playerYc = 0,0

while True:

    playerX += playerXc
    playerY += playerYc

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
     
        # Keydown Events
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_w:
                playerYc = 1 # Change value to the speed you would like also change it to -1 if it goes wrong direction

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_a:
                playerXc = -1 # Change value to the speed you would like to change and set it to 1 if it goes the wrong direction

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_s:
                playerYc = -1 # Change value to the speed you would like also change it to 1 if it goes the wrong direction

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_d:
                playerXc = 1 # Change value to the speed you would like to change and set it to -1 if it goes the wrong direction

        # Keyup Events
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_a:
                playerXc = 0

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_w:
                playerYc = 0

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_s:
                playerYc = 0

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_d:
                playerXc = 0

    
    pygame.display.update()
    clock.tick(60) # Change 60 to the framerate you would like so it runs smoother or the opposite.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接