Physics in Python with

Physics. Someone loves her, some do not, but it is definitely an integral part of our existence. In this article, we will look at how to create physics simulations ourselves using only 2 Python libraries.

By the end of the article, we will make an interactive simulation of the interaction of bodies and understand the basics of the library. Pymunk.

My terminology:

Section – a piece of code that I mark with a comment to describe it in the article
(Not used as a term, but it’s easier for me to explain to you)


Let’s get ready to get started

And so, let’s create a new Python file in an IDE that is convenient for you

Now we need to install Pymunk and Pygame… And also set them up for collaboration.
Don’t forget to install them in the project console via the command pip install

Here is the code:

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

PyGame coordinate system is different from PyMunk coordinate system, we need to fit them to the same coordinate system

Pygame
Pygame
PyMunk
PyMunk

Let’s add code to “import modules” to fix this

pymunk.pygame_util.positive_y_is_up = False

Hooray, we adjusted the coordinate system and now our libraries can work with each other.

Rendering in Pygame

To visualize our simulation, we will use a simple code.

Let’s set the screen resolution and the number of 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 and HEIGHT are Pygame window resolution options.

FPS is the number of frames rendered per second (60 is considered the standard)

Now let’s create a render class. It will always be at the very end of the code.

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)

The code looks like this at the moment:

#имопрт модулей
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)

Finally we can see what comes out.

Our window is ready to create a simulation.

Create Space

But first, let’s understand the basic concepts of the PyMunk library.

First we need to create space
Space is the basic unit of PyMunk modeling. You add solids, shapes, and joints to it, and then move them forward together in time.

Create a new comment “PyMunk Variables” which will be after our section “PyGame Settings” and create space there

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

There is space, it’s time to create gravity.

space.gravity = 0, 8000

Our PyMunk Variables section now looks like this:

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

After adding the required variables, it is important to do the following:

Let’s add a couple of lines to render to draw our bodies created in 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)

The code looks like this at the moment:

#импорт модулей:
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)

Create physical bodies

V PyMunk there are 3 types of physical objects: Dynamic, Static and Kinematic

Dynamic (Dynamic) – Objects react to collisions, they are affected by forces and gravity, they have a finite mass.
Dynamic bodies interact with all types of bodies.

Kinematic (Kinematic) – These are objects that are managed from your code, not inside a physics engine. They are not affected by gravity. Good examples of kinematic bodies: flying platforms in games

Static (Static) – Bodies that never move, but can interact with other bodies.
Walls and floors in games are a good example.

Let’s create a Static Platform:

We write the following code after the “Pymunk settings” section

#платформа
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 (object names separated by commas) – adds objects to space

segment_shape.elasticity – Coefficient of elasticity

segment_shape.friction – Coefficient of friction

This gray stripe is our first physical object, it turned out to be easy to do this.
Let’s consider it as a simulation floor.

Interactive squares and their interaction

You have reached the key section of the article, congratulations!
Now we will figure out how to create dynamic bodies and how to make the right interaction for them.

Idea:
By clicking on the screen, the program will spawn squares that yield to the laws of physics.

Let’s get down to implementation:

#квадратики
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автоматически рассчитываем момент инерции для полого круга зная массу и размер

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

Time for the first feature: Let’s make the squares appear in the place where the cursor is

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

Feature number two: the color of the cubes will be random.
You can do it like this:

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

Finally, we add the function, in the end it looks like this:

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)

remind that space.add adds body to space

We are on the home stretch! All that’s left is to update the rendering.

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

As a result, rendering looks like this:

#Отрисовка
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')

Checking

I think it turned out great 🙂

Result
Result

All source code:

#импорт модулей:
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')

Outcome

We have created a small program in PyGame and PyMunk with physics simulation.

Then you can study the documentation, articles and videos from youtube yourself.
But I’m not going to end up with one article on this topic either.

Before communication)

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

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *