当前位置: 首页 > 知识库问答 >
问题:

Python中运动粒子之间的弹性碰撞:为什么动能不守恒?

郦磊
2023-03-14

我正试图在pygame中编写粒子模拟代码,但在粒子之间的碰撞编码上遇到了麻烦。所有的碰撞都是弹性的,所以动能应该是守恒的。然而,我正经历着两个主要问题:

  1. 粒子不断加速直到失去控制
  2. 粒子聚集在一起并停止运动

我用这份文件(http://www.vobarian.com/collisions/2dcollisions2.pdf)来帮助计算碰撞后粒子的新速度。所有粒子的质量都是一样的,所以我在计算时忽略了它们的质量。以下是我到目前为止的代码:

import pygame
pygame.init()
import random
import numpy

HEIGHT = 500
WIDTH = 500
NUM_BALLS = 2


#setup
win = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("Simulation")

class Particle(object):
    def __init__(self, x, y , radius):
        self.x = x
        self.y = y
        self.radius = radius
        self.xvel = random.randint(1,5)
        self.yvel = random.randint(1,5)

    def Draw_circle(self):
        pygame.draw.circle(win, (255,0,0), (self.x, self.y), self.radius)


def redrawGameWindow():
    win.fill((0,0,0))
for ball in balls:
    ball.Draw_circle()

pygame.display.update()


balls = []    
for turn in range(NUM_BALLS):
balls.append(Particle(random.randint(20,WIDTH-20),random.randint(20,HEIGHT-20),20))


run = True
while run:

for event in pygame.event.get():
    if event.type == pygame.QUIT:
        run = False

for ball in balls:
     if (ball.x + ball.radius) <= WIDTH or (ball.x - ball.radius) >= 0:
       ball.x += ball.xvel
     if (ball.x + ball.radius) > WIDTH or (ball.x - ball.radius) < 0:
         ball.xvel *= -1
         ball.x += ball.xvel
     if (ball.y + ball.radius) <= HEIGHT or (ball.y - ball.radius) >= 0:
         ball.y += ball.yvel
     if (ball.y + ball.radius) > HEIGHT or (ball.y - ball.radius) < 0:
         ball.yvel *= -1
         ball.y += ball.yvel

#code for collision between balls
for ball in balls:
    for i in range(len(balls)):
        for j in range (i+1, len(balls)):
            d = (balls[j].x-balls[i].x)**2 + (balls[j].y-balls[i].y)**2
            if d < (balls[j].radius + balls[i].radius)**2:
                print("collision")
                n  = (balls[i].x-balls[j].x, balls[i].y-balls[j].y) #normal vector
                un = n/ numpy.sqrt((balls[i].x-balls[j].x)**2 + (balls[i].y-balls[j].y)**2) #unit normal vector
                ut = numpy.array((-un[1],un[0])) #unit tangent vector
                u1n = numpy.vdot(un, (balls[j].xvel, balls[j].yvel)) #initial velocity in normal direction for first ball
                v1t = numpy.vdot(ut, (balls[j].xvel, balls[j].yvel)) #initial velocity in tangent direction (remains unchanged)
                u2n = numpy.vdot(un, (balls[i].xvel, balls[i].yvel)) #second ball
                v2t = numpy.vdot(ut, (balls[i].xvel, balls[i].yvel))
                v1n = u2n
                v2n = u1n
                v1n *= un
                v2n *= un
                v1t *= ut
                v2t *= ut
                v1 = v1n + v1t #ball 1 final velocity
                v2 = v2n + v2t #ball 2 final velocity
                balls[j].xvel = int(numpy.vdot(v1, (1,0))) #splitting final velocities into x and y components again
                balls[j].yvel = int(numpy.vdot(v1, (0,1)))
                balls[i].xvel = int(numpy.vdot(v2, (1,0)))
                balls[i].yvel = int(numpy.vdot(v2, (0,1)))

redrawGameWindow()
pygame.time.delay(20)

pygame.quit()

共有1个答案

澹台文博
2023-03-14

这些东西粘在一起的问题很简单,即使你总是检查有没有碰撞,但它能真正识别的时间是圆圈相互接触但轻微接触的时候。圆圈现在会弹跳和移动一点。然而,他们没有移动到完全不接触,这意味着反弹,它在一个循环。我做的代码修复了这个问题,但你必须改变弹跳函数,并使用你的代码,因为我的不是那么完美,但功能。

import pygame
pygame.init()
import random
import numpy

HEIGHT = 500
WIDTH = 500
NUM_BALLS = 2


#setup
win = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("Simulation")

class Particle(object):
    def __init__(self, x, y , radius):
        self.x = x
        self.y = y
        self.radius = radius
        self.xvel = random.randint(1,5)
        self.yvel = random.randint(1,5)
        self.colideCheck = []
    def Draw_circle(self):
        pygame.draw.circle(win, (255,0,0), (int(self.x), int(self.y)), self.radius)


def redrawGameWindow():
    win.fill((0,0,0))
    for ball in balls:
        ball.Draw_circle()
    pygame.display.update()
def bounce(v1,v2, mass1 = 1, mass2 = 1):




    #i Tried my own bouncing mechanism, but doesn't work completly well, add yours here




    multi1 = mass1/(mass1+mass2)
    multi2 = mass2/(mass1+mass2)
    deltaV2 = (multi1*v1[0]-multi2*v2[0],multi1*v1[1]-multi2*v2[1])
    deltaV1 = (multi2*v2[0]-multi1*v1[0],multi2*v2[1]-multi1*v1[1])
    print("preVelocities:",v1,v2)
    return deltaV1,deltaV2
def checkCollide(circ1Cord,circ1Rad,circ2Cord,circ2Rad):
    tryDist = circ1Rad+circ2Rad
    actualDist = dist(circ1Cord,circ2Cord)
    if dist(circ1Cord,circ2Cord) <= tryDist:
        return True
    return False
def dist(pt1,pt2):
    dX = pt1[0]-pt2[0]
    dY = pt1[1]-pt2[1]
    return (dX**2 + dY**2)**0.5
balls = []  
for turn in range(NUM_BALLS):
    balls.append(Particle(random.randint(60,WIDTH-60),random.randint(60,HEIGHT-60),60))


run = True
while run:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
    for ball in balls:
         if (ball.x + ball.radius) <= WIDTH and (ball.x - ball.radius) >= 0:
             ball.x += ball.xvel
         else:
             ball.xvel *= -1
             ball.x += ball.xvel
         if (ball.y + ball.radius) <= HEIGHT and (ball.y - ball.radius) >= 0:
             ball.y += ball.yvel
         else:
             ball.yvel *= -1
             ball.y += ball.yvel
    for ball in balls:
        for secBallCheck in balls:
            if secBallCheck not in ball.colideCheck and ball!= secBallCheck and checkCollide((ball.x,ball.y),ball.radius,(secBallCheck.x,secBallCheck.y),secBallCheck.radius):
                print("COLLIDE")
                vel1,vel2 = bounce((ball.xvel,ball.yvel),(secBallCheck.xvel,secBallCheck.yvel))
                print(vel1,vel2)
                ball.xvel = vel1[0]
                ball.yvel = vel1[1]
                ball.colideCheck.append(secBallCheck)
                secBallCheck.xvel = vel2[0]
                secBallCheck.yvel = vel2[1]
                secBallCheck.colideCheck.append(ball)
            elif not checkCollide((ball.x,ball.y),ball.radius,(secBallCheck.x,secBallCheck.y),secBallCheck.radius):
                if ball in secBallCheck.colideCheck:
                    secBallCheck.colideCheck.remove(ball)
                    ball.colideCheck.remove(secBallCheck)
    redrawGameWindow()
    pygame.time.delay(20)

pygame.quit()
 类似资料:
  • 为了计算x和y速度,我求解了一个动量守恒和动能守恒方程组。 顺便说一下,这些方程没有考虑圆的“形状”。 所以我通过求两个圆相交的切线来计算回弹角。 现在我有两个不同的最终速度方向:一个是用动量定律计算的,一个是用回弹计算的。 我不知道怎么把两种速度结合起来才能得到最后一种

  • 提前感谢所有的帮助者

  • 对于分子动力学的一门课,我要模拟一个有周期边界的盒子里的100个粒子。我必须考虑粒子与粒子的碰撞,因为墙壁是“透明的”,这些相互作用可以跨越边界发生。由于模拟应该包含50000个步骤,而且我希望将来会有越来越多的额外任务,所以我希望我的代码尽可能高效(尽管运行时间很长,但我必须使用python)。 该系统包括 null 按照我的理解,这种处理对整个数组的操作的技术比每次手动遍历它更有效。移动的粒子

  • 我正在构建一个迷宫游戏,在这里我有一个简单的地图... 直到没有问题,但我的问题是碰撞 这是我的地图: 在这里,我用以下代码自己构建了地图: 此碰撞代码用于右上角矩形 我已经尝试了两种不同类型的碰撞代码,但都不起作用 碰撞码: 在这里,当玩家从左侧击中矩形时,玩家向下移动,当玩家从底部击中矩形时,玩家向左移动。 我用if, else if语句尝试过相同的代码,但仍然不起作用。当玩家点击左侧时,它可

  • 我正在制作一个吃豆人风格的游戏,在pygame中使用蟒蛇。目前,我正在创造吃豆人必须在迷宫周围避免的幽灵/怪物。我已经创建了这些,并试图添加随机运动碰撞检测,以便它们在迷宫中移动,而不仅仅是整个屏幕。这些怪物的代码是波纹管。我的问题是,似乎有点跳来跳去,几乎一动不动,我怎么能像吃豆人幽灵一样顺利地穿过迷宫?任何帮助都非常感谢。