Skip to content

Instantly share code, notes, and snippets.

@petrblahos
Created December 22, 2023 10:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save petrblahos/e8bdc60f3eef30af1582ba49860643eb to your computer and use it in GitHub Desktop.
Save petrblahos/e8bdc60f3eef30af1582ba49860643eb to your computer and use it in GitHub Desktop.
Animate a point over a list of bezier curves
import bezier
import pygame
class BezierLoop:
WIDTH = 400
HEIGHT = 400
def prepare_window(self):
self.screen = pygame.display.set_mode((self.WIDTH, self.HEIGHT))
self.screen.fill((0, 0, 0))
def make_curves(self):
ret = []
ret.append(bezier.Curve.from_nodes([
[100, 100],
[100, 110],
]))
ret.append(bezier.Curve.from_nodes([
[100, 100, 200],
[110, 300, 300],
]))
ret.append(bezier.Curve.from_nodes([
[200, 300],
[300, 300],
]))
ret.append(bezier.Curve.from_nodes([
[300, 300, 100, 100],
[300, 100, 200, 100],
]))
return ret
def animate_point_as_single_curve(self, curves, idx):
whole_len = 100 * len(curves)
n_idx = whole_len * idx // 100
curve_idx = n_idx // 100
c = curves[curve_idx]
n_idx = n_idx % 100
if n_idx > 100:
n_idx = 100
v = c.evaluate(n_idx / 100)
v = (v[0][0], v[1][0])
pygame.draw.circle(self.screen, (0, 255, 0), v, 6)
def animate_smooth(self, curves, idx):
len_all = 0
for c in curves:
len_all += c.length
projected_idx = len_all * idx / 100
previous_len = 0
current_len = 0
for c in curves:
current_len += c.length
if projected_idx < current_len:
partial = projected_idx - previous_len
v = c.evaluate(partial / c.length)
v = (v[0][0], v[1][0])
pygame.draw.circle(self.screen, (255, 0, 0), v, 6)
break
previous_len = current_len
def animate_point_each_curve(self, curves, idx):
for c in curves:
v = c.evaluate(idx / 100)
v = (v[0][0], v[1][0])
pygame.draw.circle(self.screen, (0, 0, 255), v, 6)
def draw_curves(self, curves):
# each letter:
for c in curves:
last_pt = None
for i in range(21):
v = c.evaluate(i / 20)
v = (v[0][0], v[1][0])
if not last_pt is None:
pygame.draw.line(self.screen, (255, 0, 255), last_pt, v)
last_pt = v
def run(self):
dt = 1
clock = pygame.time.Clock()
do_run = True
curves = self.make_curves()
cnt = -50
idx = -1
w_idx = -1
while do_run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
do_run = False
break
self.screen.fill((0, 0, 0))
self.draw_curves(curves)
idx = (idx + 1) % 100
self.animate_point_each_curve(curves, idx)
self.animate_point_as_single_curve(curves, idx)
self.animate_smooth(curves, idx)
pygame.display.flip()
dt = clock.tick(60)
if "__main__" == __name__:
pygame.init()
pgm = BezierLoop()
pgm.prepare_window()
pgm.run()
pygame.quit()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment