2017-01-22 5 views
1

J'ai récemment été faire un simulateur d'orbite en utilisant cette équation: Picture of Equation I am usingPygame problème simulation orbite

Voici mon code:

import pygame, math 
from pygame.locals import * 
from random import randint 
pygame.init() 
screen = pygame.display.set_mode([500,500]) 
clock = pygame.time.Clock() 

class Planet(): 
    def __init__(self, vel = [1, 1], mass = 100000, pos = [100, 100], pathLength = 100000): 
     self.v = vel 
     self.m = mass 
     self.size = mass/1000000 
     self.pos = pos 
     self.pL = pathLength 
     self.path = [[pos[0], pos[1]]] 

    def update(self): 
     self.pos[0] += self.v[0] 
     self.pos[1] += self.v[1] 
     self.path.append([self.pos[0], self.pos[1]]) 
     if len(self.path) == self.pL: 
      self.path.pop(0) 

class World(): 
    def __init__(self, planetList, iterations, mass = 10000000, gravityConstant = (6 * 10 ** -9)): 
     self.plnt = planetList 
     self.iter = iterations 
     self.mass = mass 
     self.size = int(mass/1000000) 
     self.gC = gravityConstant 
    def draw(self): 
     pygame.draw.circle(screen, [0, 0, 0], [250, 250], self.size) 
     for p in self.plnt: 
      pygame.draw.rect(screen, [0, 0, 0], [p.pos[0], p.pos[1], p.size, p.size]) 
      pygame.draw.lines(screen, [0, 0, 0], False, p.path) 
    def update(self): 
     for i in range(self.iter): 
      for p in self.plnt: 
       d = math.sqrt((p.pos[0] - 250) ** 2 + (p.pos[1] - 250) ** 2) 
       f = (self.gC * self.mass * p.m)/(d ** 2) 
       vect = [((250 - p.pos[0])/d) * f, ((250 - p.pos[1])/d) * f] 
       p.v[0] += vect[0] 
       p.v[1] += vect[1] 
       p.update() 
     self.draw() 


a = Planet([4,0]) 
b = Planet([4, 0]) 
w = World([b], 100) 
while 1: 
    screen.fill([255, 255, 255]) 

    w.update() 

    for event in pygame.event.get(): 
     if event.type == QUIT: 
      pygame.quit() 

    pygame.display.update() 
    clock.tick(60) 

Si j'ai juste 1 planète dans la simulation, il fonctionne comme prévu, mais avec cela, il a des problèmes

a = Planet([4,0]) 
b = Planet([4, 0]) 
w = World([a, b], 100) 

les planètes volent hors de l'écran et continuer pour toujours, je ne vois pas où je l'ai fait une erreur.

+0

Indépendamment de votre problème particulier, votre implémentation n'est pas exactement comment fonctionne la gravité. Vous avez un "monde" central qui exerce la gravité sur les "planètes" sans être influencé par lui-même. Et vos "planètes" ne s'influencent pas du tout.En réalité, tous les objets exercent la gravité l'un sur l'autre par paires et si A exerce une force F sur B alors la force exercée sur B par A est -F. Donc, techniquement, vous avez besoin d'une boucle imbriquée et de calculer toutes les relations par paires une fois (la direction opposée est redondante comme indiqué ci-dessus). Assurez-vous de bien choisir les signes car l'équation ne les fournit pas. –

+0

@ MartinKrämer Oui, c'est comme cela que je voulais mettre en œuvre ceci mais yeh je pourrais facilement modifier si exercer des forces entre le corps central et l'autre. – adammoyle

+0

[Essayez d'utiliser un IDE] (http://sopython.com/wiki/Python_IDEs). Il vous aidera énormément à la fois dans l'écriture d'un meilleur code et dans l'apprentissage de la programmation. Personnellement, j'utilise PyCharm qui vous informerait des arguments mutables par défaut, mais probablement d'autres IDE ont des fonctionnalités similaires. –

Répondre

2

Vous êtes tombé pour l'ancien piège Python de déclarer des arguments par défaut mutables. :)

Pour couper à la chasse afin que vous puissiez obtenir votre travail de code, copiez les remplacements que j'ai fait ci-dessous dans votre propre code:

class Planet(): 
    def __init__(self, vel = [1, 1], mass = 100000, pos = [100, 100], pathLength = 100000): 
     self.v = vel[:] # Added [:] to ensure the list is copied 
     self.m = mass 
     self.size = mass/1000000 
     self.pos = pos[:] # Added [:] here for the same reason 
     self.pL = pathLength 
     self.path = [[pos[0], pos[1]]] 

Explication

En Python, les listes mutable - vous pouvez modifier la même instance d'une liste. Une erreur courante que les gens font lors de l'utilisation de Python est de déclarer les arguments mutables comme valeurs par défaut dans les signatures de fonctions.

Le problème est que Python attribue cette valeur par défaut une fois au paramètre au moment où la définition de la fonction est traitée, puis réutilisation que la valeur attribuée à chaque fois que la fonction est invoquée et l'argument par défaut appelé .

Dans votre constructeur de la classe Planet, vous êtes en déclarant deux arguments par défaut mutables:

  • vel = [1, 1]
  • pos = [100, 100]

Chaque instance de Planet vous créez stocker une référence à ces listes, mais notez que à cause de ce que j'ai dit ci-dessus, chaque planète partagera le mêmevel liste et même listepos. Cela signifie que chaque instance interfère avec les données de vitesse et de position des autres.

Vous pouvez en savoir plus sur ce gotcha here.

Une manière alternative et préférée des situations de manipulation comme celui-ci serait de définir la valeur par défaut comme None puis attribuez-lui la valeur par défaut « réelle » si l'appelant ne fournit pas une valeur explicite pour elle:

class Planet(): 
    def __init__(self, vel = None, mass = 100000, pos = None, pathLength = 100000): 
     self.v = vel or [1, 1] 
     self.m = mass 
     self.size = mass/1000000 
     self.pos = pos or [100, 100] 
     self.pL = pathLength 
     self.path = [[self.pos[0], self.pos[1]]] 

Vous devrez alors documenter ce comportement de la fonction, car cela ne serait pas apparent à l'appelant autrement.