Zum Hauptinhalt springen

Mehrspieler

Lassen Sie mehrere Personen gleichzeitig eine Szene teilen. Senden Sie Nachrichten, teilen Sie Werte, erzeugen Sie Objekte für alle und lassen Sie andere Spieler flüssig laufen.

Diese Aufrufe funktionieren nur, wenn Mehrspieler für Ihr Projekt eingeschaltet ist und eine Sitzung offen ist. Sonst tun sie nichts. Dasselbe Skript funktioniert also auch in einer Einzelspieler-Vorschau, und Sie brauchen keine zwei Versionen.

Wer in der Sitzung ist​

ctx.net.id;        // die Id dieses Teilnehmers
ctx.net.peers(); // alle, die gerade in der Sitzung sind
ctx.net.onJoin((peer) => {});
ctx.net.onLeave((peer) => {});

Was sich von selbst synchronisiert​

Nur die Positionen von Physikkörpern, die auf shared stehen. Alles andere senden Sie selbst.

Das ist Absicht. Eine Kiste, eine Tür oder ein Ball soll ein einziges Objekt sein, das alle an derselben Stelle sehen. Eine Spielfigur darf nicht geteilt sein: Sonst bewegen sich die Avatare aller Teilnehmer, sobald eine Person läuft. → Besitz im Mehrspielermodus

Nachrichten​

Nutzen Sie Nachrichten für Dinge, die passieren: Jemand hat gepunktet, eine Runde hat begonnen, eine Tür ist aufgegangen.

ctx.net.send('score', { points: 10 });
ctx.net.on('score', ({ from, data }) => {
/* … */
});

Eine Nachricht geht an alle außer Ihnen. Eine Bestätigung bekommen Sie nicht.

Geteilter Zustand​

Nutzen Sie den geteilten Zustand für Werte, bei denen sich alle einig sein müssen. Er ist eine einfache Map, und jeder bekommt eine Kopie. Schreiben zwei Personen denselben Schlüssel, gewinnt der letzte Schreibvorgang.

ctx.net.state.set(ctx.net.id, { name, colour, ready: true });
ctx.net.state.get(somePeerId);
ctx.net.state.all();
ctx.net.state.on(ctx.net.id, (value) => {});

Um Werte pro Spieler zu speichern, nutzen Sie ctx.net.id als Schlüssel. Jede Person schreibt ihren eigenen Eintrag und liest die Einträge aller anderen.

Für alle erzeugen​

const id = ctx.net.spawn(props.bullet, { position, rotation });
ctx.net.despawn(id);

Sie bekommen die Id sofort, aber das Objekt erscheint erst einen Moment später. Die Id ist für alle gleich.

Nur wer ein Objekt erzeugt hat, kann es entfernen. Verlässt jemand die Sitzung, werden auch die Objekte entfernt, die diese Person erzeugt hat.

Andere Spieler flüssig bewegen​

Hier geht am häufigsten etwas schief, deshalb gibt es dafür einen eigenen Aufruf.

ctx.net.follow(otherPlayerObject, { position, rotation });
ctx.net.unfollow(otherPlayerObject);

Rufen Sie follow mit jeder Position auf, die Sie empfangen. Zehn- bis zwanzigmal pro Sekunde ist normal. Das Objekt bewegt sich dann flüssig, etwas hinter der neuesten Position.

Ein erneuter Aufruf von follow mit derselben Position kostet nichts. Sie können es also in jedem Frame mit der neuesten Position aufrufen, die Sie haben.

Empfangene Positionen nicht direkt in die Transformation schreiben

Updates kommen viel seltener an als Frames. Das Objekt steht also still und springt dann: Andere Spieler ruckeln, statt zu laufen. Auch ein sanftes Annähern an die neueste Position hilft nicht. Zwischen zwei Updates gibt es nichts Neues, auf das es sich zubewegen kann. Das Objekt bleibt stehen und macht dann einen Satz.

Ein Aufbau, der funktioniert​

Wenn Sie bei null anfangen, kommen Sie mit diesem Aufbau weit:

  • Jeder Spieler steuert seine eigene Figur — einen lokalen Körper, bewegt durch seine Eingaben.
  • Seine Position wird verschickt, über net.state oder Nachrichten, zehn- bis zwanzigmal pro Sekunde.
  • Die Figuren aller anderen werden mit follow bewegt.
  • Objekte der Welt sind geteilte Körper, die Physik hält sie also für Sie synchron.
  • Punktestand und Rundenstatus liegen in net.state, geschrieben von dem, der für das jeweilige Ereignis zuständig ist.

Weiter: Fehlerbehebung — was Sie tun, wenn etwas nicht funktioniert.