007 - Physics System
Das Physics System bietet Verlet-basierte Physik-Simulation.
Warum Physik in Creative Coding?
Physik macht generative Kunst lebendig. Ein Partikel, das der Schwerkraft folgt, wirkt natürlicher als einer, der linear fliegt. Ein Schwarm, dessen Individuen aufeinander reagieren, erzeugt emergente Muster, die man nicht hätte programmieren können.
Warum Verlet?
Es gibt viele Physik-Ansätze. Ich nutze Verlet-Integration, weil sie:
- Stabil ist – Auch bei großen Zeitschritten explodiert nichts
- Einfach ist – Position + vorherige Position = Geschwindigkeit (implizit)
- Constraint-freundlich ist – "Diese zwei Punkte sollen Abstand X haben" → einfach Positionen korrigieren
Klassische Euler-Integration (position += velocity * dt) akkumuliert Fehler und braucht kleine Zeitschritte. Verlet (position_new = 2*position - position_old + acceleration*dt²) ist stabiler und erlaubt größere Zeitschritte.
Warum zwei Ebenen?
Das System hat zwei getrennte Physik-Welten:
- PhysicsWorld – Für Partikel, Schwärme, Ketten. Jeder Punkt ist ein Particle.
- SoftShape – Für deformierbare Formen. Die Vertices haben eigene Mini-Physik.
Warum getrennt? Weil ein Soft Circle seine interne Jelly-Physik behält, auch wenn er als Ganzes in der PhysicsWorld herumfliegt. Der ShapePhysicsAdapter verbindet beide Welten.
Zwei-Ebenen-Architektur
┌─────────────────────────────────────────────────────────────────────────┐
│ Ebene 1: PhysicsWorld │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ PhysicsWorld │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Particles │ │ Behaviors │ │Constraints │ │ Springs │ │
│ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
▲
┌───────────────────────────────────┼─────────────────────────────────────┐
│ Adapter │ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ ShapePhysicsAdapter │ │
│ └───────────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────┼─────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Ebene 2: SoftShape │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ SoftShape │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────┐ ┌────────────────────────┐ │
│ │ Vertices │ │ Internal Constraints │ │
│ └─────────────────┘ └────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘Ebene 1: PhysicsWorld
- Globale Punkt-basierte Simulation
- Particles mit Position, Velocity, Mass
- Für: Partikel-Systeme, Schwärme, Ketten
Ebene 2: SoftShape
- Shape-interne Simulation
- Für: Deformierbare Formen (Blob, SoftCircle)
Komponenten
| Klasse | Datei | Funktion |
|---|---|---|
PhysicsWorld |
PhysicsWorld.ts |
Container für Simulation |
Particle |
Particle.ts |
Verlet-Partikel |
Behavior |
Behavior.ts |
Kraft-Interface |
Constraint |
Constraint.ts |
Regel-Interface |
Spring |
Spring.ts |
Feder-Verbindung |
ParticleString |
ParticleString.ts |
Partikel-Kette |
CollisionZone |
CollisionZone.ts |
Kollisions-Bereiche |
ProximityConnection |
ProximityConnection.ts |
Nähe-basierte Linien |
PhysicsWorld
Container und Update-Loop.
Update-Reihenfolge:
- Behaviors anwenden (Kräfte)
- Particles updaten (Verlet)
- Springs aktualisieren
- Constraints anwenden
API:
| Methode | Beschreibung |
|---|---|
addParticle(p) |
Particle hinzufügen |
addBehavior(b) |
Behavior hinzufügen |
addConstraint(c) |
Constraint hinzufügen |
addSpring(s) |
Spring hinzufügen |
update(dt) |
Simulation updaten |
clear() |
Alles entfernen |
Particle
Verlet-Partikel.
Properties:
| Property | Typ | Beschreibung |
|---|---|---|
position |
Vector |
Aktuelle Position |
previousPosition |
Vector |
Letzte Position |
mass |
number |
Masse |
locked |
boolean |
Fixiert? |
damping |
number |
Dämpfung (0-1) |
radius |
number |
Für Kollisionen |
Methoden:
| Methode | Beschreibung |
|---|---|
addForce(f) |
Kraft hinzufügen |
update(dt) |
Verlet-Integration |
velocity |
Getter/Setter für Velocity |
Behaviors
Kräfte die auf Particles wirken.
GravityBehavior
| Option | Typ | Default | Beschreibung |
|---|---|---|---|
strength |
number |
9.81 | Stärke |
direction |
Vector |
(0, 1) | Richtung |
FrictionBehavior
| Option | Typ | Default | Beschreibung |
|---|---|---|---|
coefficient |
number |
0.02 | Reibungskoeffizient |
AttractionBehavior
| Option | Typ | Default | Beschreibung |
|---|---|---|---|
target |
Vector |
- | Anziehungspunkt |
strength |
number |
0.1 | Stärke |
radius |
number |
200 | Wirkungsradius |
ConstantForceBehavior
| Option | Typ | Beschreibung |
|---|---|---|
force |
Vector |
Konstante Kraft |
Presets: createWindBehavior(), createUpdraftBehavior()
Flocking Behaviors (Boids)
| Behavior | Beschreibung |
|---|---|
SeparationBehavior |
Abstand halten |
AlignmentBehavior |
Gleiche Richtung |
CohesionBehavior |
Zusammenbleiben |
FlockingBehavior |
Kombiniert alle drei |
Flocking Presets:
| Preset | Beschreibung |
|---|---|
birds |
Vogelschwarm |
fish |
Fischschwarm |
insects |
Insektenschwarm |
tight |
Enger Zusammenhalt |
loose |
Loser Zusammenhalt |
Constraints
Regeln die Particles einhalten müssen.
RectConstraint
Hält Particles in einem Rechteck.
| Option | Typ | Beschreibung |
|---|---|---|
bounds |
{x,y,w,h} |
Rechteck |
mode |
RectConstraintMode |
'contain' oder 'repel' |
bounce |
number |
Bounciness (0-1) |
CircularConstraint
Hält Particles in/außerhalb eines Kreises.
| Option | Typ | Beschreibung |
|---|---|---|
center |
Vector |
Mittelpunkt |
radius |
number |
Radius |
mode |
CircularConstraintMode |
'contain' oder 'exclude' |
DistanceConstraint
Fester Abstand zwischen zwei Particles.
| Option | Typ | Beschreibung |
|---|---|---|
particleA |
Particle |
Erster Particle |
particleB |
Particle |
Zweiter Particle |
distance |
number |
Ziel-Abstand |
stiffness |
number |
Steifigkeit (0-1) |
AxisConstraint
Beschränkt auf eine Achse.
| Option | Typ | Beschreibung |
|---|---|---|
axis |
'x' | 'y' |
Achse |
value |
number |
Feste Position |
Presets: createHorizontalRail(), createVerticalRail()
MinConstraint / MaxConstraint
Minimum/Maximum-Grenze.
Presets: createFloor(), createCeiling(), createLeftWall(), createRightWall()
Springs
Federkräfte zwischen Particles.
| Klasse | Beschreibung |
|---|---|
Spring |
Standard Feder |
MinDistanceSpring |
Mindestabstand |
MaxDistanceSpring |
Maximalabstand |
Optionen:
| Option | Typ | Default | Beschreibung |
|---|---|---|---|
particleA |
Particle |
- | Erster Particle |
particleB |
Particle |
- | Zweiter Particle |
restLength |
number |
auto | Ruhelänge |
stiffness |
number |
0.5 | Steifigkeit |
damping |
number |
0.1 | Dämpfung |
ParticleString
Kette von Particles mit Constraints.
Factory-Funktionen:
| Funktion | Beschreibung |
|---|---|
createRope(opts) |
Seil (viele Segmente, weich) |
createTautLine(opts) |
Gespannte Linie (steif) |
createChain(opts) |
Kette (mit Springs) |
CollisionZone
Bereiche mit speziellem Verhalten.
| Option | Typ | Beschreibung |
|---|---|---|
shape |
'rect' | 'circle' |
Form |
behavior |
ZoneBehavior |
Verhalten beim Eintritt |
Behaviors:
| Behavior | Beschreibung |
|---|---|
slow |
Verlangsamen |
accelerate |
Beschleunigen |
kill |
Particle entfernen |
bounce |
Abprallen |
attract |
Anziehen |
ProximityConnection
Zeichnet Linien zwischen nahen Particles.
| Option | Typ | Default | Beschreibung |
|---|---|---|---|
maxDistance |
number |
100 | Max. Verbindungsdistanz |
minOpacity |
number |
0 | Opacity bei maxDistance |
maxOpacity |
number |
1 | Opacity bei Kontakt |
strokeWidth |
number |
1 | Linienbreite |
Presets:
| Preset | Beschreibung |
|---|---|
network |
Netzwerk-Look |
constellation |
Sternbild-Look |
web |
Spinnennetz-Look |
Presets & Factory-Funktionen
| Funktion | Beschreibung |
|---|---|
createDefaultPhysicsWorld() |
Standard-World mit Gravity |
createRandomParticle(bounds) |
Zufälliger Particle |
createParticleChain(n, opts) |
Verkettete Particles |
addFlockingToWorld(world, preset) |
Flocking hinzufügen |
Soft Body Kollisionen
Das Soft Body System (siehe 004-Shapes) unterstützt Shape-zu-Shape Kollisionen.
Kollisions-Pipeline
┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐
│ Broad-Phase │ -> │ Narrow-Phase │ -> │ Response │
│ AABB │ │ SAT │ │ Impulse │
└─────────────────┘ └─────────────────┘ └─────────────┘Phasen:
| Phase | Algorithmus | Beschreibung |
|---|---|---|
| Broad-Phase | AABB | Schneller Bounding-Box Test - filtert nicht-kollidierende Shapes |
| Narrow-Phase | SAT | Separating Axis Theorem - präzise Polygon-Überlappung |
| Response | Impulse | Shapes separieren + elastischer Bounce anwenden |
Aktivieren
import { ShapeStateManager } from '@carstennichte/cc-toolbox';
// Shapes erstellen und konfigurieren...
const shapes: ShapeStateManager[] = [...];
// Alle Shapes kennen alle anderen
const decorators = shapes.map(s => s.getDecorator());
for (const shape of shapes) {
shape.setCollisionBodies(decorators);
}Parameter-Einfluss
| Parameter | Einfluss auf Kollision |
|---|---|
elasticity |
Bounce-Stärke (Durchschnitt beider Shapes) |
stiffness |
Wie schnell sich Shape nach Kollision stabilisiert |
damping |
Dämpft Kollisions-Bounce |
Performance-Hinweise
- Alle-gegen-Alle: Bei n Shapes → n² Checks
- Empfehlung: ~20-30 Shapes mit Kollision, ~50 ohne
- Konkave Shapes: SAT funktioniert nur zuverlässig für konvexe Polygone