All checks were successful
Deploy Docs / build-and-deploy (push) Successful in 22s
7.8 KiB
7.8 KiB
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):
00Leader: Spielleiter, BLE-Gateway, sammelt Punkte.01Repeater: Router im Mesh zur Reichweitenverlängerung (z.B. am Baum).11Base: 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:
- Spielleiter verbindet App via BLE mit Leader Box.
- Leader Box öffnet das Thread-Netzwerk (Commissioning).
- Neue Geräte (Waffe/Weste) werden in den Pairing-Modus versetzt (z.B. Tastenkombination).
- Geräte erhalten Netzwerk-Credentials und treten dem Mesh bei.
Schritt 2: Spieler-Konfiguration (Assignment)
- Ziel: Zuordnung von Hardware zu einer logischen
PlayerIDund einemTeam. - Identifikation: Jedes nRF52-Board hat eine eindeutige EUI-64 (MAC).
- Ablauf:
- App scannt QR-Code oder NFC-Tag an der Weste/Waffe.
- Payload: Enthält die EUI-64 Adresse.
- App sendet Konfiguration an Leader Box:
EUI-64 -> {PlayerID: 5, Team: Rot, Name: "Rambo"}. - Waffen-Setup: Waffe meldet ihren Typ (z.B. "Sniper") an Leader.
- 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):
- Waffe A schießt (sendet IR-Code mit
ShooterID+Damage+TeamID). - Weste B empfängt IR-Signal.
- Weste B berechnet Schaden (unter Berücksichtigung von Trefferzone-Multiplikator).
- Weste B zieht Lebenspunkte ab.
- Feedback: Weste B leuchtet/vibriert/spielt Sound ("Ugh!").
- Speicherung: Weste B speichert den Treffer im internen Flash-Log (
Timestamp, ShooterID, Zone, Damage). - (Optional) Weste B sendet UDP-Paket an Leader für Live-Scoreboard (Best Effort).
- Waffe A schießt (sendet IR-Code mit
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.
- Nach Zeitablauf (z.B. 30s) sendet Weste an Waffe:
Phase E: Spielende & Auswertung
- Leader: Sendet Multicast
GAME_STATE_FINISHED. - Ablauf:
- Alle Spieler kommen zusammen.
- Spielleiter drückt in App "Daten abrufen".
- Leader Box fragt nacheinander (Unicast) alle bekannten Westen ab:
GET /game/log. - Westen übertragen ihre Treffer-Historie.
- 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)
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)
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
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)
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 bitProtokoll-ID (Magic Byte zur Unterscheidung von Fernbedienungen)16 bitShooter ID8 bitInfo (4 bit Team, 4 bit Damage Class)