Files
2026-09-24 15:45:31 +02:00

6.8 KiB
Raw Permalink Blame History

Physik-Sandbox

Interaktive 2D-Physiksimulation in Python. Über eine Werkzeugleiste erzeugst du Kreise und Rechtecke unterschiedlicher Größe, greifst sie mit der Maus, ziehst sie herum und wirfst sie gegeneinander. Die Körper fallen, prallen ab, reiben, rollen, stapeln sich und kommen stabil zur Ruhe.

Die gesamte Physik ist selbst geschrieben – Vektormathematik, Integration, Kollisionserkennung und impulsbasierte Kollisionsauflösung verwenden ausschließlich das Standardmodul math. pygame-ce dient nur für Fenster, Zeichnen, Eingaben und Zeitmessung.

Demo-Szene: Ein Rechteck wird gerade geworfen, daneben Kreispyramide und Rechteckturm

Funktionen

  • Kreise und achsenparallele Rechtecke; Größe, Seitenverhältnis, Elastizität, Dichte und Farbe in der Sidebar einstellbar – die Masse ergibt sich aus Fläche × Dichte.
  • Objekte per Klick in die Welt oder per Ziehen aus der Vorschau-Kachel erzeugen.
  • Drag & Drop mit Kollisionen: Ein gezogenes Objekt schiebt andere weg und wird von Wänden gestoppt. Beim Loslassen erhält es die geglättete Mausgeschwindigkeit (Werfen).
  • Schwerkraft, Kreis–Kreis-, Kreis–Rechteck-, Rechteck–Rechteck- und Wandkollisionen, Restitution, Coulomb-Reibung, Rollen und Rollwiderstand.
  • Fester Zeitschritt (120 Hz), semi-impliziter Euler, Warm-Starting, Positionskorrektur, Schlafmodus für ruhende Körper, Geschwindigkeitsgrenze gegen Tunneln.
  • Pause, Schwerkraft an/aus, Alles löschen, Debug-Ansicht mit Kontaktpunkten.

Voraussetzungen

  • Python 3.10 oder neuer (entwickelt und getestet mit Python 3.14)
  • Windows, macOS oder Linux

Warum pygame-ce? Das Original-pygame (2.6.1) bietet keine fertigen Pakete für Python 3.14. pygame-ce ist der API-kompatible Community-Fork; im Code heißt es weiterhin import pygame.

Einrichtung

Im Projektordner eine virtuelle Umgebung anlegen und die Abhängigkeiten installieren:

python -m venv .venv

Aktivieren – unter Windows (PowerShell):

.venv\Scripts\Activate.ps1

Meldet PowerShell "Die Ausführung von Skripts ist auf diesem System deaktiviert", erlaube lokale Skripte einmalig für deinen Benutzer (danach die Aktivierung wiederholen):

Set-ExecutionPolicy -Scope CurrentUser RemoteSigned

Alternativ ohne Aktivierung: Ersetze in allen folgenden Befehlen

Befehl durch
python .venv\Scripts\python.exe
pip .venv\Scripts\python.exe -m pip
pytest .venv\Scripts\python.exe -m pytest
ruff .venv\Scripts\ruff.exe
physics-sandbox .venv\Scripts\physics-sandbox.exe

Unter macOS/Linux:

source .venv/bin/activate

Dann installieren:

pip install -r requirements.txt

requirements.txt installiert pygame-ce und das Projekt selbst im Editable-Modus (-e .). Den Befehl deshalb im Projektordner ausführen.

Starten

python -m sandbox

Weitere Möglichkeiten:

Befehl Wirkung
python -m sandbox --demo startet mit einer Beispielszene (Turm, Kreispyramide, Gummibälle)
physics-sandbox gleichwertiger Befehl, den die Installation anlegt
python -m sandbox --demo --screenshot bild.png --seconds 3 läuft 3 s, speichert ein Bildschirmfoto und beendet sich

Bedienung (Kurzfassung)

Eingabe Aktion
Linksklick ins Leere Objekt erzeugen (gedrückt halten und ziehen = sofort werfen)
Linksklick auf Objekt + Ziehen greifen und verschieben; Loslassen in Bewegung wirft es
Ziehen aus der Vorschau-Kachel neues Objekt aus der Sidebar in die Welt ziehen
Rechtsklick / Entf Objekt unter der Maus löschen
Mausrad Größe ändern (über einem Regler: diesen Regler verstellen)
Leertaste · G · C Pause/Weiter · Schwerkraft an/aus · Alles löschen
1 · 2 Kreis · Rechteck
F1 · Esc Debug-Ansicht · Beenden

Alle Details: docs/CONTROLS.md.

Entwicklung

Entwicklungswerkzeuge (pytest, pytest-cov, ruff) installieren:

pip install -r requirements-dev.txt

Tests ausführen (inklusive Headless-UI-Tests – es öffnet sich kein Fenster):

pytest

Mit Testabdeckung:

pytest --cov=sandbox --cov-report=term-missing

Code prüfen und formatieren:

ruff check src tests
ruff format src tests

Details zu den Tests: docs/TESTING.md.

Projektstruktur

├── src/sandbox/
│   ├── main.py            Einstiegspunkt, App und Game-Loop
│   ├── config.py          alle Konstanten (Physik, Interaktion, Farben, Layout)
│   ├── physics/           eigene Physik-Engine – nur `math`, kein pygame
│   │   ├── vector.py      Vector2
│   │   ├── shapes.py      Circle, Box (AABB), HalfPlane (Wände)
│   │   ├── body.py        Body, Material
│   │   ├── collision.py   Kollisionserkennung (Narrowphase)
│   │   ├── broadphase.py  Sweep-and-Prune
│   │   ├── solver.py      Impulsauflösung, Reibung, Rollwiderstand, Positionskorrektur
│   │   ├── sleep.py       Schlafmodus (Kontakt-Inseln)
│   │   ├── timestep.py    fester Zeitschritt
│   │   └── world.py       Welt und Simulationsschritt
│   ├── interaction/       Werkzeuge ohne pygame: Erzeugen, Ziehen, Werfen
│   ├── ui/                Sidebar und selbst gezeichnete Widgets
│   ├── input_handler.py   Maus und Tastatur → Aktionen
│   ├── renderer.py        Zeichnen der Welt
│   ├── viewport.py        Bildschirm ↔ Welt
│   └── demo.py            Beispielszene
├── tests/                 pytest-Suite (Physik, Interaktion, Headless-UI, Smoke-Test)
├── docs/                  Dokumentation
├── requirements.txt       Laufzeit-Abhängigkeiten
├── requirements-dev.txt   Test- und Linting-Werkzeuge
└── pyproject.toml         Paket-, ruff- und pytest-Konfiguration

Dokumentation

Screenshots

Demo-Szene mit gerade geworfenem Rechteck (gelb umrandet, der Pfeil zeigt die Wurfgeschwindigkeit):

Demo-Szene

Debug-Ansicht (F1): Kontaktpunkte (gelb), Kontaktnormalen (rot) und Kennzahlen:

Debug-Ansicht

Ein aktuelles Bild der Demo-Szene erzeugst du jederzeit mit python -m sandbox --demo --screenshot docs/images/demo.png.