2

I want to put a particle animation in the background screen of my software, something like the link below, but for Python and kivymd

codepen.io/JulianLaval/pen/KpLXOO

I know this may be difficult or impossible for kivymd right now but if anyone has an idea please let me know

enter image description here

vahidkoohkan
  • 162
  • 1
  • 4
  • 11

1 Answers1

4

Yes! This is absolutely possible (everything is possible in Kivy). Check out the code below:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Line, Color
from random import randint
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import ListProperty
from math import sin, cos


class ParticleMesh(Widget):
    points = ListProperty()

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.direction = []
        self.point_number = 50
        Clock.schedule_once(lambda dt: self.plot_points(), 2)

    def plot_points(self):
        for _ in range(self.point_number):
            x = randint(0, self.width)
            y = randint(0, self.height)
            self.points.extend([x, y])
            self.direction.append(randint(0, 359))
        Clock.schedule_interval(self.update_positions, 0)

    def draw_lines(self):
        self.canvas.after.clear()
        with self.canvas.after:
            for i in range(0, len(self.points), 2):
                for j in range(i + 2, len(self.points), 2):

                    d = self.distance_between_points(self.points[i], self.points[i + 1], self.points[j],
                                                     self.points[j + 1])
                    if d > 120:
                        continue
                    color = d / 120
                    Color(rgba=[color, color, color, 1])
                    Line(points=[self.points[i], self.points[i + 1], self.points[j], self.points[j + 1]])

    def update_positions(self, *args):
        step = 1
        for i, j in zip(range(0, len(self.points), 2), range(len(self.direction))):
            theta = self.direction[j]
            self.points[i] += step * cos(theta)
            self.points[i + 1] += step * sin(theta)

            if self.off_screen(self.points[i], self.points[i + 1]):
                self.direction[j] = 90 + self.direction[j]

        self.draw_lines()

    @staticmethod
    def distance_between_points(x1, y1, x2, y2):
        return ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5

    def off_screen(self, x, y):
        return x < -5 or x > self.width + 5 or y < -5 or y > self.height + 5


kv = """
FloatLayout:

    canvas.before:
        Color:
            rgba: 1, 1, 1, 1
        Rectangle:
            size: self.size
            pos: self.pos

    ParticleMesh:

        canvas:
            Color:
                rgba: 0, 0, 0, 1
            Point:
                points: self.points
                pointsize: 2
"""


class MeshApp(App):

    def build(self):
        return Builder.load_string(kv)


if __name__ == '__main__':
    MeshApp().run()

This code will create the following (this is just a screenshot - if you run the app, the points move about):

enter image description here

First plot_points is called, which creates an array of points randomly placed on the screen. A random direction for each point is also created. This direction is represented by an angle between 0 and 359. On the completion of this function, a Clock object is instantiated and calls update_positions every frame.

The update_positions moves the particles by one pixel in the angle specified by directions. If the position of the particle is greater than the screen the direction is reversed.

Finally draw_lines is called. This function first clears all existing lines then draws new ones. If the points are at a distance greater than 120 pixels no line is created. However, if they are closer than 120 pixels a line is drawn such that the closer the two points are, the darker the line will be.

You can always increase or decrease the number of points on the screen by changing the self.point_number property.

I will leave it up to you to change the colour of the points and the background - I don't think that should be too hard.

jda5
  • 1,390
  • 5
  • 17