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
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):
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.