2017-10-20 2 views
1

나는 간단한 중력을 시뮬레이트하기 위해 파이 게임으로 코드를 만들려고 노력해 왔습니다. 현재 태양 주위를 공전하고있는 물체 (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

물론 문제가 발생한 시간대의 값을 격리했습니다. print 문은 변수의 순서가 인쇄 된 것을 알려줍니다. – 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 48.59116240316936 8.701759117372143 75.80214124733293 [6.526398145958425, 5.755583287313254] [-0.4658585623353533, 34.76804317142217] (456.386433879158, 384.9056683827096) ---- ---------------' – Oliver

답변

1

귀하의 주요 문제는이 라인을 함께 할 수있다 :

atan 기능은 매우는 징후를 알 수 없기 때문에 각도를 계산하는 능력에 제한이
angle = atan(d_x/d_y) #Find angle 

귀하가 귀하의 부서에서 합친 좌표의 예를 들어, 두 부서가 동일한 기울기 (1)를 계산하므로 atan(1/1)atan(-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을 양수가 아닌 음수로 계산할 수 있습니다.

언급자 중 몇 명이 언급했듯이 선택한 통합 알고리즘과 관련된 다른 문제가있을 수 있지만 이러한 오류는 가속 각도의 주요 문제만큼 커지지는 않습니다. 더 오랜 기간 동안 시뮬레이션을 실행하면 시뮬레이션 시간이 길어지고 (시뮬레이션을 빠르게 진행하려면 더 많은 시간 단계를 사용하려고 시도합니다) 현재의 알고리즘은 궤도 또는 2 개의 궤도에서는 충분하지만, 수십 또는 수백 개의 궤도를 시뮬레이트하는 경우 오류가 누적되는 것을 볼 수 있으므로 더 나은 통합자를 선택해야합니다.

+0

고마워, 나는 단지'd_x/distance'와'd_y/distance'를 사용할 수 있다는 것을 완전히 잊었다! 나는 방금 각도를 알아야하고 가속을 위해 이것을 사용해야한다고 생각했는데, 그것은 나에게 일어나지도 않았다. 또한 가속도를 역전시켜 태양쪽으로 향하게합니다. – Oliver