Я сделал похожую игру в Firebase.Я обычно использую метод onDataChange()
, чтобы убедиться, что каждый клиент знает, что список gameRoom
изменился.
пользователь щелкает Мультиплеер
Если пустая комната уже существует, клиент получает ее.
Если другие комнаты заполнены или нет пустой комнаты, клиент создает комнату
когда сопоставление завершено, давайте начнем совпадение
когда совпадение закрыто, первый клиент изменяет пользовательские переменные, а второй удаляет весь дочерний элемент комнаты.
Если вы хотите создать динамический массив, вы должны использовать метод onDataChange()
и использовать его при каждом изменении массива.Если arraylist изменился, вы должны обновить каждый клиентский arraylist.
Существует много проблем конкуренции.
Моя база данных firebase: General: 
Учетная запись предназначена для входа в систему и необходима для тех, кто хочет играть в мультиплеер 
Every_Flag - это список флагов, доступных для мультиплеера и загружаемых каждым клиентом.Внутри клиентского кода есть каждый флаг с определенным многопользовательским ID - 0,1,2 и т. Д. Легко обновить.
И наконец совпадение:

Ссылка на базу данных:
private DatabaseReference Matchmaking, Room,Accounts;
Если игрок вошел в систему, многопользовательская кнопка станет доступной.Этот метод полезен, чтобы получить каждое совпадение, доступное или нет внутри db:
//metodo per la gestione dei cambiamenti della tabella Matchmaking
Matchmaking.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
//nel caso ci siano delle modifiche alla tabella
//se il match non è stato trovato e Account è stato verificato
if(accountFound){
//azzero la Lista
List_party = new ArrayList<>();
Id_rooms = new ArrayList<>();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
//sempre se matchfound non è stato trovato
if (!currentwithID.getMatch_found()) {
//prendo la quantità di figli presenti
size = Integer.parseInt(String.valueOf(dataSnapshot.getChildrenCount()));
//inserisco all'interno della variabile CT il valore di ogni figlio
ct = ds.getValue(Class_party.class);
// e se è il numero di giocatori == 1 e la partita non è iniziata e finita in modo anomalo
if (ct.getNumberOfPlayers() == 1 && !ct.getStart() && ct.getCorrect_end() && ct.getAccessible()) {
//aggiungo l'id della room alla lista
//Inserisco alla list_party l'intero oggetto
Id_rooms.add(ct.getId());
List_party.add(ct);
}
Toast.makeText(HomeActivity.this, "Lista ROOMs aggiornata", Toast.LENGTH_SHORT).show();
}
}
}
}
И вот как я генерирую совпадение:
//MATCHMAKING
public void Create(View view)
{
boolean start = false;
boolean correct_end = true;
boolean accessible = true;
uSer = user.getDisplayName();
//se la lunghezza delle partite disponibili a cui accedere è ==0
if(size==0||Id_rooms.size()==0)
{
//creo la chiave univoca per il match
String id = Matchmaking.push().getKey();
//creo un utente corrente con nome e punteggio
current=new Class_user(uSer,0);
//un utente con ID utente, nome e se il match è stato trovato
//genero le domande che verranno utilizzato solo per quel determinato match
list_game= Generation();
//ora creo il match vero e proprio e lo inserisco nella tabella matchmaking
second = new Class_party(id, current, list_game,start,correct_end,accessible);
Matchmaking.child(id).setValue(second); }
else{
accessible = false;
// se invece ci sono delle partite disponibili, le randomizzo
Collections.shuffle(Id_rooms);
for(int i=0; i<List_party.size();i++)
{
//le passo tutte finché non trovo quella con l'ID corrispondente alla prima che ho randomizzato
if(List_party.get(i).getId()==Id_rooms.get(0))
{
// popolo la variabile class_party
second=new Class_party(List_party.get(i).getId(),List_party.get(i).getUser1(),List_party.get(i).getFlag(),start,correct_end,accessible);
}
}
matchFound = false;
//inserisco l'utente e il numero di giocatori = 2
currentwithID = new Class_user(uID,uSer,matchFound);
current=new Class_user(uSer,0);
second.setUser2(current);
second.setNumberOfPlayers(2);
//ora reinserisco tutto nel figlio che ha come ID, quello della stanza selezionata
Matchmaking.child(second.getId()).setValue(second);
Accounts.child(uID).setValue(currentwithID);
}
}
public ArrayList<Integer> Generation()
{
ArrayList<Integer> tmp = new ArrayList<>();
Collections.shuffle(mFlag);
for(int i=0; i<=10; i++) //3 momentaneamente
{
tmp.add(mFlag.get(i));
}
Toast.makeText(HomeActivity.this,"Domande generate",Toast.LENGTH_LONG).show();
return tmp;
}
Прежде всего, я установил всепеременные.uSer - это имя, которое я получаю от Google Auth.Если номер комнаты равен 0, я создаю пустую КОМНАТУ, генерирую список флагов (случайные 10 флагов) и вставляю дочерний элемент, что это класс:
public class Class_party {
public Class_user user1, user2;
public int numberOfPlayers;
public String id;
public ArrayList<Integer> value;
public boolean start,correct_end,accessible;
public Class_party(String id,Class_user user1, ArrayList<Integer> value, Boolean start,Boolean correct_end, Boolean accessible) {
this.value = value;
this.user1 = user1;
this.numberOfPlayers = 1;
this.id = id;
this.start = start;
this.accessible = accessible;
this.correct_end = correct_end;
user2 = null;
}
public Class_party() {
}
public Class_user getUser1() {
return user1;
}
public void setUser1(Class_user user1) {
this.user1 = user1;
}
public Class_user getUser2() {
return user2;
}
public void setUser2(Class_user user2) {
this.user2 = user2;
}
public int getNumberOfPlayers() {
return numberOfPlayers;
}
public void setNumberOfPlayers(int numberOfPlayers) {
this.numberOfPlayers = numberOfPlayers;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public ArrayList<Integer> getFlag() { return value; }
public void setValue(ArrayList<Integer> value) {
this.value=value;
Если я нашел совпадение или списоксоответствия, я выбираю случайное соответствие, я нахожу его и устанавливаю второго пользователя в базе данных FirebaseD с этой конкретной строкой: Matchmaking.child(second.getId()).setValue(second);
Теперь мы получаем новое действие с именем MULTIPLAYER:
В этом упражнении я создаю многопользовательскую игру, но давайте посмотрим, как я получаю всю информацию и устанавливаю все переменные.Прежде всего, я использую onDataChange, чтобы забрать каждое изменение в матче.
Matchmaking.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
//prendo tutte le tabelle e le aggiungo a list_party
for (DataSnapshot ds : dataSnapshot.getChildren()) {
ct = ds.getValue(Class_party.class);
List_party.add(ct);
}
// mi prendo la partita che mi interessa
for (int i = 0; i < List_party.size(); i++) {
if (List_party.get(i).getId() == intent_id) {
ct = List_party.get(i);
}
}
//controllo che gli utenti collegati siano due e che la partita non sia cominciata ne finita in modo anomalo
if (ct.getNumberOfPlayers() == 2 && !ct.getAccessible() && ct.getCorrect_end() && !ct.getStart()) {
//mi scarico le bandiere che sono state scelte alla creazione della ROOM
FlagsFromDB = ct.getFlag();
//passo dal Layout di Waiting a quello iniziale
switchToScreen(R.id.screen_intro);
matchFound=true;
Toast.makeText(MpMultiplayer.this, "Match Found", Toast.LENGTH_SHORT).show();
//imposto il match trovato = true
currentwithID.setMatch_found(true);
//aggiorno la tabella
Accounts.child(uID).setValue(currentwithID);
}
//se la partita è cominciata e il numero di giocatori è uguale a due e match_found = true
if (ct.getStart() && ct.getNumberOfPlayers()==2 && matchFound) {
//dico che la room è stata creata
roomcreated = true;
//ora il gioco comincia e cambio di layout
switchToScreen(R.id.screen_game);
Popolate();
}
//se qualcuno esce prima del previsto e la partita è già cominciata
if(!ct.getCorrect_end() && roomcreated)
{
//assegno automaticamente all'utente 500 punti
points += 500;
timer1.cancel();
mName.setText(intent_user + " You Won!");
mName.setTextSize(25);
mPoints.setText(new Integer(points).toString());
switchToScreen(R.id.screen_score);
Toast.makeText(MpMultiplayer.this, "The player LEFT the game", Toast.LENGTH_SHORT).show();
}
//se l'utente si è scollegato e la partita non è ancora cominciata
if(!ct.getCorrect_end() && !roomcreated)
{ //assegno automaticamente 100 punti
points += 100;
mName.setText(intent_user + "You Won!");
mName.setTextSize(25);
mPoints.setText(new Integer(points).toString());
switchToScreen(R.id.screen_score);
Toast.makeText(MpMultiplayer.this, "The player LEFT the game", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
Когда один из двух пользователей нажимает кнопку запуска, я изменяю переменную базы данных следующим способом:
void ChangeStartValue(){
Room = FirebaseDatabase.getInstance().getReference("Matchmaking");
try {
ct.setStart(true);
Room.child(ct.getId()).setValue(ct);
} catch (Exception e) {
e.printStackTrace();
}
}
void switchToScreen(int screenId) {
// make the requested screen visible; hide all others.
for (int id : SCREENS) {
findViewById(id).setVisibility(screenId == id ? View.VISIBLE : View.GONE);
}
}
И это когда пользователь заканчивает матч и нажимает кнопку backToMainMenu:
private View.OnClickListener backtomainmenu = new View.OnClickListener() {
@Override
public void onClick(final View view) {
try {
if(ct.getNumberOfPlayers()==2){
ct.setNumberOfPlayers(ct.getNumberOfPlayers()-1);
Room.child(ct.getId()).setValue(ct);
Accounts.child(uID).child("match_found").setValue(false);
}
else
if (ct.getNumberOfPlayers()==1 && ct.getStart()&& ct.getCorrect_end()){
Room.child(ct.getId()).removeValue();
Accounts.child(uID).child("match_found").setValue(false); }
else
if(ct.getNumberOfPlayers()==1 && ct.getStart() && !ct.getCorrect_end()){
Room.child(ct.getId()).removeValue();
Accounts.child(uID).child("match_found").setValue(false);}
else
if(ct.getNumberOfPlayers()==1 && !ct.getStart() && !ct.getCorrect_end()) {
Room.child(ct.getId()).removeValue();
Accounts.child(uID).child("match_found").setValue(false);}
} catch (Exception e) {
e.printStackTrace();
}
finish();
}
};
И если пользователь хочет выйти без окончания матча:
@Override
//in caso l'utente voglia uscire
public void onBackPressed() {
backpress = (backpress + 1);
// se preme una volta compare il toast
if (backpress >= 1 && backpress < 2)
Toast.makeText(getApplicationContext(), " Press Back again to Exit ", Toast.LENGTH_SHORT).show();
//se preme per più di una volta esce
if (backpress > 1) {
try {
//se i giocatori sono più di due, setto i giocatori ad 1 e Correct End a false
if(ct.getNumberOfPlayers()>=2){
ct.setNumberOfPlayers(ct.getNumberOfPlayers()-1);
ct.setCorrect_end(false);
//aggiorno poi le tabelle
Room.child(ct.getId()).setValue(ct);
Accounts.child(uID).child("match_found").setValue(false);
}
else
//se il giocatore è da solo
if(ct.getNumberOfPlayers()<2)
{
//cancello il figlio dalla tabella matchmaking
Room.child(ct.getId()).removeValue();
Accounts.child(uID).child("match_found").setValue(false);
}
} catch (Exception e) {
e.printStackTrace();
}
//se poi la partita era già cominciata, cancello il timer per evitare errori
if(roomcreated)
timer1.cancel();
//chiudo l'activity
this.finish();
}
}
Я надеюсь, чтоэто поможет вам: D Если у вас есть какие-либо вопросы, я отвечу вам: D