2017-10-20 79 views
1

我一直在试图用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() 
+0

你能后的输出值的片段吧。 – Petar

+0

当然,我已经从发生问题的时间左右隔离了这些值。打印语句会告诉您打印的变量的顺序。 – Oliver

+0

'------------------- 63.844549149787156 21.125165327178536 67.24878486813137 71.6914260165494 11.056078702397329 [10.496403191570936,3.4730960703071965] [-6.9922567082937785,29.012459884108917] (456.8522924414934,350.13762521128746) - ------------------ 56.852292441493375 50.13762521128746 75.80214124733293 48.59116240316936 8.701759117372143 [6.526398145958425,5.755583287313254] [-0.4658585623353533,34.76804317142217] (456.386433879158,384.9056683827096) ---- ---------------' – Oliver

回答

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为负值,而不是正值。

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

+0

谢谢,我完全忘记了我可以使用'd_x/distance'和'd_y/distance'!我只是认为我必须找出角度,并用它来获得加速度,但这并不是我想到的。另外,我会扭转加速度朝向太阳。 – Oliver