Создаем симулятор солнечной системы

в 8:34, , рубрики: game development, python, simulation, tutorial, метки: ,

Предисловие
Вечная тяга к новому подтолкнула к изучению такого замечательного языка программирования, как Питон. Как это часто бывает, отсутствие идеи, на реализацию которой не жалко потратить свое время, сильно тормозило процесс.

Волею судьбы на глаза попался замечательный цикл статей о создании игры-платформера на Питоне
тут и тут.
Я решил взяться за один старый проект. За симулятор движения тел под действием сил гравитации.

Что из этого вышло читайте дальше.

Часть первая. Теоритическая

Чтобы решить задачу, нужно сначала четко себе ее представить.
Предположим, всеми правдами и неправдами нам удалось заполучить двумерный участок безвоздушного пространства с находящимися в нем телами. Все тела перемещаются под действием сил гравитации. Внешнего воздействия нет.
Нужно построить процесс их движения относительно друг друга. Простота реализации и красочность конечного результата послужат стимулом и наградой. Освоение Питона будет хорошей инвестицией в будущее.

Введем систему координат.

Пускай наша система состоит из двух тел:
1. массивной звезды массой М и центром (x0, y0)
2. легкой планеты массой m, с центром в точке (x, y), скоростью v = (vx, vy) и ускорением a = (ax, ay).

Когда нам удастся разобрать этот случай, мы легко перейдем к сложным системам со взаимным влиянием звезд и планет друг на друга. Сейчас же речь пойдет о самом простом.

После несложных манипуляций со вторым законом Ньютона, законом всемирного тяготения и подобными треугольниками, я нашел, что:

ax = G * M * (x0-x) / r^3
ay = G * M * (y0-y) / r^3

Это позволяет составить алгоритм перемещения планеты в поле гравитации звезды:

1. Перед началом задаем начальное положение планеты (x, y) и начальную скорость (vx, vy)
2. На каждом шаге вычисляем новое ускорение по формуле выше, после этого пересчитываем скорость и координаты:

vx := vx + T * ax
vy := vy + T * ax

x := x + T * vx
y := y + T * yx

Осталось разобраться с константами G и T. Положим G = 1. Для нашей задачи это не так важно. Параметр T влияет на точность и скорость вычислений. Тоже положим 1 для начала.

Часть вторая. Практическая

Итак, моя первая программа на Питоне. При этом еще раз хочется поблагодарить Velese за практическое руководство.

import pygame, math
from pygame import *
from math import *

WIN_WIDTH = 800
WIN_HEIGHT = 640
PLANET_WIDTH = 20
PLANET_HEIGHT = 20
DISPLAY = (WIN_WIDTH, WIN_HEIGHT)
SPACE_COLOR = "#000022"
SUN_COLOR = "yellow"
PLANET_COLOR = "blue"

#Sun position
X0 = WIN_WIDTH // 2
Y0 = WIN_HEIGHT // 2
#Sun mass
M0 = 5000
#Stop conditions
CRASH_DIST = 10
OUT_DIST = 1000

def main():
    #PyGame init
    pygame.init()
    screen = pygame.display.set_mode(DISPLAY)
    pygame.display.set_caption("Solar Mechanics v0.1")
    
    #Space init
    bg = Surface((WIN_WIDTH,WIN_HEIGHT))
    bg.fill(Color(SPACE_COLOR))     
    draw.circle (bg, Color(SUN_COLOR), (X0, Y0), 10)
                    
    #Timer init                     
    timer = pygame.time.Clock()
    
    #Planet init
    planet = Surface((PLANET_WIDTH, PLANET_HEIGHT))
    planet.fill(Color(SPACE_COLOR))
    draw.circle (planet,
        Color(PLANET_COLOR),
        (PLANET_WIDTH // 2, PLANET_HEIGHT // 2),
        5)

    #Planet to Sun distance
    r = 0.0
    #Initial planet pos, speed and accel
    x = 100.0
    y = 290.0
    vx = 0.1
    vy = 1.5
    ax = 0.0
    ay = 0.0

    done = False
    while not done:
        timer.tick(50)
        for e in pygame.event.get():
            if e.type == QUIT:
                done = True
                break        

        r = sqrt((x - X0)**2 + (y - Y0)**2)
        
        ax = M0 * (X0 - x) / r**3
        ay = M0 * (Y0 - y) / r**3

        #New spped based on accel
        vx += ax
        vy += ay

        #New pos based on speed
        x += vx
        y += vy

        screen.blit(bg, (0, 0))      
        screen.blit(planet, (int(x), int(y)))
        pygame.display.update()     

        if r < CRASH_DIST:
            done = True
            print("Crashed")
            break
        if r > OUT_DIST:
            done = True
            print("Out of system")
            break

    #Farewell
    print (":-)")

if __name__ == "__main__":
    main()

Так выглядит наша система после некоторого времени симуляции

Создаем симулятор солнечной системы

Пока писалась эта заметка, симулятор разросся новой функциональностью: количество объектов в звездной системе не ограничевается, учитывается взаимное их влияние друг на друга, расчетная часть вынесена в свой класс, конфигурация системы задается в отдельном файле и добавлена возможность выбора систем.

Сейчас я занимаюсь поиском интересных сценариев системы и небольшими улучшениями интерфейса.

Вот пример того, что на данный момент в разработке:
Создаем симулятор солнечной системы

Если эта заметка встретит положительные отзывы, обещаю продолжить рассказ о более новой версии.

Автор: RedTroll

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js