如何在pygame中进行平滑运动
Posted
技术标签:
【中文标题】如何在pygame中进行平滑运动【英文标题】:How to make smooth movement in pygame 【发布时间】:2021-01-13 04:45:16 【问题描述】:我和我的一个朋友刚刚开始在 repl.it 上学习使用 pygame 进行编程,对于我们的第一个“真正”项目,我们希望制作一个像点击式冒险这样的老派。
但是,我们遇到了角色移动的问题,如果我们单击屏幕上的某个位置,角色只是“传送”到那里,但我们希望它看起来尽可能平滑。
所以基本上,我们希望摆脱角色的“传送”,而是从角色当前位置到鼠标位置进行平滑的逐帧过渡。
我们已经尝试减慢 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))
【问题讨论】:
另外,您可以通过下标元组if mstate[0]: do stuff
中的第一个值来检查鼠标点击。
另外,您可以在主循环中只执行一次screen.blit(pmc, (x2-46, y2-184))
,在问题中显示的while
和if
语句之外
【参考方案1】:
你有一个游戏循环,所以使用它。只需在每一帧中将角色移动到某个位置即可。例如每帧将字符移动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
对于更复杂的解决方案,您必须从指向目标的点计算 Euclidean distance。使用pygame.math.Vector2
进行计算。
计算跟随者和精灵之间的距离以及从 (follower_x
, follower_y
) 到 (mainsprite_x
, mainsprite_y
) 的单位方向向量。 Unit 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
现在你可以定义一个精确的step_distance
并移动到精灵的follower int 方向:
if distance > 0:
new_follower_vector = follower_vector + direction_vector * step_distance.
定义一个maximum_distance
和一个minimum_distance
。最小步距为:
min_step = max(0, distance - maximum_distance)
最大步距为
max_step = distance - minimum_distance
把它们放在一起:
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
最小示例: 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()
【讨论】:
哇,这是一个非常好的解决方案,非常感谢。虽然从我们目前对 phython 的了解来看,这对我们来说有点复杂:P. @esms10 你所要做的就是复制函数FollowMe
并调用x, y = FollowMe((x, y), (x2, y2))
。【参考方案2】:
我不建议使用 repl.it,因为它运行速度很慢。
你的代码应该看起来更像这样:
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()
在显示一直移动到 (x,y) 之前,您不会更新显示
【讨论】:
哦,是的,这有点令人尴尬,我们没有注意到我们自己,但谢谢老兄:P。 我们正在使用 repl.it,因为它是我们所知道的唯一在线编译器,它对用户非常友好,因为我们刚刚开始编码,所以我们基本上什么都不知道:P。以上是关于如何在pygame中进行平滑运动的主要内容,如果未能解决你的问题,请参考以下文章