de Shukant Pal
Cum să vă sincronizați aplicația de joc pe mai multe dispozitive
Dacă aveți probleme cu sincronizarea jocului online, sunteți în locul potrivit!
La nivelul lor cel mai scăzut, jocurile tipice pot fi împărțite în pași simpli luați de fiecare jucător – se numesc ture și în fiecare tura are loc o mutare. Nu este necesar ca jucătorii să obțină o tură la rând sau să facă o singură mișcare la un moment dat. Pentru a vă sincroniza aplicația de joc pe mai multe dispozitive online, trebuie să vă puteți împărți jocul în acești pași mici.
Modelul nostru
În acest articol, luăm un simplu joc de masă generic pentru doi jucători. Înainte de a face ceva, avem nevoie de doi jucători, nu?
Pentru a configura acest lucru, trebuie să implementați o caracteristică numită matchmaking, unde aveți un nod comun în baza de date Firebase în care fiecare jucător își poate posta provocarea. Provocarea postată conține UID-ul provocatorului și o altă referință la un nod-mutări în care vor fi publicate mutările. Dacă nu ați făcut acest lucru sau aveți probleme cu implementarea acestuia, citiți acest articol potrivire.
Odată ce ambii jucători apucă nodul de mișcări, un jucător trebuie să posteze prima lor mișcare, apoi a doua, apoi prima și așa mai departe. Vom folosi Firebase’s ChildEventListener
să primească mișcări postate de adversar.
Scufundați-vă mai adânc în cod
Practic, avem două lucruri de făcut: trimiterea unei mutări și primirea unei mutări. Al nostru FirebaseGameSynchronizer
componenta va face exact asta, dar interpretarea mutării se va face de către Modulator
tu implementezi.
mutant trimite mutarea folosind sendMoveMsg
. Puteți codifica mutarea dvs. într-o varietate de moduri. De exemplu, dacă o piesă este mutată de la (a, b) la (c, d), atunci codificați mutarea ca număr abcd
. Aș recomanda cu siguranță această metodă dacă dimensiunea eșantionului dvs. (sau dacă este un joc de societate, dimensiunea de bord) este mai mică de 10.
sendMoveMsg
practic încarcă mutarea în nodul cu mișcări mMovesRecordList
și se așteaptă ca celălalt jucător să îl asculte.
Odată ce mutarea este publicată, ambii jucători primesc mutarea. Așteaptă un minut … Nu vrei ca mutatorul să primească mutarea – pentru că este posibil să fi făcut deja mutarea la capătul lor și nu vrei să o faci de două ori.
Așadar, am adăugat și o caracteristică interesantă (dacă doriți ca ambii jucători să primească mutarea, eliminați toate referințele la mSelfMoveSoph
): semaforul se mișcă de sine. De fiecare data sendMoveMsg
se numește, crește la mSelfMoveSoph
. Știm câte mișcări am încărcat acum cu acest semafor.
onChildAdded
este apelat ori de câte ori o mișcare este adăugată de Firebase. Ignoră mișcarea dacă semaforul are o valoare; în caz contrar, mMessageModulator
este chemat să interpreteze mișcarea și să o arate utilizatorului dvs. Modulator
este o interfață funcțională care este complementul codificatorului dvs. de mutare în șir. Este nevoie de acel șir încărcat în Firebase și îl convertește în mișcare.
Așteptați, asta nu va funcționa dacă utilizatorul primește un apel
Da, dacă utilizatorul primește un apel și aplicația dvs. este ucisă … cum va reveni utilizatorul la joc?
Din nou, să facem un Modulator
asa:
public class GenericGameFragment implements FirebaseGameSynchronizer.Modulator {
public void onMoveReceived(boolean isSyncingPast, String encodedMsg) { // ... do move, show it on UI .....
}
}
Acum se vor întâmpla două lucruri rele:
- Dacă utilizatorul pleacă,
FirebaseGameSynchronizer
va fi lăsat atașat la nod ascultându-l. Aceasta este o scurgere de utilizare a procesorului de memorie + CPU. -
FirebaseGameSynchronizer
va avea o referință la fragmentul dvs. – vedeți-l, Modulatorul trebuie să actualizeze interfața de utilizare și are o referință laGenericGameFragment
.
Sincronizarea și dezincronizarea cu nodul de mișcare
Am folosit o soluție relativ simplă la problemă. Este o combinație de două lucruri:
-
Steagul de sincronizare: Când setați proprietatea de sincronizare,
FirebaseGameSynchronizer
va apela modulatorul, în caz contrar, va stoca mutarea într-un buffer. La setarea din nou a steagului de sincronizare, eliberează mai întâi mișcările în bufferul său. -
Atașament: Modulatorul este eliminat ori de câte ori este fragmentul
onStop
metoda și a pus din nou pe fragmentonStart
.
Înainte de a utiliza acest „nou” sincronizator, nu uitați să apelați startSync()
. Pe onStop
, apel stopSync
si in onResume
apel startSync
din nou. Acum, ar trebui să sunați detachModulator
și flush
în onDestroy
.
Verificați acest link pentru implementarea completă: FirebaseGameSynchronization Gist.
Lecturi suplimentare: