我在 Firebase 中做过类似的游戏。我通常使用onDataChange() 方法来验证每个客户端都知道gameRoom 的列表发生了变化。
如果你想创建一个动态数组列表,你必须使用onDataChange() 方法并在每次数组列表更改时使用它。如果数组列表已更改,您必须更新每个客户端数组列表。
存在很多竞争问题。
我的 firebase 数据库是这样的:
一般:
帐户用于登录信息,对于想要玩多人游戏的人来说是必须的
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;
如果我找到匹配项或匹配项列表,我会选择随机匹配项
我找到它并在 FirebaseDatabase 中设置了第二个用户
使用这个特定的字符串: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