I'm creating a basic physics engine in python and I've managed to create a simple "planet" class to handle the maths. I've also created a basic working scenario when a small planet orbits a larger one - if the small planet has zero mass. However, when I give the small planet any mass it slowly pulls the sun to the right in an arc shape. It's easier to see in this image:
.
I understand what's going on - the earth is pulling the sun right on one side and stopping it but not pulling it back on the other - but I have no idea how to fix it, short of giving the sun a hard-coded velocity. I've checked a few other sources but nothing helps - in fact this physics sim has the same problem (uncheck system centered).
Does this happen in the real world, or is it a glitch with this type of simulation? Either way, is there some sort of hack to prevent this from happening?
My planet class (all the methods are pretty straightforward):
import math
G = 6
class Planet():
def __init__(self, x = 0, y = 0, vx = 0, vy = 0, mass = 1, radius = 1, colour = "#ffffff"):
self.x = x
self.y = y
self.vx = vx
self.vy = vy
self.mass = mass
self.radius = radius
self.colour = colour
def draw(self, canvas):
canvas.create_oval(self.x - self.radius, self.y - self.radius, self.x + self.radius, self.y + self.radius, fill = self.colour)
def move_next(self):
self.x += self.vx
self.y += self.vy
def apply_gravity(self, other):
if other is self: #make sure you're not checking against yourself.
return 1
x = other.x - self.x
y = other.y - self.y
r = math.hypot(x, y)
if r == 0: #make sure they're not on each other.
return 1
gravity = G * (other.mass) / (r ** 2) #calculate the force that needs to be applied
self.vx += (x / r) * gravity #normalise the x component of vector and multiply it by the force
self.vy += (y / r) * gravity #normalise the y component of vector and multiply it by the force
And the "main" file:
from tkinter import *
import time
import planet
FPS = 1/60
window = Tk()
canvas = Canvas(window, width = 640, height = 400, bg = "#330033")
canvas.pack()
earth = planet.Planet(x = 320, y = 100, vx = 10, mass = 1, radius = 10, colour = "lightblue") #Because the earth's mass is so low, it won't be AS noticable, but it still pulls the sun a few pixels per rotation.
sun = planet.Planet(x = 320, y = 200, mass = 2e3, radius = 20, colour = "yellow")
planets = [earth, sun]
while True:
canvas.delete(ALL)
for planet in planets:
for other in planets:
planet.apply_gravity(other)
planet.move_next()
planet.draw(canvas)
window.update()
time.sleep(FPS)