I’m doing a pygame project for practice and I need a sprite to move to some point on screen and I did it, but it moves in a straight line and I would like to learn how to make it move to the same point in a curve.
JavaScript
x
28
28
1
def move_to_point(self, dest_rect, speed, delta_time):
2
3
# Calculates relative rect of dest
4
rel_x = self.rect.x - dest_rect[0]
5
rel_y = self.rect.y - dest_rect[1]
6
7
# Calculates diagonal distance and angle from entity rect to destination rect
8
dist = math.sqrt(rel_x**2 + rel_y**2)
9
angle = math.atan2( - rel_y, - rel_x)
10
11
# Divides distance to value that later gives apropriate delta x and y for the given speed
12
# there needs to be at least +2 at the end for it to work with all speeds
13
delta_dist = dist / (speed * delta_time) + 5
14
print(speed * delta_time)
15
16
# If delta_dist is greater than dist entety movement is jittery
17
if delta_dist > dist:
18
delta_dist = dist
19
20
# Calculates delta x and y
21
delta_x = math.cos(angle) * (delta_dist)
22
delta_y = math.sin(angle) * (delta_dist)
23
24
25
if dist > 0:
26
self.rect.x += delta_x
27
self.rect.y += delta_y
28
This movement looks like
and I would like it to be like
Advertisement
Answer
There are many many ways to achieve what you want. One possibility is a Bézier curve:
JavaScript
1
5
1
def bezier(p0, p1, p2, t):
2
px = p0[0]*(1-t)**2 + 2*(1-t)*t*p1[0] + p2[0]*t**2
3
py = p0[1]*(1-t)**2 + 2*(1-t)*t*p1[1] + p2[1]*t**2
4
return px, py
5
p0
, p1
and p2
are the control points and t
is a value in the range [0,0, 1,0] indicating the position along the curve. p0
is the start of the curve and p2
is the end of the curve. If t = 0
, the point returned by the bezier function is equal to p0
. If t=1
, the point returned is equal to p2
.
Also see PyGameExamplesAndAnswers – Shape and contour – Bezier
Minimal example:
JavaScript
1
36
36
1
import pygame
2
3
pygame.init()
4
window = pygame.display.set_mode((500, 500))
5
clock = pygame.time.Clock()
6
7
def bezier(p0, p1, p2, t):
8
px = p0[0]*(1-t)**2 + 2*(1-t)*t*p1[0] + p2[0]*t**2
9
py = p0[1]*(1-t)**2 + 2*(1-t)*t*p1[1] + p2[1]*t**2
10
return px, py
11
12
dx = 0
13
run = True
14
while run:
15
clock.tick(100)
16
for event in pygame.event.get():
17
if event.type == pygame.QUIT:
18
run = False
19
20
pts = [(100, 100), (100, 400), (400, 400)]
21
22
window.fill(0)
23
for p in pts:
24
pygame.draw.circle(window, (255, 255, 255), p, 5)
25
for i in range(101):
26
x, y = bezier(*pts, i / 100)
27
pygame.draw.rect(window, (255, 255, 0), (x, y, 1, 1))
28
29
p = bezier(*pts, dx / 100)
30
dx = (dx + 1) % 101
31
pygame.draw.circle(window, (255, 0, 0), p, 5)
32
pygame.display.update()
33
34
pygame.quit()
35
exit()
36