Metadata-Version: 2.4
Name: newtonian-physics
Version: 0.2.0
Summary: A deterministic pure-Python 2D and 3D rigid-body physics engine.
Author: UeCollaxion-
License: MIT
Project-URL: Homepage, https://github.com/yourusername/newtonian-physics
Project-URL: Repository, https://github.com/yourusername/newtonian-physics
Project-URL: Issues, https://github.com/yourusername/newtonian-physics/issues
Keywords: physics,simulation,rigid-body,collision,2d,3d,game-engine
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Education
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Physics
Classifier: Topic :: Games/Entertainment :: Simulation
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# 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 `pyphysics` distribution name is already owned on PyPI by
> another project. This package can still be installed locally as `pyphysics`,
> but publishing it so `pip install pyphysics` resolves 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
- `PhysicsClock` for fixed timesteps, scaled time, frame count, and accumulation
- Continuous substepping for fast-moving bodies
- No runtime dependencies

## Installation

For local development:

```powershell
python -m pip install -e .
```

When published under an available PyPI distribution name:

```powershell
python -m pip install <distribution-name>
```

The import package is always:

```python
import pyphysics
```

## 2D Quick Start

```python
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

```python
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

```python
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.

```python
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`:

```python
world = World(gravity=Vec2(), continuous=True, max_translation_per_step=0.25)
```

## Sensors And Contact Events

```python
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

```powershell
python examples/basic_scene.py
python examples/basic_scene_3d.py
```

## Development

Run tests:

```powershell
python -m unittest discover -s tests -v
```

Build distributions:

```powershell
python -m build
```

Check distributions before upload:

```powershell
python -m twine check dist/*
```

Upload to PyPI, only after choosing an available distribution name and creating
a PyPI API token:

```powershell
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:

```powershell
python -m pip install pyphysics-engine
```

and import it with:

```python
import pyphysics
```
