Created
April 25, 2023 17:33
-
-
Save jcayouette/1063bb4c5658756c271c5f6c6f9184d3 to your computer and use it in GitHub Desktop.
Planetary orbits using newtonian physics in pygame
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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