Python 3.x 粒子碰撞模拟Python

Python 3.x 粒子碰撞模拟Python,python-3.x,simulation,collision,verlet-integration,Python 3.x,Simulation,Collision,Verlet Integration,我试图创建一个相对简单的粒子模拟,它应该考虑重力、阻力、与其他粒子的碰撞(非弹性碰撞)以及与墙的碰撞(完全弹性)。我用velocity Verlet算法得到了重力和阻力部分,但目前还不能将粒子设置为平衡状态。此外,如果我加上多个粒子,它们有时会相互攀爬,这是由于(我相信)它们仍然有非常小的速度分量,这些分量逐渐变为零。如果粒子的能量足够小,我试图切断粒子的速度,但是看起来不现实。也许有人能提出一些解决这些问题的建议。我得到了一个粒子对象: import pygame import random

我试图创建一个相对简单的粒子模拟,它应该考虑重力、阻力、与其他粒子的碰撞(非弹性碰撞)以及与墙的碰撞(完全弹性)。我用velocity Verlet算法得到了重力和阻力部分,但目前还不能将粒子设置为平衡状态。此外,如果我加上多个粒子,它们有时会相互攀爬,这是由于(我相信)它们仍然有非常小的速度分量,这些分量逐渐变为零。如果粒子的能量足够小,我试图切断粒子的速度,但是看起来不现实。也许有人能提出一些解决这些问题的建议。我得到了一个粒子对象:

import pygame
import random
import numpy as np
import operator
from itertools import combinations

class Particle:
    def __init__(self):
        self.mass = 10
        self.radius = random.randint(10, 50) 
        self.width, self.height = 700, 500
        self.pos = np.array((self.width/2, self.height/2))
        self.v = np.array((0.0, 0.0)) 
        self.acc = np.array((0.0, 0.0))
        self.bounce = 0.95
我使用Verlet积分来解释重力和阻力:

def update(self, ball, dt):
        new_pos = np.array((ball.pos[0] + ball.v[0]*dt + ball.acc[0]*(dt*dt*0.5), ball.pos[1] + ball.v[1]*dt + ball.acc[1]*(dt*dt*0.5)))
        new_acc = np.array((self.apply_forces(ball))) # only needed if acceleration is not constant
        new_v = np.array((ball.v[0] + (ball.acc[0]+new_acc[0])*(dt*0.5), ball.v[1] + (ball.acc[1]+new_acc[1])*(dt*0.5)))
        ball.pos = new_pos;
        ball.v = new_v;
        ball.acc = new_acc;
   
    def apply_forces(self, ball):
        grav_acc = [0.0, 9.81]
        drag_force = [0.5 * self.drag * (ball.v[0] * abs(ball.v[0])), 0.5 * self.drag * (ball.v[1] * abs(ball.v[1]))]  #D = 0.5 * (rho * C * Area * vel^2)
        drag_acc = [drag_force[0] / ball.mass, drag_force[1] / ball.mass] # a = F/m

        return (-drag_acc[0]),(grav_acc[1] - drag_acc[1])
这里我计算碰撞部分:

    def collision(self):
        pairs = combinations(range(len(self.ball_list)), 2)

        for i,j in pairs:
            part1 = self.ball_list[i]
            part2 = self.ball_list[j]
            distance = list(map(operator.sub, self.ball_list[i].pos, self.ball_list[j].pos))

            if np.hypot(*distance) < self.ball_list[i].radius + self.ball_list[j].radius:
                distance = part1.pos - part2.pos
                rad = part1.radius + part2.radius
                slength = (part1.pos[0] - part2.pos[0])**2 + (part1.pos[1] - part2.pos[1])**2
                length = np.hypot(*distance)
                factor = (length-rad)/length;
                x = part1.pos[0] - part2.pos[0]
                y = part1.pos[1] - part2.pos[1]

                part1.pos[0] -= x*factor*0.5
                part1.pos[1] -= y*factor*0.5
                part2.pos[0] += x*factor*0.5
                part2.pos[1] += y*factor*0.5

                u1 = (part1.bounce*(x*part1.v[0]+y*part1.v[1]))/slength
                u2 = (part2.bounce*(x*part2.v[0]+y*part2.v[1]))/slength
                part1.v[0] = u2*x-u1*x
                part1.v[1] = u1*x-u2*x
                part2.v[0] = u2*y-u1*y
                part2.v[1] = u1*y-u2*y

    def check_boundaries(self, ball):
        if ball.pos[0] + ball.radius > self.width:
            ball.v[0] *= -ball.bounce
            ball.pos[0] = self.width - ball.radius
                
        if ball.pos[0] < ball.radius:
            ball.v[0] *= -ball.bounce
            ball.pos[0] = ball.radius
                
        if ball.pos[1] + ball.radius > self.height:
            self.friction = True
            ball.v[1] *= -ball.bounce
            ball.pos[1] = self.height - ball.radius

        elif ball.pos[1] < ball.radius:
            ball.v[1] *= -ball.bounce
            ball.pos[1] = ball.radius
def冲突(自):
成对=组合(范围(len(self.ball_列表)),2)
对于成对的i,j:
第1部分=自球列表[i]
第2部分=自球列表[j]
距离=列表(映射(operator.sub,self.ball\u列表[i].pos,self.ball\u列表[j].pos))
如果np.hypot(*距离)自身宽度:
ball.v[0]*=-ball.bounce
ball.pos[0]=自身宽度-ball.radius
如果球位置[0]<球半径:
ball.v[0]*=-ball.bounce
ball.pos[0]=ball.radius
如果球位置[1]+球半径>自身高度:
自摩擦=真
ball.v[1]*=-ball.bounce
ball.pos[1]=自身高度-ball.radius
elif球位置[1]<球半径:
ball.v[1]*=-ball.bounce
球位置[1]=球半径

由于问题的根源是粒子动力学而不是可视化显示,请考虑将代码简化为动态部分作为一部分,这样我们可以更好地帮助你。希望改变有帮助。