# Simple animation (numpy & pysimplegui)

Time：2022-4-29

Document establishment date: March 26, 2020

Last revision date: None

Relevant software information:

 Windows 10 Python 3.7.6 PySimpleGUI 4.16.0 Numpy 1.18.2 PIL/Pillow 7.1.1

Note: please quote or change this article at will. Just indicate the source and author. The author does not guarantee that the content is absolutely correct. Please be responsible for any consequences

## Title: simple animation (numpy & pysimplegui)

In the past, multithreading was always used to achieve multi object motion processing. In fact, there are timing processing designs in many GUIs. Therefore, try to use multithreading without using multithreading`GUI`The timing of itself can deal with the moving and updating of all objects, which seems to have a quick and natural effect And the design is much simpler than multithreading and easy to debug

## Objectives:

1. Eject any bubble (water drop) at fixed time

2. Each bubble has its own direction and velocity. In order to facilitate processing, it is set as the velocity in X direction and Y direction

3. There are three things to deal with in the bubble process

• Fall will be affected by gravity and acceleration
• The falling process will be gradually dispersed. Because the dispersion effect is not obvious, the color is changed to the background color
• If the bubble position exceeds the display area, it must be deleted, otherwise there will be more and more bubble objects

## Code and description

1. Import related libraries
``````import numpy as np
import PySimpleGUI as sg
import random``````
1. Create bubble class

• Colors no longer use text, such as`yellow`, `green`, because the color should be changed in the process of movement`RGB`Way of`#RRGGBB`To define

• Start by creating an empty array of bubbles, each with five attributes

• Image ID – the object drawn on the canvas

• Coordinates of initial positions of X and Y bubbles when they are generated

• V_ x, V_ Y is the initial velocity of bubble formation, and the two constitute its moving direction

``````class Bubble():

def __init__(self):
self.width, self.height = self.size = (301, 501)
self.x0, self.y0 = self.origin = self.width//2, self.height-50
self.number  = 10   # 10 bubbles generate each time
self.range   = 30
self.time    = 10
self.rate    = self.time/40
self.color   = '#FFFFFF'
self.bg      = '#0080FF'
self.bubbles = np.empty((0, 5), dtype=np.float)``````
1. Bubble generation
• The initial positions are fixed, and the number is`self.number`
• If the velocity is a random number, there will be bubbles with different directions and velocities
• Draw bubbles in order and coexist their images`id`For later update or deletion
``````def create(self):
new_bubbles = np.hstack(
(np.full((self.number, 1),     0.0),
np.full((self.number, 1), self.x0),
np.full((self.number, 1), self.y0),
(np.random.rand(self.number, 1)-0.5)*self.range,
(np.random.rand(self.number, 1)-0.5)*self.range
)).astype(np.float)
for bubble in new_bubbles:
color = self.color
bubble[0] = draw.DrawCircle((bubble[1], bubble[2]),
self.bubbles = np.vstack((self.bubbles, new_bubbles))``````
1. Bubble movement

• The speed of direction X remains the same, and its position is X_ {n+1} = X_ n + V_ x * dt

• The velocity in direction Y is affected by gravity

• Position Y_ {n+1} = Y_ n – V_ Y * DT + G * T ^ 2 / 2, where V_ Y for simplicity, take only constants

• Speed v_ {n+1} = V_ n-g*dt

• These formulas may be simplified again. For example, if the time difference is 1 and the gravitational acceleration is 1, the calculation formula will be simpler.

``````def change(self):
self.bubbles[:, 1] += self.bubbles[:, 3]*self.rate
self.bubbles[:, 2] += self.bubbles[:, 4]*self.rate - 9.8*self.rate**2/2
self.bubbles[:, 4] -= 9.8*self.rate``````
1. More bubble update
• The color change is updated from the original bubble color to the background color in proportion to the position of the Y axis
• because`PySimpleGUI`The color of the image cannot be updated directly, so delete the image in the original position first, and then draw the image again in the new position
``````def update(self):
b = 255
color = self.color
for bubble in self.bubbles:
r = min(int(255 - 255*(self.y0-bubble[2])/self.y0), 255)
g = min(int(255 - 128*(self.y0-bubble[2])/self.y0), 255)
color = "#%02x%02x%02x" % (r, g, b)
draw.DeleteFigure(int(bubble[0]))
bubble[0] = draw.DrawCircle((bubble[1], bubble[2]),
1. Check whether the bubble is out of bounds
• use`Numpy`According to the position of the bubble, confirm whether it is out of bounds and establish`boolean`Indexes.
• Export the image to be deleted according to the index and update the list of bubbles that still exist
``````def check(self):
filter = np.logical_and(
np.logical_and(self.bubbles[:,1]>0, self.bubbles[:,1]<self.width),
np.logical_and(self.bubbles[:,2]>0, self.bubbles[:,2]<self.height))
draw.DeleteFigure(int(key))
self.bubbles = self.bubbles[filter]``````
1. Establish bubble instance and GUI interface

• `GUI`The interface is very simple, just a canvas
``B = Bubble()``
1. Run the main program
• The content is very simple – generate bubbles, update the position and speed, check whether it is out of bounds, update the bubble position and color, and cycle until the user closes the window
• After deducting blank lines, only`65`that ‘s ok.
``````B.create()
while True:
if event == None:
break
B.change()
B.check()
B.update()
B.create()
window.close()``````