Animating two labels along a Bezier curve in Kivy with Python

28 Views Asked by At

I am learning Kivy and I'm stuck on a problem. I have python code that generates two labels whose positions are then animated along two Bezier curves. The problem is that I can't get the second label to move along its Bezier curve, in spite of using two lists for the points.

Here's the code. Your assistance will be highly appreciated. Thanks.

from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.graphics import Color, Bezier
from kivy.animation import Animation
from math import pow, comb
from random import randint, random

class BezierPath(Widget):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.points = [[100, 100, 200, 100, 300, 200, 400, 1400], [620, 100, 520, 100, 420, 200, 400, 1400]]
        self.colors = [(1, 0, 0, 1), (1, 0.5, 0, 1)]
        self.starting_points = [(100, 100), (620, 100)]

        for i in range(len(self.points)):
            with self.canvas:
                Color(*self.colors[i])
                self.bezier = Bezier(points = self.points[i])

class SimpleBezier:
    def __init__(self, **kwargs):
        self.points = kwargs.pop('points', [])

    def get_point(self, t):
        num_points = int(len(self.points)/2)
        x = 0
        y = 0

        for i in range(num_points):
            px = self.points[i * 2]
            py = self.points[i * 2 + 1]
        
            coeff = comb(num_points-1, i) * pow(t, i) * pow((1.0 - t), (num_points - 1 - i))
            x += coeff * px
            y += coeff * py

        return x, y


class BezierLabelApp(App):
    def build(self):
        bezier_path = BezierPath()

        for i in range(len(bezier_path.points)):
            label = Label(
                pos = bezier_path.starting_points[i],
                font_size = 30,
                color = bezier_path.colors[i]
            )

            bezier_path.add_widget(label)

            animation = Animation(duration = randint(10, 20))
            animation.bind(on_progress = self.update_pos)

            animation.start(label)

            self.sb = SimpleBezier(points = bezier_path.points[i])

        return bezier_path

    def update_pos(self, anim, label, t):
        label.center = self.sb.get_point(t)
        # verbose
        num = str(t)[str(t).index('.')+1:][:2].lstrip('0')
        label.text = num

if __name__ == '__main__':
    BezierLabelApp().run()`

I tried reversing the self.points list but then the labels shift to moving along the second Bezier Curve. I don't understand why the second label won't stick to moving along the second Bezier curve.

0

There are 0 best solutions below