[英]Adding a multi-node ArrayList to Firebase Realtime-Database
I have been working on this multiplayer lobby for a few days now and I am STRUGGLING let me tell ya.我已经在这个多人游戏大厅工作了几天,我很挣扎,让我告诉你。
Anyways, I am reworking the problem on paper so I can have a step by step way to achieve what I am trying to do.无论如何,我正在纸上重新解决问题,以便我可以逐步实现我想要做的事情。 The simple steps to my lobby are as follows:
我的大厅的简单步骤如下:
So that is my current process but I am not sure if I am missing any steps.所以这是我目前的流程,但我不确定我是否遗漏了任何步骤。 Of course there is a lot of code behind these steps but this is just the jist of things.
当然,这些步骤背后有很多代码,但这只是事情的要点。
My question is how can I make it so that when a user creates a game, how can I have this properly added into an ArrayList that is in realtime and accessible to all users.我的问题是如何做到这一点,以便在用户创建游戏时,如何将其正确添加到所有用户都可以实时访问的 ArrayList 中。 Right now the ArrayList is not the same for all users.
现在 ArrayList 对所有用户都不同。 So if one person makes a game, that game is added to the realtime database, but it is not added to the list for each user.
因此,如果一个人制作了一款游戏,该游戏会添加到实时数据库中,但不会添加到每个用户的列表中。
How can I make a dynamic realtime ArrayList?如何制作动态实时 ArrayList?
This is currently the method that is adding the game to the database and to the list at the same time.这是目前将游戏同时添加到数据库和列表的方法。
gameMaker = new GameMaker(hp.uid, userName, wagerD, numGames);
cgRef.child(Integer.toString(numGames))
.setValue(gameMaker).addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Toast.makeText(FlipCoinLobby.this, "Game creation successful.", Toast.LENGTH_SHORT).show();
uName = gameRef.child("Username").toString();
openGames.add(numGames, uName);
adapter.notifyDataSetChanged();
} else {
Toast.makeText(FlipCoinLobby.this, task.getException().getMessage(), Toast.LENGTH_SHORT).show();
}
}
});
And my ArrayList is simply defined as this in the top of the class:我的 ArrayList 在类的顶部被简单地定义为:
ArrayList<String> openGames = new ArrayList<>();
I have done a similar game in Firebase.我在 Firebase 中做了一个类似的游戏。 I usually use
onDataChange()
method to verify that every client knows that the list of gameRoom
has changed.我通常使用
onDataChange()
方法来验证每个客户端都知道gameRoom
列表已更改。
user click Multiplayer用户点击多人游戏
If already exist an empty room, the client get in.如果已经存在一个空房间,则客户端进入。
If the other rooms are full or there isn't empty room, the client create a room如果其他房间已满或没有空房间,则客户端创建一个房间
when the matchmaking is done, let's start the match配对完成后,让我们开始比赛
when the match is closed, the first client modify the user variables and the second delete the entire room child.当比赛结束时,第一个客户端修改用户变量,第二个客户端删除整个房间的孩子。
If u want to make a dynamic arraylist, you have to use onDataChange()
method and use it every arraylist change.如果你想创建一个动态
onDataChange()
,你必须使用onDataChange()
方法并在每次数组列表更改时使用它。 If the arraylist has changed, u have to update each client arraylist.如果 arraylist 已更改,则必须更新每个客户端 arraylist。
There is a lot of problem of competition.有很多竞争问题。
My firebase database is this : General :我的 firebase 数据库是这样的: 一般:
Account is for the log-in info and is a must for who wanna play multiplayer帐户用于登录信息,对于想玩多人游戏的人来说是必须的
Every_Flag is a list of flags avaible for the multiplayer and downloaded by each client. Every_Flag 是多人游戏可用并由每个客户端下载的标志列表。 Inside the client code, there are every flag with specific multiplayer ID - 0,1,2 etc Easy to update.
在客户端代码中,每个标志都有特定的多人游戏 ID - 0,1,2 等 易于更新。
And finally the match :最后是比赛:
Database reference :数据库参考:
private DatabaseReference Matchmaking, Room,Accounts;
If the player logged in, the multiplayer button become accessible.如果玩家登录,多人游戏按钮变得可用。 This method is useful to get every match avaible or not inside the db :
此方法对于在 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();
}
}
}
}
And this is how i generate the match :这就是我生成匹配的方式:
//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;
}
First of all, i set all the variables.首先,我设置了所有变量。 uSer is the name that i get from google auth.
uSer 是我从 google auth 获得的名称。 If the room avaible is 0, i create the empty ROOM, generate the list of flags ( random 10 flags) and insert the child that it is a class :
如果房间可用为 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;
If i found a match or a list of match, i choose a random match i find it and i set the second user inside the FirebaseDatabase with this particular string : Matchmaking.child(second.getId()).setValue(second);
如果我找到一个匹配项或匹配项列表,我会选择一个随机匹配项,我找到它,并使用这个特定字符串在 FirebaseDatabase 中设置第二个用户:
Matchmaking.child(second.getId()).setValue(second);
Now, we get a new activity called MULTIPLAYER :现在,我们得到了一个名为 MULTIPLAYER 的新活动:
In this activity i create the multiplayer game, but let's see how I get all the information and set all the variables.在此活动中,我创建了多人游戏,但让我们看看如何获取所有信息并设置所有变量。 First of all i use onDataChange to pickup every change inside the match.
首先,我使用 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) {
}
});
When one of the two user press the button start, i change the database variable with this method :当两个用户之一按下按钮启动时,我使用此方法更改数据库变量:
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);
}
}
And this is when the user finish the match and press the backToMainMenu button :这是当用户完成比赛并按下 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();
}
};
And if the user wanna go out without finish the match :如果用户想不完成比赛就出去:
@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();
}
}
I hope that this will help you :D If u have any questions, I'll answer to you :D我希望这会帮助你:D 如果你有任何问题,我会回答你:D
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.