Физика в Python с использованием Pymunk

от автора

Физика. Кто-то её любит, кто-то нет, но определённо это неотъемлемая часть нашего существования. В этой статье мы рассмотрим как самому создавать физические симуляции используя всего 2 библиотеки Python.

К концу статьи мы сделаем интерактивную симуляцию взаимодействия тел и поймём основы использования библиотеки Pymunk.

Моя терминология:

Раздел — кусок кода который я помечаю комментарием, чтобы описать это в статье
(В качестве термина не используется, но мне так проще вам объяснить)


Подготовимся для начала работы

И так, создадим новый файл Python в удобной для вас IDE

Теперь нам нужно установить Pymunk и Pygame. А так же настроить их для совместной работы.
Не забудьте установить их в консоли проекта через команду pip install

Вот код:

#импорт модулей import pygame as pg import pymunk.pygame_util

Система координат PyGame отличается от системы координат PyMunk, нам нужно подогнать их под одну систему координат

PyGame
PyGame
PyMunk
PyMunk

Добавим код в «импорт модулей» для исправления этого

pymunk.pygame_util.positive_y_is_up = False

Ура, мы подогнали систему координат и теперь наши библиотеки могут работать друг с другом.

Отрисовка в Pygame

Чтобы визуализировать нашу симуляцию мы будем использовать не сложный код

Зададим разрешение экрана и количество FPS.

#Настройки PyGame RES = WIDTH, HEIGHT = 900, 720 FPS = 60  pg.init() surface = pg.display.set_mode(RES) clock = pg.time.Clock() draw_options = pymunk.pygame_util.DrawOptions(surface)

WIDTH и HEIGHT это параметры разрешения окна Pygame.

FPS — это количество кадров обрисовываемые в секунду (стандартом считается 60)

Теперь создадим цикл отрисовки. Он будет всегда находиться в самом конце кода.

while True:     surface.fill(pg.Color('black'))      for i in pg.event.get():         if i.type == pg.QUIT:             exit()     pg.display.flip()     clock.tick(FPS)

Код на данный момент выглядит так:

#имопрт модулей import pygame as pg import pymunk.pygame_util pymunk.pygame_util.positive_y_is_up = False  #Настройки PyGame RES = WIDTH, HEIGHT = 900, 720 FPS = 60  pg.init() surface = pg.display.set_mode(RES) clock = pg.time.Clock() draw_options = pymunk.pygame_util.DrawOptions(surface)  #Отрисовка PyGame while True:     surface.fill(pg.Color('black'))      for i in pg.event.get():         if i.type == pg.QUIT:             exit()                  pg.display.flip()     clock.tick(FPS)

Наконец мы можем посмотреть что выходит.

Наше окно готово к созданию симуляции.

Создаём Пространство

Но для начала разберёмся с основными понятиями библиотеки PyMunk.

Для начала нам нужно создать пространство (space)
Space — основная единица моделирования PyMunk. Вы добавляете к нему твердые тела, формы и суставы, а затем продвигаете их вперед вместе во времени.

Создаём новый комментарий «Переменные PyMunk» который будет находиться после нашего раздела «Настройки PyGame» и создаём там space

#переменные Pymunk space = pymunk.Space()

Пространство есть, пора создать гравитацию.

space.gravity = 0, 8000

Теперь наш раздел «Переменные PyMunk» выглядит так:

#настройки Pymunk space = pymunk.Space() space.gravity = 0, 8000

После добавления нужных переменных важно сделать следующее:

Добавим пару строк в отрисовку чтобы она рисовала наши тела созданные в PyMunk:

#Отрисовка while True:     surface.fill(pg.Color('black'))      for i in pg.event.get():         if i.type == pg.QUIT:             exit() #Мы добавили вот эти 2 строки:     space.step(1 / FPS)     space.debug_draw(draw_options)      pg.display.flip()     clock.tick(FPS)

Код на данный момент выглядит так:

#импорт модулей: import pygame as pg from random import randrange import pymunk.pygame_util pymunk.pygame_util.positive_y_is_up = False  #параметры PyGame RES = WIDTH, HEIGHT = 900, 720 FPS = 60  pg.init() surface = pg.display.set_mode(RES) clock = pg.time.Clock() draw_options = pymunk.pygame_util.DrawOptions(surface)  #настройки Pymunk space = pymunk.Space() space.gravity = 0, 8000  #Отрисовка while True:     surface.fill(pg.Color('black'))      for i in pg.event.get():         if i.type == pg.QUIT:             exit()      space.step(1 / FPS)     space.debug_draw(draw_options)      pg.display.flip()     clock.tick(FPS)

Создаём физические тела

В PyMunk есть 3 типа физических объектов: Динамические, Статические и Кинематические

Динамические (Dynamic) — Объекты реагируют на столкновения, на них действуют силы и гравитация, они имеют конечную массу.
Динамические тела взаимодействуют со всеми типами тел.

Кинематические (Kinematic) — Это объекты, которые управляются из вашего кода, а не внутри физического движка. На них не действует гравитация. Хорошие примеры кинематических тел: летающие платформы в играх

Статические (Static) — Тела которые никогда не двигаются, но могут взаимодействовать с другими телами.
Хороший пример — стены и полы в играх.

Создадим Статическую платформу:

Пишем вот такой код после раздела «настройки Pymunk»

#платформа segment_shape = pymunk.Segment(space.static_body, (1, HEIGHT), (WIDTH, HEIGHT), 26) space.add(segment_shape) segment_shape.elasticity = 0.4 segment_shape.friction = 1.0

space.add(названия объектов через запятую) — добавляет объекты в пространство

segment_shape.elasticity — Коэффициент упругости

segment_shape.friction — Коэффициент трения

Эта серая полоска — наш первый физический объект, оказалось сделать такое несложно.
Будем считать её полом для симуляции.

Интерактивные квадраты и их взаимодействие

Вы добрались до ключевого раздела статьи, поздравляю!
Сейчас мы разберёмся как создавать динамические тела и как сделать для них правильное взаимодействие.

Идея:
Кликая на экран программа будет добавлять новые квадраты поддающиеся законам физики.

Приступаем к реализации:

#квадратики def create_square(space, pos):     square_mass, square_size = 1, (60, 60)     square_moment = pymunk.moment_for_box(square_mass, square_size)     square_body = pymunk.Body(square_mass, square_moment)

square_mass - масса квадрата (в наше случае равняется одному)

square_size - размер квадрата. Передаётся в формате (width, height)

square_moment = pymunk.moment_for_boxавтоматически рассчитываем момент инерции для box зная массу и размер

quare_body = pymunk.Bodyэкземпляр тела

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

def create_square(space, pos):     square_mass, square_size = 1, (60, 60)     square_moment = pymunk.moment_for_box(square_mass, square_size)     square_body = pymunk.Body(square_mass, square_moment)     # появление на позиции курсора     square_body.position = pos

square_body.position - позиция тела

def create_square(space, pos):     square_mass, square_size = 1, (60, 60)     square_moment = pymunk.moment_for_box(square_mass, square_size)     square_body = pymunk.Body(square_mass, square_moment)     square_body.position = pos     square_shape = pymunk.Poly.create_box(square_body, square_size)     square_shape.elasticity = 0.8     square_shape.friction = 1.0

Фича под номером два: цвет кубиков будет рандомен.
Сделать это можно так:

square_shape.color = [randrange(256) for i in range(4)]

Наконец дописываем функцию, в итоге она выглядит так:

def create_square(space, pos):     square_mass, square_size = 1, (60, 60)     square_moment = pymunk.moment_for_box(square_mass, square_size)     square_body = pymunk.Body(square_mass, square_moment)     square_body.position = pos     square_shape = pymunk.Poly.create_box(square_body, square_size)     square_shape.elasticity = 0.8     square_shape.friction = 1.0     square_shape.color = [randrange(256) for i in range(4)]     space.add(square_body, square_shape)

напоминаю что space.add добавляет тело в пространств

Мы на финишной прямой! Осталось только обновить отрисовку.

# спавн кубиков         if i.type == pg.MOUSEBUTTONDOWN:             if i.button == 1:                 create_square(space, i.pos)                 print(i.pos)

В итоге отрисовка выглядит так:

#Отрисовка while True:     surface.fill(pg.Color('black'))      for i in pg.event.get():         if i.type == pg.QUIT:             exit()         # спавн мячиков         if i.type == pg.MOUSEBUTTONDOWN:             if i.button == 1:                 create_square(space, i.pos)                 print(i.pos)      space.step(1 / FPS)     space.debug_draw(draw_options)      pg.display.flip()     clock.tick(FPS)  print('end')

Проверяем

Считаю что получилось отлично 🙂

Результат
Результат

Весь исходный код:

#импорт модулей: import pygame as pg from random import randrange import pymunk.pygame_util pymunk.pygame_util.positive_y_is_up = False  #параметры PyGame RES = WIDTH, HEIGHT = 900, 720 FPS = 60  pg.init() surface = pg.display.set_mode(RES) clock = pg.time.Clock() draw_options = pymunk.pygame_util.DrawOptions(surface)  #настройки Pymunk space = pymunk.Space() space.gravity = 0, 8000  #платформа segment_shape = pymunk.Segment(space.static_body, (2, HEIGHT), (WIDTH, HEIGHT), 26) space.add(segment_shape) segment_shape.elasticity = 0.8 segment_shape.friction = 1.0    #квадратики body = pymunk.Body() def create_square(space, pos):     square_mass, square_size = 1, (60, 60)     square_moment = pymunk.moment_for_box(square_mass, square_size)     square_body = pymunk.Body(square_mass, square_moment)     square_body.position = pos     square_shape = pymunk.Poly.create_box(square_body, square_size)     square_shape.elasticity = 0.4     square_shape.friction = 1.0     square_shape.color = [randrange(256) for i in range(4)]     space.add(square_body, square_shape)   #Отрисовка while True:     surface.fill(pg.Color('black'))      for i in pg.event.get():         if i.type == pg.QUIT:             exit()         # спавн кубиков         if i.type == pg.MOUSEBUTTONDOWN:             if i.button == 1:                 create_square(space, i.pos)                 print(i.pos)      space.step(1 / FPS)     space.debug_draw(draw_options)      pg.display.flip()     clock.tick(FPS)  print('end') 

Итог

Мы создали небольшую программу на PyGame и PyMunk с симуляцией физики.

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

До связи)

Материалы: Standalone Coder, форумы, официальная документация.


ссылка на оригинал статьи https://habr.com/ru/articles/593547/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *