I've written a tutorial in the past about the python package called box2d,
see this tutorial.
Today I will be more precise and I will show you a source code related to 2D simulation.
I installed the python package in the Fedora 35 Linux distribution with the DNF tool:
[root@fedora mythcat]# dnf search pybox2d
...
python3-pybox2d.x86_64 : A 2D rigid body simulation library for Python
[root@fedora mythcat]# dnf install python3-pybox2d.x86_64
Last metadata expiration check: 0:18:37 ago on Sun 16 Jan 2022 10:15:43 AM EET.
Dependencies resolved.
...
Installed:
python3-pybox2d-2.3.2-17.fc35.x86_64
Complete!
I created the working folders and the first python file named example001.py:
[mythcat@fedora ~]$ mkdir PyGameProjects
[mythcat@fedora ~]$ cd PyGameProjects/
[mythcat@fedora PyGameProjects]$ touch example001.py
[mythcat@fedora PyGameProjects]$ vi example001.py
It contains a default source code:
from Box2D import (b2PolygonShape, b2World)
# create word
world = b2World()
# set the world
groundBody = world.CreateStaticBody(position=(0, -10),
shapes=b2PolygonShape(box=(50, 10)),
)
# create a dynamic body at position
body = world.CreateDynamicBody(position=(0, 4))
# add and set a box fixture onto it with a nonzero density, so it will move
box = body.CreatePolygonFixture(box=(1, 1), density=1, friction=0.3)
# use a time step of 1/60 of a second
timeStep = 1.0 / 60
# simulation scenario with 6 velocity/2 position iterations
vel_iters, pos_iters = 6, 2
# the game loop.
for i in range(60):
# use step of simulation
world.Step(timeStep, vel_iters, pos_iters)
# clear body forces even I didn't apply any forces
world.ClearForces()
# print the position and angle of the body.
print(body.position, body.angle)
The result of the run looks like this:
...
b2Vec2(1.8719e-08,1.01496) 6.208252216310939e-06
b2Vec2(1.90152e-08,1.01497) 4.9494738050270826e-06
For a more complex example we created two python files.
One is a class for a box and a file that calls the class.
The first file contains the following source code is named box.py:
import pygame
from Box2D import (b2EdgeShape, b2FixtureDef, b2PolygonShape, b2_dynamicBody,
b2_kinematicBody, b2_staticBody, b2World)
class Box:
def __init__(self, x, y, l, world):
self.x = x / l
self.y = y / l
self.w = .2
self.h = .2
self.world = world
self.attachment = self.world.CreateDynamicBody(
position=(self.x, self.y),
fixtures=b2FixtureDef(
shape=b2PolygonShape(box=(self.w, self.h)), density=0.4, friction = 0.4),)
def display(self, screen):
for body in self.world.bodies:
for fixture in body.fixtures:
shape = fixture.shape
vertices = [(body.transform * v) * 20 for v in shape.vertices]
pygame.draw.polygon(screen, 'azure', vertices)
pygame.draw.polygon(screen, 'blue', vertices,width=3)
The file calling the class has the following source code:
import pygame
from box import Box
from Box2D import b2World
l = 20
fps = 60
frame_rate = 1.0 / fps
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Physics")
clock = pygame.time.Clock()
# A list for all of our rectangles
list_boxes = []
world = b2World(gravity=(0, 9.8), doSleep=False)
close = False
while not close:
for event in pygame.event.get():
if event.type == pygame.QUIT:
close = True
screen.fill('white')
click, _, _ = pygame.mouse.get_pressed()
if click == 1:
x,y = pygame.mouse.get_pos()
box = Box(x, y, l, world)
list_boxes.append(box)
for box in list_boxes:
box.display(screen)
world.Step(frame_rate, 10, 10)
pygame.display.flip()
clock.tick(fps)
pygame.quit()
The result of running this file looks like this screenshot with some squares moving to the bottom: