Pyhsics Engine is a compact interactive physics playground where rectangular bodies fall, collide, bounce, and respond to mouse dragging. It is built around a simple but real physics loop: forces change acceleration, acceleration changes velocity, velocity changes position, and collisions are solved with AABB overlap checks plus impulse response.
The project is small enough to understand in one sitting, but it already includes the foundations of a real 2D simulation engine:
| Layer | What it does |
|---|---|
app.py |
Runs the Pygame window, event loop, panels, buttons, and object creation flow. |
source.py |
Defines UI widgets, physics bodies, world simulation, collisions, dragging, rendering, and SQLite persistence. |
database/data.db |
Stores user-created objects so they can load again on startup. |
window.png |
Visual panel asset used by the slide-out menu. |
| Feature | Description |
|---|---|
| Gravity | Every dynamic body receives downward force each frame. |
| Dynamic bodies | Moving rectangles have mass, velocity, acceleration, restitution, color, and name. |
| Static bodies | Floor, ceiling, and walls stay fixed while still colliding with objects. |
| AABB collisions | Rectangle overlap is detected on the X and Y axes. |
| Impulse response | Objects bounce using relative velocity, inverse mass, and restitution. |
| Mouse dragging | Dragged objects follow the cursor using a spring-like force. |
| Object inspector | Right-click an object to view its name, mass, and color. |
| Add-object panel | Create objects from the in-app menu using name, mass, and Pygame color. |
| SQLite save/load | Newly added objects are written to database/data.db. |
app.py
|-- initializes Pygame and the 1280x720 window
|-- creates starter dynamic bodies and static boundaries
|-- owns the main event loop
|-- handles mouse input, keyboard input, buttons, and side-panel state
|-- creates new objects from text fields
|-- calls world.update(dt)
|-- calls world.render()
`-- calls world.write() to persist newly created objects
source.py
|-- Button
| `-- small hover/click UI helper
|
|-- textzone
| `-- focused text input field for name, mass, and color
|
|-- object
| |-- stores body position, size, mass, velocity, acceleration, color, and flags
| |-- applies forces
| |-- applies impulses
| |-- integrates motion
| `-- renders itself as a Pygame rectangle
|
`-- world
|-- stores every body in the simulation
|-- applies gravity
|-- applies drag forces
|-- detects AABB overlaps
|-- resolves collisions with impulses
|-- handles picking, releasing, and inspection
`-- loads/saves user-created objects through SQLite
The project is split cleanly between orchestration and simulation. app.py decides what happens each frame; source.py defines the reusable pieces that make the world behave.
Pygame Events
|
v
Input + UI Handling
|
v
Apply Forces -> Integrate Motion -> Detect Collisions -> Resolve Impulses
|
v
Render World + Slide-out Panel
|
v
Persist New Objects
The simulation is intentionally clear and direct.
Dynamic objects receive forces, convert them into acceleration, then update velocity and position using delta time:
self.vx += dt * self.ax
self.vy += dt * self.ay
self.x += dt * self.vx
self.y += dt * self.vyCollisions are detected by checking rectangle overlap:
overlap_x = min(a.right, b.right) - max(a.left, b.left)
overlap_y = min(a.bottom, b.bottom) - max(a.top, b.top)
The smallest overlap axis becomes the collision normal.
When two bodies move toward each other, the engine computes an impulse using:
- Relative velocity
- Collision normal
- Inverse mass
- Restitution
That impulse changes each body's velocity, producing a bounce.
| Action | Control |
|---|---|
| Drag a dynamic object | Left mouse button |
| Release dragged object | Release left mouse button |
| Inspect an object | Right mouse button |
| Open add-object menu | menu button |
| Close side panel | X button |
| Type into a field | Click field, then type |
| Delete text | Backspace |
Open the menu and enter:
| Field | Example | Notes |
|---|---|---|
name |
box01 |
Short object label. |
mass |
1200 |
Must be an integer. |
color |
yellow |
Must be a valid Pygame color name. |
Valid color examples:
red
blue
green
yellow
purple
orange
white
black
When added, the object is inserted into the running world and saved into SQLite.
cd /home/bro/my-creations/pyhsics-enginepython3 -m venv .venv
source .venv/bin/activaterequirements.txt is currently empty, but the app imports pygame and numpy.
pip install pygame numpypython app.pypyhsics-engine/
|-- app.py # Main app, event loop, starter objects, menu flow
|-- source.py # Button, textzone, object, world, physics, SQLite
|-- window.png # Slide-out side panel image
|-- database/
| `-- data.db # SQLite database containing saved objects
|-- objects.db # Empty database file, currently unused
|-- requirements.txt # Placeholder dependency file
`-- README.md # This documentation
The active database is:
database/data.db
It contains:
CREATE TABLE "objects" (
"name" TEXT NOT NULL,
"mass" INTEGER NOT NULL,
"color" TEXT NOT NULL
);At startup, saved rows are loaded as dynamic objects. During runtime, newly created objects are inserted into the table.
This is a learning-focused engine, so the simple design is part of the point.
| Limit | Why it matters |
|---|---|
| Rectangles only | No circles, polygons, or rotated bodies yet. |
| Pairwise collision checks | Works fine for small scenes, but not optimized for many objects. |
| Friction not fully solved | Objects store friction, but contact friction is not yet part of impulse resolution. |
| Absolute database path | source.py currently opens the database with a machine-specific path. |
| Empty requirements file | Dependencies should be added before sharing. |
Class named object |
Works, but shadows Python's built-in object type. |
- Add circle bodies.
- Add rotated rectangles or polygon collision.
- Add friction impulses.
- Add pause, reset, and clear-world buttons.
- Add object editing and deletion.
- Move the database path to a project-relative path.
- Fill
requirements.txt. - Add broad-phase collision detection.
- Add tests for collisions and database persistence.
- Rename
objecttoPhysicsBody.
wanted to try somehting that allows me to use both my physics knowledge and coding skills
not yet