原 matplotlib动画入门(3):弹球

2019-09-23 15:18:25 浏览数 (1)

介绍

在平面上画一个方框代表墙壁,框内有一个运动的弹球,当弹球碰到墙壁时就弹回去,小球不停的运动。

代码

新建一个文件particle.py,增加如下代码:

先引入相应的包

代码语言:javascript复制
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

新建一个ParticleBox类

代码语言:javascript复制
class ParticleBox:
    '''
    初始化方法
    init_state是一个数组:[x,y,vx,vy],四个值分别表示x坐标,y坐标,x方向的速度,y方向的速度
    bounds 是箱子的边界: [xmin, xmax, ymin, ymax]
    size: 球的半径
    '''
    def __init__(self,
            init_state = [1,0,0.5,1],
            bounds = [-2, 2, -2, 2],
            size = 0.04):
        self.init_state = np.asarray(init_state, dtype=float)
        self.size = size
        self.state = self.init_state.copy()
        self.bounds = bounds

    '''
    每一帧动画调用一次step函数,画出小球的位置。
    dt是每一帧代表的时间,其乘以速度就是运动的距离
    '''
    def step(self, dt):

        '''
         x = x   dt * vx 
         y = y   dt * vy
        '''
        self.state[:2]  = dt * self.state[2:]

        '''
        如果弹球碰到墙,就弹回来
        '''
        crossed_x1 = (self.state[0] < self.bounds[0]   self.size)
        crossed_x2 = (self.state[0] > self.bounds[1] - self.size)
        crossed_y1 = (self.state[1] < self.bounds[2]   self.size)
        crossed_y2 = (self.state[1] > self.bounds[3] - self.size)

        if crossed_x1:
            self.state[0] = self.bounds[0]   self.size
        if crossed_x2:
            self.state[0] = self.bounds[1] - self.size 
        if crossed_y1:
            self.state[1] = self.bounds[2]   self.size
        if crossed_y2:
            self.state[1] > self.bounds[3] - self.size 
        #反方向运动
        if crossed_x1 | crossed_x2 :
            self.state[2] *= -1
        if crossed_y1 | crossed_y2 :    
            self.state[3] *= -1   

每一帧动画调用一次animate函数,i表示帧号。

代码语言:javascript复制
def animate(i):
    global box, rect
    box.step(dt)
    rect.set_edgecolor('k')
    particles.set_data(box.state[0], box.state[1])
    particles.set_markersize(4)
    return particles, rect

生成边框、小球以及让它动起来

代码语言:javascript复制
#随机取四个数作为起始位置和速度
init_state = np.random.random(4)
box = ParticleBox(init_state, size=0.04)
#每帧代表0.1秒
dt = 0.1

#画图
fig = plt.figure()
fig.subplots_adjust(left=0, right=1, bottom=0, top=1)
ax = fig.add_subplot(111, aspect='equal', autoscale_on=False,
                     xlim=(-3.2, 3.2), ylim=(-2.4, 2.4))

particles, = ax.plot([], [], 'bo', ms=4)
rect = plt.Rectangle(box.bounds[::2],
                     box.bounds[1] - box.bounds[0],
                     box.bounds[3] - box.bounds[2],
                     ec='none', lw=2, fc='none')
ax.add_patch(rect)

ani = animation.FuncAnimation(fig, animate, frames=600,
                              interval=1, blit=False)

plt.show()

完整代码为:

代码语言:javascript复制
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

class ParticleBox:
    '''
    init_state is an array:[x,y,vx,vy]
    bounds 箱子的边界: [xmin, xmax, ymin, ymax]
    size: 球的半径
    '''
    def __init__(self,
            init_state = [1,0,0.5,1],
            bounds = [-2, 2, -2, 2],
            size = 0.04):
        self.init_state = np.asarray(init_state, dtype=float)
        self.size = size
        self.state = self.init_state.copy()
        self.bounds = bounds

    '''
    每一帧动画调用一次step函数,画出小球的位置。
    dt是每一帧代表的时间,其乘以速度就是运动的距离
    '''    
    def step(self, dt):

        '''
         x = x   dt * vx 
         y = y   dt * vy
        '''
        self.state[:2]  = dt * self.state[2:]

        '''
        如果碰到墙,就弹回来
        '''
        crossed_x1 = (self.state[0] < self.bounds[0]   self.size)
        crossed_x2 = (self.state[0] > self.bounds[1] - self.size)
        crossed_y1 = (self.state[1] < self.bounds[2]   self.size)
        crossed_y2 = (self.state[1] > self.bounds[3] - self.size)

        if crossed_x1:
            self.state[0] = self.bounds[0]   self.size
        if crossed_x2:
            self.state[0] = self.bounds[1] - self.size 
        if crossed_y1:
            self.state[1] = self.bounds[2]   self.size
        if crossed_y2:
            self.state[1] > self.bounds[3] - self.size 

        if crossed_x1 | crossed_x2 :
            self.state[2] *= -1
        if crossed_y1 | crossed_y2 :    
            self.state[3] *= -1      



def animate(i):
    global box, rect
    box.step(dt)
    rect.set_edgecolor('k')
    particles.set_data(box.state[0], box.state[1])
    particles.set_markersize(4)
    return particles, rect

#随机取四个数作为起始位置和速度
init_state = np.random.random(4)
box = ParticleBox(init_state, size=0.04)
#每帧代表0.1秒
dt = 0.1

#画图
fig = plt.figure()
fig.subplots_adjust(left=0, right=1, bottom=0, top=1)
ax = fig.add_subplot(111, aspect='equal', autoscale_on=False,
                     xlim=(-3.2, 3.2), ylim=(-2.4, 2.4))

particles, = ax.plot([], [], 'bo', ms=4)
rect = plt.Rectangle(box.bounds[::2],
                     box.bounds[1] - box.bounds[0],
                     box.bounds[3] - box.bounds[2],
                     ec='none', lw=2, fc='none')
ax.add_patch(rect)

ani = animation.FuncAnimation(fig, animate, frames=600,
                              interval=1, blit=False)

plt.show()

执行命令

代码语言:javascript复制
python3 particle.py 

0 人点赞