Skip to content

Instantly share code, notes, and snippets.

@jcayouette
Created April 25, 2023 17:33
Show Gist options
  • Save jcayouette/23b2f3ef4097881370ae805b9162d531 to your computer and use it in GitHub Desktop.
Save jcayouette/23b2f3ef4097881370ae805b9162d531 to your computer and use it in GitHub Desktop.
Planetary orbits with newtonian physics in pygame
import pygame
import math
pygame.init()
WIDTH, HEIGHT = 1920, 1080
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Planet Simulation")
WHITE = (255, 255, 255)
YELLOW = (255, 255, 0)
BLUE = (100, 149, 237)
RED = (188, 39, 50)
DARK_GREY = (80, 78, 81)
FONT = pygame.font.SysFont("comicsans", 16)
# Class defining the PLANET object
class Planet:
# Planet VALUES
# 1 au distance from earth to sun 149 million km converted to meters
AU = 149.6e6 * 1000
# Gravity
G = 6.67428e-11
# Scale 1 AU = 100 pixels reduce number on left to help fit on screen
SCALE = 300 / AU
# Represents 1 days worth of orbital movement 3600 seconds in 24 hours
TIMESTEP = 3600 * 24
def __init__(self, x, y, radius, color, mass):
self.x = x
self.y = y
self.radius = radius
self.color = color
self.mass = mass
# track orbit points planet has traveled on
self.orbit = []
# The sun does not orbit in this sim set it to false
self.sun = False
self.distance_to_sun = 0
self.x_vel = 0
self.y_vel = 0
def draw(self, win):
x = self.x * self.SCALE + WIDTH / 2
y = self.y * self.SCALE + HEIGHT / 2
if len(self.orbit) > 2:
updated_points = []
for point in self.orbit:
x, y = point
x = x * self.SCALE + WIDTH / 2
y = y * self.SCALE + HEIGHT / 2
updated_points.append((x, y))
pygame.draw.lines(win, self.color, False, updated_points, 2)
pygame.draw.circle(win, self.color, (x, y), self.radius)
if not self.sun:
distance_text = FONT.render(
f"{self.distance_to_sun/1000, 1}km", 1, WHITE)
win.blit(distance_text, (x - distance_text.get_width() /
2, y - distance_text.get_height()/2))
# Using actual solar system numbers to calculate motion of objects and gravitational relationship
def attraction(self, other):
other_x, other_y = other.x, other.y
distance_x = other_x - self.x
distance_y = other_y - self.y
distance = math.sqrt(distance_x ** 2 + distance_y ** 2)
if other.sun:
self.distance_to_sun = distance
force = self.G * self.mass * other.mass / distance ** 2
theta = math.atan2(distance_y, distance_x)
force_x = math.cos(theta) * force
force_y = math.sin(theta) * force
return force_x, force_y
def update_position(self, planets):
# Obtaining total forces exerted on each planet from all other planets (and the sun) that are not itself
total_fx = total_fy = 0
for planet in planets:
if self == planet:
continue
fx, fy = self.attraction(planet)
total_fx += fx
total_fy += fy
# Solve for x and y velocities
self.x_vel += total_fx / self.mass * self.TIMESTEP
self.y_vel += total_fy / self.mass * self.TIMESTEP
# Update x and y positions by using velocities
self.x += self.x_vel * self.TIMESTEP
self.y += self.y_vel * self.TIMESTEP
# Append the positions so we can draw the orbit
self.orbit.append((self.x, self.y))
# Event loop for planet sim
def main():
run = True
# regulate frame rate
clock = pygame.time.Clock()
# Suns position, size, color, mass in KG
sun = Planet(0, 0, 30, YELLOW, 1.98892 * 10**30)
sun.sun = True
earth = Planet(-1 * Planet.AU, 0, 16, BLUE, 5.9742 * 10 ** 24)
earth.y_vel = 29.783 * 1000
mars = Planet(-1.524 * Planet.AU, 0, 12, RED, 6.38 * 10 ** 23)
mars.y_vel = 24.077 * 1000
mercury = Planet(0.387 * Planet.AU, 0, 8, DARK_GREY, 3.30 * 10 ** 23)
mercury.y_vel = -47.4 * 1000
venus = Planet(0.723 * Planet.AU, 0, 14, WHITE, 4.8685 * 10 ** 24)
venus.y_vel = -35.02 * 1000
planets = [sun, earth, mars, mercury, venus]
while run:
clock.tick(60)
WIN.fill((0, 0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
for planet in planets:
planet.update_position(planets)
planet.draw(WIN)
pygame.display.update()
pygame.quit()
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment