In this tutorial we show how to create an online multiplayer game based on preset tables.

 

We assume that the developer already owns an account into the ArenaDaemon web platform and

owns the knowledge for creating a new application and retrieving the correspondent appKey.

For more information about how to create a developer account and for setup a new application,

please refer to the chapter "Create an appKey".

 

When the developer wants to create an online multiplayer application, the very first thing to do is

to create tablesThe tables are entities to which the players can register in order to participate

to an online match.

A table has several properties one of which is maxPlayers that specifies the number of the seats

available for the match.

 

A table can be created through the ArenaDaemon web interface, in Dashboard/manage apps section

of a specific application :

 

multiplayer_create_table

 

  

We now create a new table called 'Classic' with 2 seats available :

 

multiplayer_create_table2

 

 

 

NOTE

 

The LIVE and SANDBOX checkboxes specify the environments to which the table belongs.

If the developer runs the mobile application in the SANDBOX environment (this can be done by

initializing the BDArenaConnector unique instance passing false to the second parameter of the

intializeWithAppKey() method) only the tables for which the SANDBOX

checkbox has been flagged, will be shown in the list of the available tables.

The same logic is applied for the LIVE environment.

 

 

Now that a table has been created, the coding of the mobile appication can start!

 

Create a new Android project and include the SDK as shown in chapter SDK Installation and setup.

 

The next step is to create :

  • Fragment that brings a ListView (we'll give it the name 'TablesFragment') through which the players will register to the tables.
  • Fragment that manages the match once started (we'll give it the name 'MatchFragment'). 

 

multiplayer_create_controllers_android

 

Before doing any action with the daemons, the local player needs to be authenticated so we need

to add the following code to the MainActivity class:

 

 

protected void onCreate(Bundle savedInstanceState){

         .....

        // init BDArenaConnector and register an object to observers

        BDArenaConnector.initializeWithAppKey(this, "YOUR_APP_KEY", true);

        BDArenaConnector.getInstance().registerEventsObserver(authHandler);

        BDArenaConnector.getInstance().requestAuth();

        .....

}

  

protected void onPause(){

        // unregister the handler object from observers

        BDArenaConnector.getInstance().unregisterEventsObserver(authHandler);

}

  

public void arenaConnectorAuthReceivedForLocalPlayerWithData(

    BDArenaPlayerData localPlayerData, boolean alreadyMet, boolean isOffline) {

 

        // show tables list

        TablesFragment tableFrag = new TablesFragment();

 

        getSupportFragmentManager().beginTransaction()

            .add(R.id.main_container, tableFrag)

            .commit();

 

}

 

public void arenaConnectorAuthFailedForLocalPlayerWithError(BDArenaError error) {

        // Handle errors

}

 

 

 

Now we can implement the TablesFragment by adding an ArrayList to store

the list of available tables:

 

 

public class TablesFragment extends Fragment {

 

        private BDArenaConnectorAdapter arenaConnectorHandler;

 

        private ListView tablesList;

        private TextView infoLabel;

 

        private ArrayList<BDArenaTableData> tablesArray;

        ....

 

 

 

In order to be notified about SDK events and to let the app connect to the Multiplayer Daemon,

in the onStart method of TablesFragment we add:

 

 

public void onStart() {

        super.onStart();

 

        arenaConnectorHandler = new ArenaPlayHandler();

        BDArenaConnector.getInstance().registerEventsObserver(arenaConnectorHandler);

 

        if(BDArenaConnector.getInstance().getPlayConnector().isConnected() == false)

                BDArenaConnector.getInstance().getPlayConnector().connect();

        else

                refreshTablesList();

}

 

 

 

Once the Fragment is paused, we need to remove the handler from observers:

 

 

public void onPause() {

        super.onPause();

        BDArenaConnector.getInstance().unregisterEventsObserver(arenaConnectorHandler);

}

 

 

For managing the results of the above requests, we need to implement

arenaPlayRequestDidFail()arenaPlayConnectionEstabilished()arenaPlayConnectionFailed() and 

arenaPlayTablesListReceived() 

 

As you can see in the code above, we use a SimpleAdapter for showing retrieved tables list.

 

 

@Override

public void arenaPlayRequestDidFail(

    BDArenaPlayConnector playConnector, BDArenaError error) {

        // handle error here

        // ...

 

        // refresh tables list after 1 sec

        refreshTablesList();

}

 

@Override

public void arenaPlayConnectionFailed(BDArenaError error) {

        // handle error here

        // ...

 

        // refresh tables list after 1 sec

        refreshTablesList();

}

 

@Override

public void arenaPlayConnectionEstablished() {

 

        // connection established. Request tables list

        BDArenaConnector.getInstance().getPlayConnector().getTablesList();

 

}

 

@Override

public void arenaPlayTablesListReceived(

    BDArenaPlayConnector connector, List<BDArenaTableData> tables,

    int activeMatches, int activePlayers) {

 

        // show active matches and players

        infoLabel.setText(activePlayers + " active players | " +

            activeMatches + " active matches");

 

        // tables list received. Fill tablesArray

        tablesArray = new ArrayList<BDArenaTableData>(tables);

 

        ArrayList<HashMap<String, String>> tablesMapArray =

            new ArrayList<HashMap<String,String>>();

       

        for(BDArenaTableData table : tablesArray){

 

               HashMap<String, String> tableMap = new HashMap<String, String>();

               tableMap.put("name", table.getSymbolicName());

               tableMap.put("registered", (table.isAlreadyRegistered() ? "unregister" : "register"));

               tableMap.put("seats", table.getRegisteredPlayers() + "/" +

                   table.getMaxPlayers());

 

               tablesMapArray.add(tableMap);

 

        }

 

        // refresh tableList

        SimpleAdapter listAdapter = new SimpleAdapter(getActivity(), tablesMapArray,

            R.layout.tables_list_item

            new String[]{"name", "registered", "seats"}, 

            newint[]{R.id.table_name, R.id.register_label, R.id.seats_available_label});

 

        tablesList.setAdapter(listAdapter);

 

        // refresh tables list after 1 sec

        refreshTablesList();

 

}

 

 

In order to register the local player to a table for partecipating the match, we need to call

registerToTableWithId() and 

unregisterFromTableWithId(),

retrieving the results implementing 

arenaPlayRegistrationToTableSuccessfullyCompleted(),

arenaPlayAlreadyRegisteredToTable(),

arenaPlayUnregistrationSuccessfullyCompletedFromTable(),

arenaPlayUnregistrationFailedFromTable() and

arenaPlayNotRegisteredToTable()

 

The application now looks as follow :

tutorial_multiplayer_screens

 

The match will start when both seats will be occupied by the players.

When this event will occur, the application will be notified through arenaPlayMatchDidStart() interface method.

 

 

@Override

public void arenaPlayMatchDidStart(

    BDArenaPlayConnector connector, BDArenaMatchData matchInfo) {

 

        // start match

       MatchFragment matchFrag = new MatchFragment();

       matchFrag.setMatchData(matchInfo);

 

       getFragmentManager().beginTransaction()

           .add(R.id.main_container, matchFrag)

           .addToBackStack("match")

           .commit();

 

}

 

 

The MatchFragment presents a ListView, through which are listed the participants

to the match.

 

Within this Fragment, the developer must implement the main logic of his game

by communicating with remote players through sendMessageToPlayerInMatch() or 

sendMessageToAllPlayersInMatch() methods.

 

If the local player wants to leave the current match, he needs to call leaveMatchWithId() method

before the application pauses the MatchFragment.

 

For all the participants to a match, all the events can be managed by implementing 

arenaPlayMessageSuccessfullySentInMatch(),

arenaPlayNewMessageReceivedInMatch(),

arenaPlayMatchSuccessfullyLeft(),

arenaPlayLeaveMatchWithIdDidFailWithError(),

arenaPlayPlayerLeftMatch() and

arenaPlayPlayersListReceivedForMatch()

 

This sample project implements a Tic-Tac-Toe game and the MatchFragment looks like follows:

tutorial_multiplayer_ttt

 


 

 

Sample project

Download the sample project for this tutorial.