2017-10-20 10 views
1

私は単純な重力をシミュレートするためにpygameでコードを作成しようとしてきました。現時点では、太陽の周りを周回している物体(HOM)は1つしかありません。しかし、私が知らない理由から、コードを実行するたびに、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

あなたの主な問題は、この行に関係しています:

angle = atan(d_x/d_y) #Find angle 

それが兆候を伝えることができないので、atan関数は角度を計算する能力が非常に限られていますあなたがあなたの部門に結合した座標の例えば、両方の部門が同じスロープ(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