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 multithreadingGUI
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:
-
Eject any bubble (water drop) at fixed time
-
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
-
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
Output screen
Code and description
- Import related libraries
import numpy as np
import PySimpleGUI as sg
import random
-
Create bubble class
-
Colors no longer use text, such as
yellow
,green
, because the color should be changed in the process of movementRGB
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.radius = 3
self.bubbles = np.empty((0, 5), dtype=np.float)
- 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
- The initial positions are fixed, and the number is
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.radius, fill_color=color, line_color=color)
self.bubbles = np.vstack((self.bubbles, new_bubbles))
-
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
- 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]),
self.radius, fill_color=color, line_color=color)
- 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 establishboolean
Indexes. - Export the image to be deleted according to the index and update the list of bubbles that still exist
- use
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))
discard = self.bubbles[np.logical_not(filter)]
for key in discard[:, 0]:
draw.DeleteFigure(int(key))
self.bubbles = self.bubbles[filter]
-
Establish bubble instance and GUI interface
GUI
The interface is very simple, just a canvas
B = Bubble()
- 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:
event, values = window.read(timeout=B.time)
if event == None:
break
B.change()
B.check()
B.update()
B.create()
window.close()
This work adoptsCC agreement, reprint must indicate the author and the link to this article