简体   繁体   English

如何在pygame中平滑移动

[英]How to make smooth movement in pygame

A friend of mine and me are just starting to learn to program with pygame on repl.it and for our first "real" project we want to make an old school like point'n'click adventure.我和我的一个朋友刚刚开始学习在 repl.it 上使用 pygame 进行编程,对于我们的第一个“真实”项目,我们希望制作一个像点击式冒险一样的老派。

However, we have a problem with the movement of the character, if we click somewhere on the screen the character just "teleports" there but we want it to look as smooth as possible.然而,我们在角色的移动上遇到了问题,如果我们点击屏幕上的某个地方,角色只是“传送”到那里,但我们希望它看起来尽可能流畅。

So basically, we want to get rid of the "teleporting" of the character and instead have a smooth frame-by-frame transition from the characters current position to the mouse position.所以基本上,我们想要摆脱角色的“传送”,而是从角色当前位置到鼠标位置平滑地逐帧过渡。

We've already tried to slow down the while loops so that we could project the character each time the while loop is executed but that just crashes the whole site, we also tried to do it outside of repl.it in case it was a problem with the website but it didn't work there either.我们已经尝试减慢 while 循环的速度,以便我们可以在每次执行 while 循环时投射角色,但这只会使整个站点崩溃,我们还尝试在 repl.it 之外执行此操作,以防出现问题与网站,但它也没有在那里工作。

#PMC = Character
#mpos = the mouse position 
#mstate= the state of the mouse buttons (0 if nothing is pressed, 1 if a mouse 
#button is pressed) 
#charspeed = the speed at which the character moves (=1px)
  ```
#---PMC movement when mouse click-----------------------
    #---x,y = mpos   x2,y2 = characterpos
    if mstate == (1,0,0):
      #print('x: ', x, ' y: ', y, '   x2: ', x2, ' y2: ', y2) #debugging_positions

      
      while x2 != x:
        if x2>x:
          x2-=charspeed
          screen.blit(pmc, (x2-46, y2-184))
        if x2<x:
          x2+=charspeed
          screen.blit(pmc, (x2-46, y2-184))
          
      while y2 != y:
        if y2>y:
          y2 -= charspeed
          screen.blit(pmc, (x2-46, y2-184))
        if y2<y:
          y2 += charspeed
          screen.blit(pmc, (x2-46, y2-184))

You have a game loop, so use it.你有一个游戏循环,所以使用它。 Just move the character by a certain position in each frame.只需在每一帧中将角色移动某个位置即可。 For instance mov the character by step per frame:例如,每帧step角色:

step = 1

if x2 + step <= x:
    x2 += step
elif x2 - step >= x:
    x2 -= step
else:
    x2 = x

if y2 + step <= y:
    y2 += step
elif y2 - step >= y:
    y2 -= step
else:
    y2 = y

For a more sophisticated solution, you've to compute the Euclidean distance form the point to the target.对于更复杂的解决方案,您必须计算从点到目标的欧几里得距离 Use pygame.math.Vector2 for the computation.使用pygame.math.Vector2进行计算。

Compute the distance from between the follower and the sprite and the unit direction vector from ( follower_x , follower_y ) to ( mainsprite_x , mainsprite_y ).计算跟随者和精灵之间的距离以及从 ( follower_x , follower_y ) 到 ( mainsprite_x , mainsprite_y ) 的单位方向向量。 The Unit Vector can be computed by dividing the direction vector by the distance or by normalizing ( normalize() ) the direction vector:单位向量可以通过将方向向量除以距离或通过归一化( normalize() )方向向量来计算:

target_vector = Vector2(mainsprite_x, mainsprite_y)
follower_vector = Vector2(follower_x, follower_y)

distance = follower_vector.distance_to(target_vector)
direction_vector = target_vector - follower_vector
if distance > 0:
    direction_vector /= distance

Now you can define an exact step_distance and move to follower int direction of the sprite:现在你可以定义一个精确的step_distance并移动到精灵的 follower int 方向:

if distance > 0:
    new_follower_vector = follower_vector + direction_vector * step_distance.

Define a maximum_distance and a minimum_distance .定义一个maximum_distance和一个minimum_distance The minimum step distance is:最小步距为:

min_step = max(0, distance - maximum_distance)

The maximum step distance is最大步距为

max_step = distance - minimum_distance

Put it all together:把它们放在一起:

minimum_distance    = 0
maximum_distance    = 10000
target_vector       = Vector2(mainsprite_x, mainsprite_y)
follower_vector     = Vector2(follower_x, follower_y)
new_follower_vector = Vector2(follower_x, follower_y)

distance = follower_vector.distance_to(target_vector)
if distance > minimum_distance:
    direction_vector    = (target_vector - follower_vector) / distance
    min_step            = max(0, distance - maximum_distance)
    max_step            = distance - minimum_distance
    step_distance       = min_step + (max_step - min_step) * LERP_FACTOR
    new_follower_vector = follower_vector + direction_vector * step_distance

Minimal example:最小的例子: repl.it/@Rabbid76/PyGame-FollowMouseSmoothly repl.it/@Rabbid76/PyGame-FollowMouseSmoothly

import pygame

LERP_FACTOR      = 0.05
minimum_distance = 25
maximum_distance = 100

def FollowMe(pops, fpos):
    target_vector       = pygame.math.Vector2(*pops)
    follower_vector     = pygame.math.Vector2(*fpos)
    new_follower_vector = pygame.math.Vector2(*fpos)

    distance = follower_vector.distance_to(target_vector)
    if distance > minimum_distance:
        direction_vector    = (target_vector - follower_vector) / distance
        min_step            = max(0, distance - maximum_distance)
        max_step            = distance - minimum_distance
        step_distance       = min_step + (max_step - min_step) * LERP_FACTOR
        new_follower_vector = follower_vector + direction_vector * step_distance

    return (new_follower_vector.x, new_follower_vector.y) 

pygame.init()
window = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()

follower = (100, 100)
run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    player   = pygame.mouse.get_pos()
    follower = FollowMe(player, follower)

    window.fill(0)  
    pygame.draw.circle(window, (0, 0, 255), player, 10)
    pygame.draw.circle(window, (255, 0, 0), (round(follower[0]), round(follower[1])), 10)
    pygame.display.flip()

I wouldn't recommend using repl.it as it tends to run very slowly.我不建议使用 repl.it,因为它往往运行得很慢。

Also your code should look more like this:此外,您的代码应该更像这样:

    while True:
        screen.fill((0,0,0))

        stuff happens

        if x2>x:
            x2-=charspeed
        elif x2<x:
            x2+=charspeed
        elif y2>y:
            y2 -= charspeed
        elif y2<y:
            y2 += charspeed
        screen.blit(pmc, (x2-46, y2-184))
        pygame.display.flip()

You weren't updating the display until it had moved all of the way to (x,y)在显示一直移动到 (x,y) 之前,您不会更新显示

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

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