重力问题

时间:2017-10-20 07:52:59

标签: python pygame

我一直试图用pygame制作代码来模拟简单的引力。目前,只有一个物体(HOM)绕太阳运行。然而,由于我不知道的原因,每当我运行代码时,HOM在开始时在轨道上绕太阳运行,但是当它到达时从太阳加速 离开 距垂直方向约135度。

有谁知道为什么会发生这种情况以及如何解决这个问题?我一直在打印一些变量来尝试解决问题,但到目前为止还没有运气。

代码:

import pygame,sys,time
from math import *

screen=pygame.display.set_mode((800,600))

G = 5

class Object: #Just an object, like a moon or planet
    def __init__(self,mass,init_cds,init_vel,orbit_obj='Sun'):
        self.mass = mass
        self.cds = init_cds
        self.velocity = init_vel
        self.accel = [0,0]
        self.angle = 0
        self.orb_obj = orbit_obj

    def display(self):
        int_cds = (round(self.cds[0]),round(self.cds[1]))#Stores its co-ordinates as floats, has to convert to integers for draw function
        pygame.draw.circle(screen,(255,0,0),int_cds,10)

    def calc_gravity(self):
        if self.orb_obj == 'Sun':
            c_x,c_y = 400,300
            c_mass = 10000
        else:
            c_x,c_y = self.orb_obj.cds
            c_mass = self.orb_obj.mass
        d_x = self.cds[0]-c_x
        d_y = self.cds[1]-c_y
        dist = sqrt(d_x**2+d_y**2) #Find direct distance
        angle = atan(d_x/d_y) #Find angle
        print(d_x,d_y)
        print(dist,degrees(angle))
        if dist == 0:
            acc = 0
        else:
            acc = G*c_mass/(dist**2) #F=G(Mm)/r^2, a=F/m -> a=GM/r^2
        print(acc)
        acc_x = acc*sin(angle) #Convert acceleration from magnitude+angle -> x and y components
        acc_y = acc*cos(angle)
        self.accel = [acc_x,acc_y]
        print(self.accel)
        self.velocity = [self.velocity[0]+self.accel[0],self.velocity[1]+self.accel[1]] #Add acceleration to velocity
        print(self.velocity)
        self.cds = (self.cds[0]+self.velocity[0],self.cds[1]+self.velocity[1]) #Change co-ordinates by velocity
        print(self.cds)
        print('-------------------') #For seperating each run of the function when printing variables

HOM = Object(1000000,(400,100),[10,0]) #The problem planet

clock = pygame.time.Clock()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    screen.fill((0,0,0))
    pygame.draw.circle(screen,(255,255,0),(400,300),25)
    HOM.display()
    HOM.calc_gravity()

    clock.tick(30)

    pygame.display.flip()

1 个答案:

答案 0 :(得分:1)

你的主要问题与这一行有关:

angle = atan(d_x/d_y) #Find angle

atan函数计算角度的能力非常有限,因为它无法分辨您在分区中组合的坐标的符号。例如,它会为atan(1/1)atan(-1/-1)提供相同的结果,因为两个分区都计算相同的斜率(1)。

相反,您应该使用atan2,并分别传递坐标。因为这会让代码看到两个坐标,所以每次都可以在圆的右象限中选择一个角度。

但是还有更好的解决方法。不是计算角度然后立即将其转换回单位向量(通过调用sincos),为什么不直接计算单位向量?你已经有了原始矢量的长度!而不是:

acc_x = acc*sin(angle) #Convert acceleration from magnitude+angle -> x and y components
acc_y = acc*cos(angle)

使用:

acc_x = acc * d_x / distance
acc_y = acc * d_y / distance

d_x / distanced_y / distance值与您之前获得的sincos值相同(对于他们正常工作时的角度),但是不需要三角学。你可以完全摆脱我引用的那条线!

请注意,可能需要反转您计算d_xd_y的方式,以便获得从轨道物体指向物体的矢量它绕着轨道运行(而不是指向另一个方向,从轨道中心朝向轨道物体)。我不确定我是否正确地阅读了你的代码,但它看起来像你现在已经反过来了。这意味着,在您当前代码按预期方式工作的情况下,您实际上从atan获得了错误的结果,并且不良行为(飞向无处)是代码正常工作(来自数学观点)。或者,您可以将acc计算为负数,而不是正数。

正如一些评论者所提到的,您可能还有其他与您选择积分算法相关的问题,但这些错误不会像加速角度的主要问题那么大。当您在较长时间段内运行模拟时,它们会突然出现(并尝试使用更大的时间步长来使模拟更快)。你当前的算法对于一两个轨道是足够好的,但是如果你正在模拟几十个或几百个轨道,你就会开始看到错误累积,所以你应该选择一个更好的积分器。