Files
train-game/README.md
2026-08-29 11:44:31 +02:00

122 lines
5.4 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.
# Cozy Train
Low-Poly-Zugspiel in Godot 4.7. Eine Crew verwaltet gemeinsam einen Zug:
einer fährt, die anderen kontrollieren Tickets, servieren Getränke und
laden Güter um. First-Person, entspannter Ton, alles aus Primitiven gebaut.
## Starten
~/bin/godot --path . # Spiel
~/bin/godot --editor --path . # Editor
./tests/run.sh # Tests (Spiellogik, Eingabe, Netzwerk)
Im Menü: **Einzelspieler**, **Sitzung hosten** oder **Beitreten** mit
Adresse und Port (Standard 7654). Der Host simuliert alles, Clients
schicken Wünsche und bekommen den Zustand zurück.
Die Eingabe-Tests brauchen ein Fenster, die anderen laufen headless.
Sie schieben echte Input-Events durch die Godot-Kette (GUI -> `_unhandled_input`)
und prüfen die Wirkung im Spiel, nicht nur den Aufruf. `direction_test.gd`
vergleicht jede Laufrichtung mit den Achsen der Kamera – ein Vorzeichenfehler
beim Seitwärtsgehen fällt damit sofort auf.
## Steuerung
| Taste | Wirkung |
|-------------------|------------------------------------------|
| Maus | Umsehen |
| W A S D | Laufen (im Führerstand: W Gas, S Bremse) |
| Shift | Rennen |
| E | Benutzen; am Güterwagen halten |
| H | Pfeife (nur wer fährt) |
| M | Musik an/aus |
| V | Außenkamera (A/D drehen, R/F neigen, Rad zoomen) |
| Esc | Maus freigeben / Terminal schließen |
## Was es zu tun gibt
**Fahren.** Im Führerstand am Pult E drücken. Nur ein Spieler kann fahren;
E gibt die Steuerung wieder frei. Am Bahnsteig anhalten – der Zug gilt als
angekommen, wenn seine Mitte nah genug am Bahnsteig steht.
**Fahrgäste.** Sie warten am Bahnsteig, steigen beim Halt ein und wollen
kontrolliert werden. Ein Blick auf den Gast, E – das Ticket bringt sofort
Geld. Wer bis zum Ziel unkontrolliert bleibt, fährt schwarz und kostet
Ansehen.
**Servieren.** Mit einem Speisewagen bekommen Gäste nach einer Weile Durst.
Getränk an der Theke holen (E), zum Gast, E. Bringt Trinkgeld und hält die
Laune oben. Schlechte Laune kostet beim Aussteigen Ansehen.
**Güter.** Im Güterwagen steht eine Ladekonsole. Im Halt E gedrückt halten:
Erst wird abgeliefert, was der Bahnhof annimmt, danach geladen, was er
produziert.
| Bahnhof | produziert | nimmt an |
|-------------|-----------|-------------------|
| Waldkirch | Holz | Getreide |
| Kohlberg | Kohle | – |
| Eisenwerk | – | Kohle, Holz |
| Grüntal | Getreide | – |
| Ahornstadt | – | Getreide, Holz |
**Depot-Terminal.** Hinten im Führerstand. Dort kaufst und verkaufst du
Waggons, tauschst die Lok und schaltest Ausbauten frei. Bessere Loks und
Waggons brauchen **Ansehen** – das steigt mit zufriedenen Fahrgästen und
gelieferten Waren.
## Aufbau
Die Welt entsteht komplett zur Laufzeit, `scenes/main.tscn` ist nur der
Einstiegspunkt.
| Datei | Inhalt |
|-------|--------|
| `shaders/flat.gdshader` | Facettierte Optik über Screen-Space-Normalen |
| `scripts/game.gd` | Weltaufbau, Spielstand, Aktionen, Netzwerk |
| `scripts/car.gd` | Ein Fahrzeug: Hülle, Innenraum, Sitze, Hotspots |
| `scripts/car_defs.gd` | Stammdaten für Loks, Waggons, Ausbauten |
| `scripts/train.gd` | Verband, Fahrphysik, Zug- zu Weltkoordinaten |
| `scripts/player.gd` | First-Person-Bewegung in Zugkoordinaten |
| `scripts/passenger.gd` | Fahrgast mit Ticket, Wunsch und Laune |
| `scripts/station.gd` | Bahnsteig, Lager, Warteplätze |
| `scripts/world.gd` | Gelände und Vegetation (MultiMesh) |
| `scripts/track.gd` | Gleiskurve und Gleisoptik |
| `scripts/shop.gd`, `hud.gd`, `menu.gd` | Oberflächen |
| `scripts/camera_rig.gd` | Außenkamera |
| `scripts/synth.gd` | Wavetable-Synth: Töne, Rauschen, Hüllkurven |
| `scripts/sfx.gd` | Alle Klänge und das Musikstück als Rezept |
| `scripts/audio.gd` | Wiedergabe, Fahrgeräusch, Radschläge, Schritte |
### Zugkoordinaten
Spieler bewegen sich nicht in Weltkoordinaten, sondern in einer
Längsposition `s` entlang des Zuges plus einer Querposition `x`.
`train.locate(s)` liefert den passenden Waggon, dessen Transform die
Weltposition ergibt. Dadurch bleibt der Innenraum auch bei voller Fahrt
und in Kurven stabil begehbar, ohne Physik-Plattformen.
### Klang
Es gibt keine Audiodateien. `sfx.gd` beschreibt jeden Klang als Rezept aus
Sinustönen, Rauschen und Hüllkurven; `synth.gd` rechnet daraus PCM. Das
läuft beim Start in einem Thread (rund drei Sekunden), bis dahin bleibt es
still – das Spiel ruckelt dabei nicht.
Die Musik ist ein 27-Sekunden-Stück in 72 bpm: Flächen über Am7–Fmaj7–
Cmaj7–G6, dazu Bass, sparsame Glockentöne und ein leiser Shaker. Der
Ausklang wird auf den Anfang gemischt, dadurch ist die Schleife nahtlos.
Das Fahrgeräusch ist eine Rauschschleife, deren Lautstärke und Tonhöhe am
Tempo hängen. Die Radschläge kommen nicht per Timer, sondern alle 8,5
gefahrene Meter – deshalb passen sie automatisch zur Geschwindigkeit.
### Netzwerk
Godot-Hochsprachen-RPCs über ENet. Der Host ist maßgeblich für Zug,
Fahrgäste, Lager und Kasse. Clients senden ihre Pose (15 Hz) und
Aktionswünsche; der Host verteilt Zustandspakete (4 Hz). Die Welt wird auf
allen Rechnern aus demselben Seed erzeugt und muss deshalb nicht
übertragen werden.