python - Pygame轨道模拟问题

标签 python pygame physics game-physics orbital-mechanics

我最近一直在使用这个方程制作轨道模拟器:Picture of Equation I am using

这是我的代码:

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)

行星飞出屏幕并永远继续下去,我看不出我在哪里犯了错误。

最佳答案

您陷入了声明可变默认参数的古老 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 中,列表是可变的 - 您可以修改列表的同一实例。人们在使用 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]]]

然后,您需要记录该函数的这种行为,因为否则调用者不会明显看出。

关于python - Pygame轨道模拟问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41796276/

相关文章:

python - 如何在Python中隐藏SDL库调试消息?

python - 在 pymunk 中在动态体和移动静态体之间创建 DampedRotarySpring

unity-game-engine - 使两个物理对象不发生碰撞,但在 Unity 中检测碰撞

ios - SceneKit:两个节点之间接触后 UIView 加载缓慢

python - 有条件地将 pandas.DataFrame 中的值替换为之前的值

python - Bokeh Columnsourcedata 查找最小值和最大值

python - url 中的 id(数字) 路径

python - Graphite 和 GUnicorn - 配置问题或路径问题

python - Pygame 屏幕在我关闭时卡住

python - 在 python 中结合两个势