Files
atomic-engine/AGENTS.md
T
nico 1bce9da0c6 Initial commit: AtomicEngine v0.2
- Rust/WASM physics engine (grid, material, physics, render_buffer)
- 16 material types (stone, sand, water, wood, fire, lava, glass, ice, oil, acid, steam, spark, smoke + player placeholder)
- Fire system (fuel-based, flammability-scaled consumption, spread, smoke/sparks)
- Lighting system (emission, flood-fill propagation, glow, reflection)
- Per-material pixel texturing (wood grain, dirt specks, stone noise, flame variation)
- WebGL2 renderer with camera (WASD move, mouse wheel zoom)
- Native x86 debug binary (identical dimensions, FPS counter)
- Large world 1024x768 with active-region simulation (camera + 200px margin)
- UI material palette + FPS display
2026-07-09 11:13:39 +02:00

225 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AtomicEngine
> Eine 2D-Platformer-Gameengine bei der jeder Pixel wie ein Atom mit eigenen
> Eigenschaften und Anziehungskräften zu seinen Nachbarn agiert.
> Browser-basiert mit Rust/WASM für die Physik und WebGL2 fürs Rendering.
## Architektur-Übersicht
```
engine/ (Rust → WASM) web/ (TypeScript + Vite)
┌─────────────────────┐ ┌──────────────────────┐
│ grid.rs │ │ main.ts │
│ material.rs │ │ renderer.ts (WebGL2) │
│ physics.rs │ │ input.ts │
│ render_buffer.rs │ │ camera.ts │
│ lib.rs (wasm API) │ │ │
└─────────────────────┘ └──────────────────────┘
│ │
└── SharedArrayBuffer ──────┘
```
## Tech-Stack
| Schicht | Technologie | Warum |
|---------------|--------------------------|------------------------------------|
| Physik | Rust → WASM | Performance, Sicherheit |
| WASM Bridge | wasm-bindgen, wasm-pack | Auto JS-Bindings |
| Renderer | WebGL2 (Canvas) | GPU-beschleunigt, 60fps |
| Web Shell | TypeScript, Vite | Build, Dev-Server, HMR |
| Speicher | SharedArrayBuffer | Zero-copy WASM ↔ JS |
## Welt-Modell
- **Große Welt**: 1024×768 Pixel (4×3 Chunks à 256×256)
- Nur Zellen im Sichtfeld + 80px Margin werden simuliert
- Rest eingefroren — keine CPU-Kosten für unsichtbare Bereiche
- Grid wächst auf 1024×768 = 786K Zellen (~3 MB Speicher)
### Datenstruktur Cell (pro Pixel)
```rust
struct Cell {
material: u8, // Material-ID (0 = Luft)
health: u8, // Lebenspunkte/Dichte
temp: u8, // Temperatur
flags: u8, // Bitflags (aktiv, Player, Flüssig, ...)
}
```
Grid ist SoA (Structure of Arrays):
- `Vec<u8>` für materials, healths, temps, flags
- Breite × Höhe = Chunk-Größe
## Material-System
16 Materialien (0=Luft, 1=Stein, 2=Erde, 3=Sand, 4=Wasser, 5=Holz, 6=Lava,
7=Player, 8=Dampf, 9=Feuer, 10=Glas, 11=Eis, 12=Öl, 13=Säure, 14=Funken, 15=Rauch).
Properties pro Material: `MaterialProps` in `engine/src/material.rs`:
- `color`, `density`, Bewegung-Typ (`is_powder/is_liquid/is_gas/is_solid/is_static`)
- `flammability`, `melt_temp`, `boil_temp`, `heat_conduct`, `acid_resist`
- `light_emit` (0255, wie viel Licht das Material abstrahlt)
- `light_block` (0255, wie stark das Material Licht blockiert)
### Interaktions-System
**Heat-Transfer**: Temperatur-Diffusion über Moore-Nachbarn (`heat_conduct`-abhängig).
**Phase-Transformationen** (`material::transform`):
- Eis (11) → Wasser (4) bei temp ≥ 5°C
- Wasser (4) → Dampf (8) bei temp ≥ 100°C
- Dampf (8) → Wasser (4) bei temp ≤ 80°C
- Lava (6) → Stein (1) bei temp ≤ 5°C
- Holz (5) → Feuer (9) bei temp ≥ 240°C
- Öl (12) → Feuer (9) bei temp ≥ 120°C
**Reaktionen** (`physics::react`):
- Wasser + Lava → Dampf + Stein
- Wasser + Feuer → Dampf + Luft (löscht Feuer)
- Lava + Holz/Öl → entzündet Holz/Öl sofort zu Feuer
- Säure + Holz/Sand → zerstört Holz/Sand
- Säure + Stein/Erde → zerstört Stein/Erde (langsamer)
**Feuer-System**:
- Braucht Brennstoff (Holz, Öl) um zu überleben — prüft direkt unter sich + Moore-Nachbarn
- Feuer-Säule: Hat eine Zelle Feuer unter sich, gilt sie als versorgt (Ketten-Propagation)
- Mit Brennstoff: keine Health-Decay
- Ohne Brennstoff: 6hp/Frame → erlischt in ~7 Frames (~0.1s)
- Brenn-Rate `flammability`-abhängig: `300/flam` Frames zwischen 1hp-Konsum
- Holz (30): ~10 Frames/Konsum → ~42s pro Block
- Öl (80): ~3 Frames/Konsum → ~13s pro Block
- Ausbreitung: 1/250 Chance auf brennbare Nachbarn
- Wasser/Eis in Nachbarschaft → Feuer erlischt sofort
- Erzeugt Funken (14) und Rauch (15) beim Brennen
- **Flammen-Züngeln**: 1/5 Chance pro Zelle, Funken-Partikel nach oben zu feuern (412 Frames Lebensdauer)
**Ephemere Partikel** (Funken + Rauch):
- `update_ephemeral`: dekrementiert Health, bei 0 → Luft
- Flammen-Funken: 412 Frames, 1/5 Emission, kurzlebig für Flammenspitzen
- Funken: 3080 Frames Lebensdauer, orange, 1/16 Emission/Frame
- Rauch: 140220 Frames, hellgrau transparent, 1/6 Emission/Frame
- Gas-Pass separat (alle 2 Frames, top→bottom = max 1px/Frame Aufstieg)
## Physik-Loop (pro Frame)
Reihenfolge in `physics::update(cam_x, cam_y, rw, rh, zoom)`:
Nur Zellen innerhalb **Kamera-Sichtfeld + 80px Margin** werden simuliert.
Rest der Welt ist eingefroren (keine CPU-Kosten).
1. **update_fire** — Feuer-Update: Brennstoff-Verbrauch, Ausbreitung, Funken/Rauch-Emission
2. **Haupt-Loop** (bottom→top, alternierende Spalten, nur aktive Region):
- Heat-Transfer über Moore-Nachbarn
- Material-Reaktionen (Water+Lava, Säure+Holz, ...)
- Phasen-Transformation (Temp-basiert)
- Bewegung: Powders ↓, Liquids ↓↔, Solids ↓ (kein Gas!)
3. **update_gases** (top→bottom, nur jedes 2. Frame, nur aktive Region): Gas steigt 1px/Frame
4. **update_ephemeral** (nur aktive Region): Spark/Smoke Health dekrementieren, bei 0 → Luft
## Level-Format
RGBA-PNG, jeder Pixel = 1 Atom:
- R = Material-ID (0=Luft)
- G = Dichte/Gesundheit
- B = Temperatur
- A = Flags
Levels in Aseprite/Photoshop malbar. Große Welten = Raster von PNG-Dateien.
## Rendering
1. WASM schreibt sichtbaren Bereich als RGBA-Buffer
2. Buffer als Uint8Array aus WASM-Speicher gelesen
3. WebGL2 lädt als Textur → Fullscreen-Quad
4. Kamera-Matrix für Scroll/Zoom
### Textur-System
Jedes Material bekommt deterministische Pixel-Variation basierend auf Grid-Koordinaten:
- **Holz**: Vertikale Maserung (dünne Fasern alle ~5px, ±1px Welle)
- **Erde**: Grobkörnige Flecken (niederfrequentes Rauschen, ±20 RGB)
- **Stein/Glas**: Subtiles Rauschen (±10 RGB)
- **Sand**: Feines Granulat (±6 RGB)
- **Eis**: Minimales Rauschen (±5 RGB)
- **Flüssigkeiten/Gase**: Keine Textur
- **Feuer/Lava**: Kanal-getrennte Varianz (R ±6, G ±12, B ±8) — natürliche Gelb-/Orange-Mischung
### Beleuchtungs-System
**Light-Propagation** in `render_buffer.rs`:
1. Emissions-Pass: Jedes Pixel mit `light_emit > 0` strahlt Licht
2. Flood-Fill (max 12 Passes, early-termination): 8-Richtungs-Propagation
- Falloff: 2 (kardinal) / 3 (diagonal) + `light_block` (gecapped bei 200)
- Opaque Pixel blocken Weitergabe, werden aber selbst beleuchtet
3. Abwechselnde Scan-Richtung für gleichmäßige Verteilung
**Lichtquellen**: Feuer (255), Lava (200), Funken (180)
**Glow-Effekt**: Luft-Pixel mit Licht blenden von dunklem Hintergrund zu warmem Orange — quadratische Kurve (`t = lvl²/255`) für natürlichen Abfall. Nur direkt an der Quelle stark sichtbar.
**Reflexion**: Semi-transparente Materialien (Glas, Wasser, Eis — block 1179) werfen 50% des empfangenen Lichts an Nachbar-Pixel zurück → indirekte Beleuchtung.
**Beleuchtungs-Formel** (Material-Pixel): Additiv: `r = min(255, r × 150/256 + light)` — Ambient-Basis 59% + Licht obendrauf.
### UI
- **Material-Palette**: Leiste am unteren Bildschirmrand, Farb-Swatch + Name + Taste
- **FPS-Anzeige**: Oben rechts, grün, alle 500ms aktualisiert
## Build & Entwicklung
**WICHTIG**: Native Debug-Binary und WASM/Web-Build müssen immer identisch laufen.
Der Debug-Build nutzt dieselben Module (`grid`, `material`, `physics`, `render_buffer`)
und dieselben Dimensionen (256×192 Grid, 320×180 Render-Buffer). Performance-Unterschiede
sind WASM-Overhead, nicht Logik-Abweichungen. Bei Änderungen an der Engine immer beide
Builds testen.
```bash
# Rust → WASM bauen
cd engine && wasm-pack build --target web --out-dir ../web/pkg
# Native Debug-Binary (x86, ohne WASM)
cd engine && cargo run --bin atomic-debug --release
# Web Dev-Server
cd web && npm run dev
# Produktion
cd web && npm run build
```
## Datei-Index (was findet man wo)
| Was | Datei |
|----------------------------------|-----------------------------------|
| WASM öffentliche API | `engine/src/lib.rs` |
| Native Debug Binary | `engine/src/main.rs` |
| Cell + Chunk + Grid DS | `engine/src/grid.rs` |
| Material-Definitionen | `engine/src/material.rs` |
| Physik: Kräfte, Sand, Fluide | `engine/src/physics.rs` |
| RGBA-Buffer Export | `engine/src/render_buffer.rs` |
| Rust-Abhängigkeiten | `engine/Cargo.toml` |
| WebGL2 Renderer | `web/src/renderer.ts` |
| WASM-Bridge + Material-Konstanten| `web/src/engine.ts` |
| Game-Loop, Wiring | `web/src/main.ts` |
| Input (Keyboard, Maus) | `web/src/input.ts` |
| Kamera (Scroll, Zoom) | `web/src/camera.ts` |
| HTML Einstieg | `web/index.html` |
| Vite Konfiguration | `web/vite.config.ts` |
| TypeScript Konfiguration | `web/tsconfig.json` |
## Aktueller Status
- [x] Phase 0: Projekt-Struktur + WASM/WebGL End-to-End ← **fertig**
- [x] Phase 1: Sand-Physik (Pixel fällt nach unten) ← **fertig** (Sand + Flüssigkeiten)
- [x] Phase 2: Mehrere Materialien + Kräfte-Tabelle ← **fertig**
- [x] Phase 3: Chunk-System + große Welt + Kamera ← **fertig**
- [ ] Phase 4: Spieler als Atom-Cluster + Input
- [ ] Phase 5: Erweiterungen (Items, Player-Interaktion, Editor, ...)
## Namenskonventionen
- Rust: snake_case, English
- TypeScript: camelCase, English
- Keine Kommentare im Code (nur wenn explizit gewünscht)