在朋克朋民之间产生排斥

问题描述

我正在尝试制作一个动画,其中两个磁铁(互相排斥)掉入旋转的管中。我有下降(重力)位并向下旋转,但是磁力有问题。我使用的力的等式为(磁体1的磁强度x磁体2的磁强度)/(磁体之间的距离)^ 2。基本上,力的强度随着磁体之间距离的平方而减小。目的是使磁铁彼此排斥,因为相同的磁极彼此面对。我相信我没有正确使用“ apply_force_at_local_point”命令。我尤其不确定在“ apply_force_at_local_point”命令中更新力的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)] #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,420),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]),(masses[1].body.position.x,masses[1].body.position.y)) #this needs to be fixed

pygame.quit()

解决方法

代码有几个问题。我认为主要问题是您使用apply_force_at_local_point而不是apply_force_at_world_point。在局部上施加从身体的局部上施加力。也就是说,力和位置都应在身体局部坐标中给出。因此,例如,如果将力的位置置于(0,0),则意味着力将施加在身体的中心。请注意,也应考虑角度。

通常,在世界坐标系中更容易思考,而改用apply_force_at_world_point。从您的代码看来,这也是您的想法,因为您将力施加在身体世界的位置上。

其他一些问题:

  1. 您将覆盖矩形实体上的质量。本身不是问题,但您会感到困惑:) 如果设置附加到实体的形状的密度,它们将覆盖您指定的任何质量。因此,在您的代码中实际上未使用rect_mass。而是使用您在形状上设置的密度来计算身体的质量和力矩。要查看产生的质量和力矩,只需将它们添加到空间后再打印:print(body.mass,body.moment)

  2. 在第二个施加力中,您乘以-1。但是,与之相乘的是一个元组,因此最终结果是一个空的元组。

-1 * (
    mag_force * (temp[1][0] - temp[0][0]),mag_force * (temp[1][1] - temp[0][1]),) 

相反,您可以将其包装在pymunk.Vec2d中,也可以将-1移入其中:

-1 * Vec2d(
    mag_force * (temp[1][0] - temp[0][0]),)
#or 
(
    -1 * mag_force * (temp[1][0] - temp[0][0]),-1 * mag_force * (temp[1][1] - temp[0][1]),)

最后,当我查看您的代码时,我做了两件事来帮助我调试问题。首先是打印/绘制有问题的零件。

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

  2. 这对我施加作用力很有用。一种方法是执行以下操作:

f1 = (
    mag_force * (temp[1][0] - temp[0][0]),)
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),False,[(100,100),(round(p2.x),round(p2.y))],3,)

(然后再绘制一个图形,例如(300,100))

最后,我想补充一点,pymunk.Vec2d具有进行诸如两点之间的距离之类的计算的功能(例如rel_dist = temp[0].get_distance(temp[1]))。但这更多是个人选择,自从我成为《 Pymunk》作者以来,我颇有偏见:)