2017-01-22 9 views
1

Я недавно был сделать орбитальную симулятор с помощью этого уравнения: Picture of Equation I am usingPygame орбиты моделирования вопрос

Вот мой код:

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) 

Если я просто 1 планета в моделировании она работает, как ожидалось, но при этом она имеет проблемы

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

планеты летят с экрана и продолжать вечно, я не могу видеть, где я допустил ошибку.

+0

Не связанная с вашей конкретной проблемой ваша реализация не совсем точно, как гравитация работает. У вас есть один центральный «мир», воздействующий на «планеты», не влияя на себя. И ваши «планеты» вообще не влияют друг на друга.В действительности все объекты притягиваются друг к другу по-разному, и если A оказывает силу F на B, то сила, действующая на B из A, равна -F. Поэтому технически вам нужен вложенный цикл и вычислять все попарные отношения один раз (противоположное направление избыточно, как указано выше). Не забудьте правильно выбрать знаки, так как уравнение не предоставляет их. –

+0

@ MartinKrämer Да, это то, как я хотел реализовать это, но я могу легко изменить, если приложить силы между центральным телом, а затем другим. – adammoyle

+0

[Попробуйте использовать IDE] (http://sopython.com/wiki/Python_IDEs). Это поможет вам как в написании лучшего кода, так и в обучении программированию. Лично я использую PyCharm, который будет уведомлять вас об измененных аргументах по умолчанию, но, вероятно, другие IDE имеют схожие функции. –

ответ

2

Вы попали за вековую ловушку Python, объявив изменяемые аргументы по умолчанию. :)

Чтобы вырезать в погоню, так что вы можете получить свой код работает, скопируйте замены я сделал ниже в свой собственный код:

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]]] 

Объяснение

В Python списки mutable - вы можете изменить один и тот же экземпляр списка. Одной из распространенных ошибок, которые люди делают при использовании Python, является объявление изменяемых аргументов в качестве значений по умолчанию в сигнатурах функций.

Проблемы заключается в том, что Python будет присвоить значение , что по умолчанию один раз к параметру в то время, что определение функции обрабатывается, а затем повторное присвоенного значения каждый раз, когда функция вызывается и аргумент по умолчанию призвало ,

В вашем конструкторе класса Planet, вы объявить два изменяемых аргументов по умолчанию:

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

Каждый экземпляр Planet вы создаете будет хранить ссылки на эти списки, но обратите внимание, что из-за того, что я сказал выше, каждая планета будет делиться такими жеvel и таких жеpos список. Это означает, что каждый случай будет мешать данным о скорости и местоположении других.

Подробнее об этом можно узнать по телефону here.

Альтернативный и предпочтительный способ обработки ситуаций, как это было бы установить значение по умолчанию, как None, а затем присвоить «реальное» значение по умолчанию, если абонент не дает явного значения для него:

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]]] 

Тогда вам следует было документировать это поведение функции, так как в противном случае это не было бы очевидно для вызывающего.