• Zuhause
  • Artikel
  • So synchronisieren Sie Ihre Spiel-App auf mehreren Geräten
Veröffentlicht am 23-02-2019

So synchronisieren Sie Ihre Spiel-App auf mehreren Geräten

Wenn Sie Probleme mit der Synchronisierung von Online-Spielen haben, sind Sie hier genau richtig!

Foto von rawpixel auf Unsplash

Auf ihrer niedrigsten Stufe können typische Spiele in einfache Schritte unterteilt werden, die von jedem Spieler ausgeführt werden. Diese werden als Zug bezeichnet und in jeder Runde erfolgt eine Bewegung. Es ist nicht notwendig, dass die Spieler nur eine Runde oder nur einen Zug machen. Um Ihre Spiel-App über mehrere Online-Geräte hinweg zu synchronisieren, müssen Sie Ihr Spiel in diese kleinen Schritte einteilen können.

Unser Modell

In diesem Artikel nehmen wir ein einfaches Brettspiel mit zwei Spielern. Bevor wir etwas tun, brauchen wir zwei Spieler, richtig?

Um dies einzurichten, müssen Sie eine Funktion namens Matchmaking implementieren, bei der sich in Ihrer Firebase-Datenbank ein gemeinsamer Knoten befindet, in dem jeder Spieler seine Herausforderung posten kann. Die gepostete Challenge enthält die UID des Challengers und einen weiteren Verweis auf einen Move-Knoten, auf dem die Moves veröffentlicht werden. Wenn Sie dies nicht getan haben oder Probleme bei der Implementierung haben, lesen Sie diesen Artikel zum Matchmaking.

Sobald beide Spieler den Zugknoten erreichen, muss ein Spieler seinen ersten Zug posten, dann den zweiten, dann den ersten usw. Wir verwenden den ChildEventListener von Firebase, um vom Gegner gepostete Züge zu erhalten.

Tauchen Sie tiefer in den Code ein

Grundsätzlich haben wir zwei Dinge zu tun: Senden Sie einen Zug und erhalten Sie einen Zug. Unsere FirebaseGameSynchronizer-Komponente wird genau das tun, aber die Interpretation der Verschiebung wird vom Modulator vorgenommen, den Sie implementieren.

Der Mover sendet seine Bewegung mit sendMoveMsg. Sie können Ihren Zug auf verschiedene Arten kodieren. Wenn zum Beispiel ein Stück von (a, b) nach (c, d) verschoben wird, codieren Sie die Bewegung als Zahl abcd. Ich würde diese Methode auf jeden Fall empfehlen, wenn die Größe Ihres Samples (oder wenn es sich um ein Brettspiel handelt, die Boardgröße kleiner ist)

sendMoveMsg lädt die Bewegung grundsätzlich auf den Move-Node mMovesRecordList hoch und erwartet, dass der andere Spieler sie hört.

Sobald der Zug veröffentlicht ist, erhalten beide Spieler den Zug. Warten Sie eine Minute… Sie möchten nicht, dass der Versender den Zug erhält - weil Sie den Zug vielleicht schon an seinem Ende gemacht haben und nicht zweimal machen möchten.

Daher habe ich auch eine coole Funktion hinzugefügt (wenn Sie möchten, dass beide Spieler stattdessen die Bewegung erhalten, entfernen Sie einfach alle Verweise auf mSelfMoveSoph): das Semaphore für die Selbstbewegungen. Bei jedem Aufruf von sendMoveMsg wird der Wert auf mSelfMoveSoph erhöht. Wir wissen, wie viele Züge wir gerade mit diesem Semaphor hochgeladen haben.

onChildAdded wird aufgerufen, wenn Firebase eine Bewegung hinzufügt. Die Bewegung wird ignoriert, wenn das Semaphor einen Wert hat. Andernfalls wird der mMessageModulator aufgerufen, um die Verschiebung zu interpretieren und Ihrem Benutzer anzuzeigen. Der Modulator ist eine funktionale Schnittstelle, die die Ergänzung Ihres Move-to-String-Encoders darstellt. Die in Firebase hochgeladene Zeichenfolge wird in die Bewegung umgewandelt.

Warten Sie, das funktioniert nicht, wenn der Benutzer einen Anruf erhält

Ja, wenn der Benutzer einen Anruf erhält und Ihre Anwendung beendet wird… wie wird der Benutzer wieder spielen?

Lassen Sie uns noch einmal einen Modulator so machen:

public class GenericGameFragment implementiert FirebaseGameSynchronizer.Modulator {
    public void onMoveReceived (boolean isSyncingPast, String encodedMsg) {
       // ... bewegen, zeigen Sie es auf der Benutzeroberfläche .....
    }
}

Nun werden zwei schlimme Dinge passieren:

  1. Wenn der Benutzer den Computer verlässt, bleibt FirebaseGameSynchronizer mit dem Knoten verbunden, der auf ihn wartet. Das ist ein Speicherleck + CPU-Verbrauchsleck.
    1. FirebaseGameSynchronizer verfügt über einen Verweis auf Ihr Fragment - Sie müssen nur wissen, dass Modulator die Benutzeroberfläche aktualisieren muss und einen Verweis auf GenericGameFragment hat.
    2. Synchronisieren und Aufheben der Synchronisierung mit dem Umzugsknoten

      Ich habe eine relativ einfache Lösung für das Problem verwendet. Es ist eine Kombination aus zwei Dingen:

      1. Sync-Flag: Wenn Sie die Sync-Eigenschaft festlegen, ruft FirebaseGameSynchronizer den Modulator auf. Andernfalls wird die Verschiebung in einem Puffer gespeichert. Beim erneuten Setzen des Sync-Flags werden zuerst die Bewegungen in seinem Puffer freigegeben.
        1. Anhang: Der Modulator wird bei jeder onStop-Methode des Fragments entfernt und wieder auf onStart des Fragments gesetzt.
        2. Denken Sie daran, vor dem Verwenden dieses "neuen" Synchronizers startSync () aufzurufen. Rufen Sie bei onStop stopSync auf, und rufen Sie in onResume erneut startSync auf. Nun sollten Sie detachModulator aufrufen und onDestroy einspülen.

          Überprüfen Sie diesen Link für die vollständige Implementierung: FirebaseGameSynchronization Gist.

          Vergiss nicht zu klatschen :)