So im trying to simulate gravity between 2 (and hopefully more) planets in python using pygame. I've run itto 3 main problems that i just can't seem to figure out. The first one is that the small moon that im trying to simulate first just goes towards the big planet completely wrong, if you copy paste the code below you can see that it goes 45 degrees up utnil they're at the same y-axis and then goes right inside the planet. I'm pretty sure that isn't how gravity work. The 2nd problem is that i don't know how i could add a start-velocity to the moon so that its actually capable of going into orbit. The 3rd problem is that I have no clue how to add more planets/moons without really long lines of code. Any help would be appreaciated! Code:
import pygame
import math
''
w = 1280
h = 720
g = 25
def main():
pygame.init()
running = True
xm1 = float(200)
ym1 = float(660)
xm2 = float(w/2)
ym2 = float(h/2)
mass1 = int(10)
mass2 = int(100)
while running:
screen = pygame.display.set_mode((w, h))
pygame.draw.circle(screen, (0, 255, 0), (xm1, ym1), 15, 15)
pygame.draw.circle(screen, (255, 0, 0), (xm2, ym2), 45, 45)
distance = math.sqrt((xm1-xm2)**2 + (ym1-ym2)**2)
if ym1 > ym2:
ym1 += g * mass2 / -distance ** 2
else:
ym1 -= g * mass2 / -distance ** 2
if ym1 < ym2:
ym2 += g * mass1 / -distance ** 2
else:
ym2 -= g * mass1 / -distance ** 2
if xm1 > xm2:
xm1 += g * mass2 / -distance ** 2
else:
xm1 -= g * mass2 / -distance ** 2
if xm1 < xm2:
xm2 += g * mass1 / -distance ** 2
else:
xm2 -= g * mass1 / -distance ** 2
if distance <= 60:
running = False
pass
pygame.display.update()
main()
-
2Here's a small hint for you: There are no "if" statements in nature. Gravity – as every other force – does not have conditionals. When simulating things, you'll encounter conditionals mostly to deal with collisions, but that's just because the fundamental physics of collisions happens on such small scales (electromagnetic fields acting between atoms) and such large numbers of particles involved, that you can't practically do it numerically.datenwolf– datenwolf2020年11月14日 17:17:14 +00:00Commented Nov 14, 2020 at 17:17
-
I think you need to research how to simulate the effect of gravity between two untethered masses - I’d have thought the initial x and y velocity of the masses matters rather a lot, and also the time interval to update the simulation. For linear movement v=u+atDisappointedByUnaccountableMod– DisappointedByUnaccountableMod2020年11月14日 17:18:23 +00:00Commented Nov 14, 2020 at 17:18
-
@datenwolf Yes I'd like to not use if statements but whenever one of the objects passes each others x or y position i have to substract and not add force and I don't think i could do that without if statements. I probably have to just start over and think of another way of doing it because i don't think thiis way will workNoah9111– Noah91112020年11月14日 17:31:30 +00:00Commented Nov 14, 2020 at 17:31
-
@Noah9111: No, you don't have to switch between adding/subtracting. You only add. The gravitational force between two masses as a vector is F = (r-R)·m·M·G / distance(r,R)³, where r and R are the position vectors. Note the use of the exponent in the denominator being 3, so that with the vector difference in the numerator you get the inverse square law (G is the gravitational constant).datenwolf– datenwolf2020年11月14日 17:36:44 +00:00Commented Nov 14, 2020 at 17:36
2 Answers 2
I rewrote your code so that it actually simulates free fall as described by Newton's laws. Never mind, that this naive implementation is terribly unstable, numerically for small distances. Essentially this is numerically integrating a differential equation, and some method like by Runge-Kutta or similar should be applied. Anyway, the gist is
def gravity(m1,r1,m2,r2):
d = vsub(r2,r1);
return vmul(d, m1*m2/(vlen(d)**3))
def main():
pygame.init()
screen = pygame.display.set_mode((w, h))
running = True
r1 = (200., 660.)
r2 = (w/2., h/2.)
v1 = ( 0.3, 0)
v2 = (-0, 0)
m1 = 10.
m2 = 100.
while running:
screen.fill((0,0,0))
pygame.draw.circle(screen, map(int, (0, 255, 0)), map(int, r1), 15, 15)
pygame.draw.circle(screen, map(int, (255, 0, 0)), map(int, r2), 45, 45)
F = gravity(m1,r1,m2,r2)
v1 = vadd(v1, vmul(F, G/m1));
v2 = vadd(v2, vmul(F, -G/m2));
r1 = vadd(r1, v1)
r2 = vadd(r2, v2)
pygame.display.update()
main()
I'll leave it as an exercise for you to implement the vadd, vsub, vmul, and vlen functions.
1 Comment
To your 3rd Question if didn't find a solution yourself and the anwer isn't too late, classes would help
It would be something like that:
class Planetary_objekt():
def __init__(mass = 1,
x = 0, y = 0,
velocity = [0,0],
color = 255,255,255,
radius = 100
):
self.mass = mass
self.x = x
self.y = y
self.x_velocity = velocity[0]
self.y_velocity = velocity[1]
def draw(self):
pygame.draw.circle(screen, map(int, self.color), map(int, self.radius), self.x, self.y)