A deterministic pure-Python 2D and 3D rigid-body physics engine.
Project description
pyphysics
pyphysics is a pure-Python rigid-body physics engine with deterministic 2D and
3D simulation APIs. It is built for games, prototypes, education, robotics
experiments, and simulation tools that need a readable engine core without
runtime dependencies.
PyPI name note: the
pyphysicsdistribution name is already owned on PyPI by another project. This package can still be installed locally aspyphysics, but publishing it sopip install pyphysicsresolves to this library requires ownership or maintainer access to that existing PyPI project.
Highlights
- 2D rigid bodies: dynamic, static, and kinematic
- 3D rigid bodies: dynamic, static, and kinematic
- 2D shapes:
Circle,Box,ConvexPolygon - 3D shapes:
Sphere,Box3D,ConvexPolyhedron - SAT-based convex polygon and polyhedron collision
- Impulse collision response with restitution and friction
- Gravity, force accumulation, persistent acceleration, and damping
- Distance joints for 2D constraints
- Sensors, contact callbacks, collision categories, and collision masks
- Ray casting and AABB queries in 2D and 3D
PhysicsClockfor fixed timesteps, scaled time, frame count, and accumulation- Continuous substepping for fast-moving bodies
- No runtime dependencies
Installation
For local development:
python -m pip install -e .
When published under an available PyPI distribution name:
python -m pip install <distribution-name>
The import package is always:
import pyphysics
2D Quick Start
from pyphysics import Body, Box, Circle, Vec2, World
world = World(gravity=Vec2(0, -9.81))
world.add(Body.static(position=Vec2(0, -2), shape=Box(20, 1)))
ball = world.add(
Body.dynamic(
position=Vec2(0, 5),
shape=Circle(0.5),
mass=1.0,
restitution=0.55,
)
)
for _ in range(120):
world.step(1 / 60)
print(ball.position)
3D Quick Start
from pyphysics import Body3D, Box3D, Sphere, Vec3, World3D
world = World3D(gravity=Vec3(0, -9.81, 0))
world.add(Body3D.static(position=Vec3(0, -2, 0), shape=Box3D(20, 1, 20)))
ball = world.add(
Body3D.dynamic(
position=Vec3(0, 5, 0),
shape=Sphere(0.5),
mass=1.0,
restitution=0.55,
)
)
for _ in range(120):
world.step(1 / 60)
print(ball.position)
Convex Shapes
from pyphysics import Body, ConvexPolygon, ConvexPolyhedron, Vec2, Vec3, World, World3D
world2 = World(gravity=Vec2())
ship = world2.add(
Body.dynamic(
shape=ConvexPolygon.regular(5, 1.0),
mass=2,
acceleration=Vec2(15, 0),
)
)
world3 = World3D(gravity=Vec3())
rock = world3.add(
Body.dynamic(
shape=ConvexPolyhedron.tetrahedron(1.0),
mass=1,
acceleration=Vec3(0, 0, 8),
)
)
Time And Continuity
PhysicsClock gives the world a single place for fixed timestep state, frame
count, elapsed simulation time, and time scaling.
from pyphysics import PhysicsClock, Vec2, World
world = World(
gravity=Vec2(),
clock=PhysicsClock(fixed_dt=1 / 120, time_scale=1.0),
max_translation_per_step=0.25,
)
for stats in world.tick(elapsed=1 / 60):
print(stats.frame, stats.time, stats.substeps)
Fast bodies are automatically split into substeps when continuous=True:
world = World(gravity=Vec2(), continuous=True, max_translation_per_step=0.25)
Sensors And Contact Events
from pyphysics import Body, Box, Circle, Vec2, World
world = World(gravity=Vec2())
trigger = world.add(Body.static(shape=Box(3, 3), sensor=True, name="trigger"))
player = world.add(Body.dynamic(shape=Circle(0.5), position=Vec2(), mass=1, name="player"))
world.on_begin_contact = lambda contact: print(contact.a.name, contact.b.name)
stats = world.step(1 / 60)
assert stats.sensor_contacts == 1
Examples
python examples/basic_scene.py
python examples/basic_scene_3d.py
Development
Run tests:
python -m unittest discover -s tests -v
Build distributions:
python -m build
Check distributions before upload:
python -m twine check dist/*
Upload to PyPI, only after choosing an available distribution name and creating a PyPI API token:
python -m twine upload dist/*
Package Status
This repository currently provides the import package pyphysics. The desired
PyPI command pip install pyphysics cannot point to this project unless the
existing PyPI owner grants access or transfers the name. A practical publishing
path is to keep the import name pyphysics and publish under a new distribution
name such as pyphysics-engine, then users would install it with:
python -m pip install pyphysics-engine
and import it with:
import pyphysics
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file newtonian_physics-0.2.0.tar.gz.
File metadata
- Download URL: newtonian_physics-0.2.0.tar.gz
- Upload date:
- Size: 19.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
044a71088931f5bfb048151d34c7c2e348d41b51fd8c2f3156c352e3777ae2b3
|
|
| MD5 |
c6282df783d192b7bb5a1631a5feeade
|
|
| BLAKE2b-256 |
de2ece0c8e49c2ca07e38554aa6e8179761a77ed28d819274030a3030b8849f6
|
File details
Details for the file newtonian_physics-0.2.0-py3-none-any.whl.
File metadata
- Download URL: newtonian_physics-0.2.0-py3-none-any.whl
- Upload date:
- Size: 26.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9384bdc3dd1e6039a040810145edc261405a0be73b5bc25202c96554143e6c32
|
|
| MD5 |
3ee3c989c0d4fce74075a3ef65a88e27
|
|
| BLAKE2b-256 |
fbe89213a279f6c83d1e5489de310feefdf135dd09801d35cd5809933446ad6b
|