Python 在pymunk质量之间创建排斥

Python 在pymunk质量之间创建排斥,python,physics,pymunk,Python,Physics,Pymunk,我试图制作一个动画,其中两个磁铁(相互排斥)落在一个旋转的管中。我有下降(重力)位和向下旋转,但我有磁力问题。我使用的力的方程是(磁铁的磁性强度1 x磁铁的磁性强度2)/(磁铁之间的距离)^2。基本上,力的强度随着磁铁之间距离的平方而减小。目标是让磁铁彼此排斥,因为相同的磁极彼此面对。我相信我没有正确使用“在本地点应用力”命令。我特别不确定是否要更新“在本地点应用力”命令中力的x和y方向 你真的不需要知道太多的物理知识。提前谢谢你的帮助 import pymunk import pymunk.p

我试图制作一个动画,其中两个磁铁(相互排斥)落在一个旋转的管中。我有下降(重力)位和向下旋转,但我有磁力问题。我使用的力的方程是(磁铁的磁性强度1 x磁铁的磁性强度2)/(磁铁之间的距离)^2。基本上,力的强度随着磁铁之间距离的平方而减小。目标是让磁铁彼此排斥,因为相同的磁极彼此面对。我相信我没有正确使用“在本地点应用力”命令。我特别不确定是否要更新“在本地点应用力”命令中力的x和y方向

你真的不需要知道太多的物理知识。提前谢谢你的帮助

import pymunk
import pymunk.pygame_util
import pygame
import numpy as np

GRAY = (220, 220, 220)

width_mass=48
height_mass=48

charges=[10000,-10000] #magnet strengths

pygame.init()
size = 800,600
screen = pygame.display.set_mode(size,pygame.FULLSCREEN)
draw_options = pymunk.pygame_util.DrawOptions(screen)

space = pymunk.Space()
space.gravity = (0,-900)

pts = [(-27, -238.5), (27,-238.5), (27,238.5), (-27,238.5)] #enpoints of the endlessly rotating rectangle
body_type=pymunk.Body(body_type=pymunk.Body.KINEMATIC)  
body_type.position = (400, 263.5)  
space.add(body_type)
for i in range(4):
    segment = pymunk.Segment(body_type, pts[i], pts[(i+1)%4], 2)
    space.add(segment)

body_type.angular_velocity=1 #rotation speed


class Rectangle:
    def __init__(self, rect_mass, pos,size=(80, 50)):
        self.body = pymunk.Body(mass=rect_mass)
        self.body.position = pos
        shape = pymunk.Poly.create_box(self.body, size)
        shape.density = 0.1
        space.add(self.body, shape)

mass_1 = Rectangle(rect_mass=1,pos=(400,473),size=(50,50))

mass_2 = Rectangle(rect_mass=1,pos=(400,420),size=(50,50))

masses=[mass_1,mass_2]

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill(GRAY)
    space.debug_draw(draw_options)
    pygame.display.update()
    space.step(0.01)
    temp=[] #collecting the positions of all masses in one place
    for mass in masses:
        temp.append(mass.body.position)
    if len(masses)==2:
        rel_dist=np.sqrt((temp[1][1]-temp[0][1])**2+(temp[1][0]-temp[0][0])**2) #euclidean distance between magnets
        mag_force=charges[0]*charges[1]/(rel_dist**2 + 0.00001) #force = magnet1*magnet2/dist of the magnets^2
        masses[0].body.apply_force_at_local_point(
            (mag_force*(temp[1][0]-temp[0][0]),
            mag_force*(temp[1][1]-temp[0][1])), 
            (masses[0].body.position.x,masses[0].body.position.y)) #this needs to be fixed
        masses[1].body.apply_force_at_local_point(
            -1*(mag_force*(temp[1][0]-temp[0][0]),
            mag_force*(temp[1][1]-temp[0][1])), 
            (masses[1].body.position.x,masses[1].body.position.y)) #this needs to be fixed

pygame.quit()

代码有几个问题。我认为主要的问题是,您在本地点使用
apply\u force\u
,而不是在世界点使用
apply\u force\u
。在局部点应用从实体的局部点应用力。也就是说,力和位置都应该在身体局部坐标中给出。例如,如果将力的位置设置为(0,0),则表示力将应用于物体的中心。请注意,还应考虑角度

通常,在世界坐标系中思考更容易,而使用
在世界点处应用力
。从你的代码来看,当你把力施加在身体世界的位置时,你似乎也是这样想的

其他一些问题:

  • 覆盖矩形实体上的体量。这本身不是问题,但您会感到困惑:) 若设置附着到实体的形状的密度,它们将覆盖指定的任何质量。因此,在您的代码中,实际上没有使用质量校正。相反,通过使用在形状上设置的密度来计算物体的质量和力矩。要查看生成的质量和力矩,您可以在将它们添加到空间后将其打印:
    print(body.mass,body.moment)

  • 在第二次施力时,将力乘以
    -1
    。但是,与之相乘的是一个元组,因此最终结果是一个空元组

  • 相反,您可以将其包装在pymunk.Vec2d中,或者将-1移到内部:

    -1 * Vec2d(
        mag_force * (temp[1][0] - temp[0][0]),
        mag_force * (temp[1][1] - temp[0][1]),
    )
    #or 
    (
        -1 * mag_force * (temp[1][0] - temp[0][0]),
        -1 * mag_force * (temp[1][1] - temp[0][1]),
    )
    
    最后,当我查看您的代码时,我做了两件事来帮助我调试这个问题。首先是打印/绘制有问题的部分

  • 可以为形状设置单独的颜色。这样更容易理解他们的行为。例如,像这样
    shape.color=(255,0,0255)
    其中元组是RGBA元组,以使形状变为红色

  • 画出施加的力对我很有用。一种方法是这样做:

  • (然后在例如(300100)处绘制第二张图纸)

    最后,我想补充一点,
    pymunk.Vec2d
    具有计算两点之间距离的函数(例如
    rel_dist=temp[0]。get_distance(temp[1])
    )。但这更多的是个人的选择,我有很大的偏见,因为我是Pymunk的作者:)

    -1 * Vec2d(
        mag_force * (temp[1][0] - temp[0][0]),
        mag_force * (temp[1][1] - temp[0][1]),
    )
    #or 
    (
        -1 * mag_force * (temp[1][0] - temp[0][0]),
        -1 * mag_force * (temp[1][1] - temp[0][1]),
    )
    
    f1 = (
        mag_force * (temp[1][0] - temp[0][0]),
        mag_force * (temp[1][1] - temp[0][1]),
    )
    masses[0].body.apply_force_at_world_point(
        f1, (masses[0].body.position.x, masses[0].body.position.y)
    )
    p2 = (100, 100) + pymunk.Vec2d(f1) / 10000
    pygame.draw.lines(
        screen,
        (100, 0, 0),
        False,
        [(100, 100), (round(p2.x), round(p2.y))],
        3,
    )