简体   繁体   English

将多节点 ArrayList 添加到 Firebase Realtime-Database

[英]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:我的大厅的简单步骤如下:

  1. A user clicks a 'create game' button用户单击“创建游戏”按钮
  2. That button calls a createGame method which adds a node into my openGames root in my RealTime Database该按钮调用 createGame 方法,该方法将节点添加到我的实时数据库中的 openGames 根目录中
  3. That node has more children such as the username, the user id, the index of the game in a list, and some other things.该节点有更多子节点,例如用户名、用户 ID、列表中游戏的索引以及其他一些内容。
  4. This game which is indexed in an arraylist, is drawn onto the screen through RecyclerView这个在数组列表中索引的游戏,通过 RecyclerView 绘制到屏幕上

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM