fitst version
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
# 🏎️ Turbo Race
|
||||
|
||||
Multiplayer browser-racegame voor **tot 20 spelers**, speelbaar op de telefoon,
|
||||
met een neon/synthwave-look. Server-authoritatief (Node.js + WebSocket),
|
||||
deploybaar op je eigen Kubernetes-node.
|
||||
|
||||
## Features
|
||||
|
||||
- Verticale scrollende weg, portretmodus, **eenhandig besturen**
|
||||
(linkerhelft / rechterhelft van het scherm vasthouden).
|
||||
- Keyboard-up / pijltjes op desktop.
|
||||
- **Host** opent de kamer met `?host=<token>` en start heimelijk met de `S`-toets
|
||||
(30-seconden countdown, nieuwe aanmelders blijven welkom).
|
||||
- Obstakels: **pylonen** (vertragen) en **olievlekken** (wegslijden).
|
||||
- Power-ups: **⚡ boost** en **🛡 schild** (respawnen na 4,5s).
|
||||
- Live positie, snelheid, afstand, leaderboard en minimap.
|
||||
- **1:30 minuten** race over een baan van 23.000 m; wie over de finish is wint,
|
||||
anders wint bij aflopen van de tijd wie het verst is. Daarna **uitslag + podium**
|
||||
en direct een nieuwe ronde.
|
||||
|
||||
## Snel starten (lokaal)
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm start # → http://localhost:8080
|
||||
```
|
||||
|
||||
Open `http://localhost:8080` op je laptop én op je telefoon (zelfde wifi).
|
||||
Vul een naam in, klik aanmelden, en stuur met je vingers.
|
||||
|
||||
> 🎮 **De host is ook gewoon een speler.** Open als host:
|
||||
> `http://localhost:8080/?host=dev-host`
|
||||
> en druk op de **S**-toets om de start-telling in gang te zetten
|
||||
> (pas als de kamer vol is of iedereen klaar is 😉).
|
||||
|
||||
### Besturing
|
||||
|
||||
| Apparaat | Actie |
|
||||
| --- | --- |
|
||||
| Telefoon | Linkerhelft vasthouden = links, rechterhelft = rechts |
|
||||
| Toetsenbord | `←` / `A` en `→` / `D` |
|
||||
| Host | `S` in lobby of uitslag = race (laten) starten |
|
||||
|
||||
## Configuratie (omgevingsvariabelen)
|
||||
|
||||
| Variabele | Standaard | Betekenis |
|
||||
| --- | --- | --- |
|
||||
| `PORT` | `8080` | HTTP-poort (ook WebSocket op `/ws`) |
|
||||
| `MAX_PLAYERS` | `20` | Maximaal aantal coureurs per kamer |
|
||||
| `ADMIN_TOKEN` | `dev-host` | Geheim token waarmee je host wordt |
|
||||
| `COUNTDOWN_S` | `30` | Aftellen nadat de host op `S` drukt |
|
||||
| `RACE_DURATION_S` | `90` | Maximale racetijd in seconden |
|
||||
| `TRACK_LENGTH` | `23000` | Baanglengte in meter (finish = einde van de baan) |
|
||||
|
||||
> ⚠️ Gebruik in productie een **sterk `ADMIN_TOKEN`** (random string), anders kan
|
||||
> iedereen met de URL host worden.
|
||||
|
||||
## Tests
|
||||
|
||||
Headless simulatie: engine-unit-test **plus** live integratietest met een echte
|
||||
server, 20 websocket-clients en een host die de race start en de uitslag leest.
|
||||
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
```bash
|
||||
docker build -t turbo-race:latest .
|
||||
docker run --rm -p 8080:8080 \
|
||||
-e ADMIN_TOKEN='moeilijk-te-raden-token' \
|
||||
turbo-race:latest
|
||||
```
|
||||
|
||||
## Deployen op Kubernetes
|
||||
|
||||
Manifests staan in `k8s/` (Kustomize). Bouw de image op je node (of push naar
|
||||
een registry) en pas de image-tag in `k8s/base/deployment.yaml` aan.
|
||||
|
||||
```bash
|
||||
# 1) image bouwen (op de node zelf)
|
||||
docker build -t turbo-race:latest .
|
||||
|
||||
# 2) token instellen (kustomization generatiert een Secret)
|
||||
# Bewerk de literal 'admin-token=...' in k8s/base/kustomization.yaml
|
||||
|
||||
# 3) deployen
|
||||
kubectl apply -k k8s/base
|
||||
kubectl rollout status deploy/turbo-race
|
||||
kubectl get svc turbo-race # -> NodePort 30090
|
||||
```
|
||||
|
||||
Speel nu via: `http://<IP-van-je-node>:30090`
|
||||
|
||||
- Healthcheck: `curl http://<node-ip>:30090/healthz` → `{"ok":true,...}`
|
||||
- Met een domein + ingress-controller voeg je `k8s/ingress.yaml` toe
|
||||
(pas de `host` aan, WebSocket-tunnels worden lang opengehouden).
|
||||
|
||||
### Lokaal testen met Kind (macOS/Linux)
|
||||
|
||||
Op een **echte node** is NodePort 30090 direct bereikbaar op het node-IP.
|
||||
Met **Kind** moet de poort wél expliciet naar de host gemapt worden:
|
||||
dienst `k8s/kind-config.yaml` mapt `30090 → localhost`.
|
||||
|
||||
```bash
|
||||
kind create cluster --config k8s/kind-config.yaml # alleen bij (her)aanmaken
|
||||
kind load docker-image turbo-race:latest
|
||||
kubectl apply -k k8s/base
|
||||
# speel op: http://localhost:30090
|
||||
```
|
||||
|
||||
> ℹ️ Kind hergebruikt een bestaand cluster; als NodePort niet naar `localhost`
|
||||
> werkt, verwijder het cluster eerst (`kind delete cluster`) en maak het opnieuw
|
||||
> aan met bovenstaande `--config` (port-mappings staan vast bij creatie).
|
||||
|
||||
|
||||
> ⚠️ **Belangrijk:** de game staat **in-memory** (1 kamer). Houd
|
||||
> `replicas: 1` — meerdere replica's zouden spelers over losse kamers verspreiden.
|
||||
|
||||
## Architectuur
|
||||
|
||||
```
|
||||
public/ frontend (geen bundler): index.html, style.css, client.js, render.js
|
||||
server/engine.js server-side spelengine: fysica, obstakels, power-ups, fases, ranking
|
||||
server/index.js HTTP/static + WebSocket /ws + events + broadcasts
|
||||
test/simulate.js headless test (fluweel: 20 clients ipv 1)
|
||||
```
|
||||
|
||||
- Engine loop 40 Hz; **snapshots op ~16 Hz**; clients **interpoleren** de rendering.
|
||||
- Baan is **deterministisch** opgebouwd uit één random seed → eerlijk & identiek
|
||||
voor elke speler.
|
||||
- De host is een normale speler; de `host_start`-melding wordt alleen geaccepteerd
|
||||
van sockets die met het juiste token zijn aangemeld.
|
||||
|
||||
## Flow & regels
|
||||
|
||||
1. **Lobby** — namen aanmelden tot max 20 (fases live zichtbaar).
|
||||
2. Host drukt `S` → **30s countdown** (heen-en-weer banners, nieuwe spelers welkom).
|
||||
3. **Race** — rechte weg met obstakels en power-ups; finish is het einde van de
|
||||
baan. Wie als eerste over de line is, wint; anders wint bij het aflopen van
|
||||
de tijd wie het verst is.
|
||||
4. **Uitslag** — podium + volledige lijst; de host start opnieuw met `S`.
|
||||
Reference in New Issue
Block a user