Konzepte angepasst und erweitert
All checks were successful
Deploy Docs / build-and-deploy (push) Successful in 13s

This commit is contained in:
2026-01-03 11:20:42 +01:00
parent d7f004ee72
commit 06af540be3
10 changed files with 891 additions and 121 deletions

194
doc/software.md Normal file
View File

@@ -0,0 +1,194 @@
# Software-Konzept & Spielablauf
Dieses Dokument beschreibt die Software-Architektur, die Rollenverteilung und die Kommunikationsabläufe des Lasertag-Systems.
## 1. System-Rollen & Hardware-Typen
Das System basiert auf nRF52840-Chips, die über OpenThread (802.15.4) kommunizieren.
### A. Leader Box (Game Controller)
* **Funktion:** Zentrale Spielsteuerung, Zeitgeber, Gateway zur Smartphone-App.
* **Modi (wählbar via DIP-Schalter):**
* `00` **Leader:** Spielleiter, BLE-Gateway, sammelt Punkte.
* `01` **Repeater:** Router im Mesh zur Reichweitenverlängerung (z.B. am Baum).
* `11` **Base:** Interaktives Ziel (z.B. für "Domination"-Modus).
### B. Weste (Player Hub)
* **Funktion:** Zentrale Einheit des Spielers. Verwaltet Lebenspunkte, empfängt Treffer, steuert Audio.
* **Kommunikation:** Hält die Verbindung zur Waffe (Pairing) und zum Leader.
### C. Waffe
* **Funktion:** Aussenden der IR-Signale, haptisches Feedback, Muzzle-Flash.
* **Logik:** Sendet "Schuss"-Events, empfängt "Sperren"-Befehle von der Weste (wenn tot).
---
## 2. Provisionierung & Setup (Lobby-Phase)
Bevor das Spiel startet, müssen Geräte dem Netzwerk beitreten und Spielern zugeordnet werden.
### Schritt 1: Netzwerk-Beitritt (Provisioning)
* **Szenario:** Neue Hardware wird zum ersten Mal verwendet.
* **Ablauf:**
1. Spielleiter verbindet App via BLE mit **Leader Box**.
2. Leader Box öffnet das Thread-Netzwerk (Commissioning).
3. Neue Geräte (Waffe/Weste) werden in den Pairing-Modus versetzt (z.B. Tastenkombination).
4. Geräte erhalten Netzwerk-Credentials und treten dem Mesh bei.
### Schritt 2: Spieler-Konfiguration (Assignment)
* **Ziel:** Zuordnung von Hardware zu einer logischen `PlayerID` und einem `Team`.
* **Identifikation:** Jedes nRF52-Board hat eine eindeutige **EUI-64** (MAC).
* **Ablauf:**
1. App scannt **QR-Code** oder **NFC-Tag** an der Weste/Waffe.
2. Payload: Enthält die EUI-64 Adresse.
3. App sendet Konfiguration an Leader Box: `EUI-64 -> {PlayerID: 5, Team: Rot, Name: "Rambo"}`.
4. **Waffen-Setup:** Waffe meldet ihren Typ (z.B. "Sniper") an Leader.
5. Leader sendet Konfigurations-Paket (CoAP Unicast) an das Gerät:
* **Weste:** Erhält PlayerID, TeamID, MaxHealth.
* **Waffe:** Erhält Damage-Wert, Nachladezeit, Magazingröße.
---
## 3. Spielablauf (Game Loop)
### Phase A: Vorbereitung
* **Leader:** Sendet Multicast `GAME_STATE_LOBBY`.
* **Geräte:** Spielen Idle-Animation ab, warten auf Start.
* **Check:** Leader kann "Ping" an alle senden, um Anwesenheit zu prüfen.
### Phase B: Countdown
* **Leader:** Sendet Multicast `GAME_START_COUNTDOWN` (Payload: 10 sek).
* **Westen:** Zählen laut herunter: "10, 9, 8...".
### Phase C: Spiel läuft (Running)
* **Status:** `GAME_STATE_RUNNING`.
* **Aktion:** Waffen sind entsperrt. Sensoren sind scharf.
* **Treffer-Logik (Dezentral):**
1. Waffe A schießt (sendet IR-Code mit `ShooterID` + `Damage` + `TeamID`).
2. Weste B empfängt IR-Signal.
3. Weste B berechnet Schaden (unter Berücksichtigung von Trefferzone-Multiplikator).
4. Weste B zieht Lebenspunkte ab.
5. **Feedback:** Weste B leuchtet/vibriert/spielt Sound ("Ugh!").
6. **Speicherung:** Weste B speichert den Treffer im internen Flash-Log (`Timestamp, ShooterID, Zone, Damage`).
7. *(Optional)* Weste B sendet UDP-Paket an Leader für Live-Scoreboard (Best Effort).
### Phase D: Spieler eliminiert
* **Bedingung:** Lebenspunkte <= 0.
* **Weste B:**
* Spielt "Dead"-Sound.
* Leuchtet dauerhaft in Teamfarbe (oder aus).
* Sendet CoAP Unicast an **eigene Waffe**: `CMD_DISABLE`.
* **Respawn (falls aktiv):**
* Nach Zeitablauf (z.B. 30s) sendet Weste an Waffe: `CMD_ENABLE`.
* Lebenspunkte werden zurückgesetzt.
### Phase E: Spielende & Auswertung
* **Leader:** Sendet Multicast `GAME_STATE_FINISHED`.
* **Ablauf:**
1. Alle Spieler kommen zusammen.
2. Spielleiter drückt in App "Daten abrufen".
3. Leader Box fragt nacheinander (Unicast) alle bekannten Westen ab: `GET /game/log`.
4. Westen übertragen ihre Treffer-Historie.
5. App berechnet Highscores, MVP, Trefferquoten.
---
## 4. Spielmodi
Die Logik für die Modi wird primär auf den Westen implementiert (Regelwerk), gesteuert durch Flags vom Leader.
### Team Deathmatch
* Klassisch Rot gegen Blau.
* Friendly Fire konfigurierbar (an/aus).
* Siegbedingung: Meiste Kills oder wenigste Tode nach Zeitablauf.
### Last Man Standing (Free-for-all)
* Jeder gegen Jeden.
* Keine Teams (oder jeder hat eigene Team-ID).
* Kein Respawn.
### Zombie (Infected)
* **Start:** 1 Spieler ist "Zombie" (Team Grün), Rest "Mensch" (Team Rot).
* **Regel:**
* Zombie hat unendlich Leben (oder sehr viel).
* Mensch hat 1 Leben.
* Wird Mensch getroffen -> Wechselt Team zu Zombie (Weste leuchtet grün, Waffe sendet ab jetzt Zombie-ID).
* Wird Zombie getroffen -> "Stunned" (Waffe 5s gesperrt).
* **Ziel:** Überleben bis Zeitablauf.
### Base Domination
* **Hardware:** Leader-Boxen im Modus `11` (Base) verteilt im Gelände.
* **Ablauf:**
* Spieler schießt auf Base-Box.
* Base-Box wechselt Farbe zu Teamfarbe des Schützen.
* Base-Box zählt Zeit für das haltende Team.
* Am Ende fragt Leader alle Base-Boxen ab: "Wie lange warst du Rot? Wie lange Blau?".
---
## 5. Technische Spezifikation (API & Datenstrukturen)
Die Kommunikation erfolgt über CoAP (UDP). Alle Payloads sind binär (`__packed` C-Structs, Little Endian für nRF52, aber Network Byte Order Big Endian empfohlen für Portabilität - hier vereinfacht Little Endian da homogene Hardware).
### 5.1 CoAP Endpunkte
| Ressource | Methode | Typ | Beschreibung | Payload |
| :--- | :--- | :--- | :--- | :--- |
| `game/state` | PUT | Multicast | Globaler Spielstatus (Start/Stop/Zeit) | `struct game_state_packet` |
| `game/conf` | PUT | Unicast | Konfiguration für einen Spieler | `struct player_config_packet` |
| `game/hit` | POST | Unicast | Treffer-Meldung (Live-Ticker) | `struct hit_report_packet` |
| `game/wconf` | PUT | Unicast | Konfiguration für eine Waffe | `struct weapon_config_packet` |
| `game/log` | GET | Unicast | Abruf der gespeicherten Trefferdaten | `struct flash_log_entry[]` |
### 5.2 Datenstrukturen
#### Spielstatus (Multicast)
```c
struct game_state_packet {
uint8_t state; // 0=Idle, 1=Lobby, 2=Running, 3=Paused, 4=Finished
uint8_t game_mode; // 0=TeamDeathmatch, 1=Zombie, 2=Base
uint16_t game_id; // Rolling Counter zur Deduplizierung
uint16_t remaining_sec; // Restzeit in Sekunden
uint8_t flags; // Bitmaske (z.B. FriendlyFire)
} __packed;
```
#### Spieler-Konfiguration (Provisioning)
```c
struct player_config_packet {
uint16_t player_id; // Logische ID (1-65535)
uint8_t team_id; // 0=Rot, 1=Blau, 2=Grün (Zombie), ...
uint8_t health_max; // Maximale Lebenspunkte
char name[16]; // Anzeigename (null-terminated)
} __packed;
```
#### Waffen-Konfiguration
```c
struct weapon_config_packet {
uint8_t base_damage; // Schaden pro Schuss
uint16_t reload_time_ms;// Zeit für Nachladen
uint8_t magazine_size; // Schuss pro Magazin
} __packed;
```
#### Treffer-Bericht (Live & Log)
```c
struct hit_report_packet {
uint32_t timestamp; // ms seit Spielstart
uint16_t shooter_id; // ID des Schützen (aus IR)
uint16_t victim_id; // Eigene ID
uint8_t damage; // Erlittener Schaden
uint8_t hit_location; // 0=Unbekannt, 1=Kopf, 2=Brust, 3=Rücken
} __packed;
```
---
## 6. IR-Protokoll (Physical Layer)
Das IR-Signal nutzt eine 38kHz Trägerfrequenz (NEC-ähnlich).
Payload (32-bit):
* `8 bit` Protokoll-ID (Magic Byte zur Unterscheidung von Fernbedienungen)
* `16 bit` Shooter ID
* `8 bit` Info (4 bit Team, 4 bit Damage Class)