Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

Make Realtime Multiplayer AndEngine Games

0.00/5 (No votes)
25 Jun 2013CPOL4 min read 23K  
Adding realtime multiplayer game play and virtual rooms logic to your AndEngine games

Introduction

AndEngine is a free Android 2D OpenGL Game Engine. Using AppWarp, you can add realtime multiplayer game play and virtual rooms logic to your AndEngine games. In this post, we will walk through the integration steps for a simple demo game called Fruity Monster. Players connect to AppWarp cloud, can create rooms or join existing rooms. Once inside a room, players can see each other move in realtime and place fruits to the four corners of the room.

Using the Code

Let's browse through the source code and walk through some of the key concepts in building this simple game.

First edit Constants.java file with your AppWarp keys as indicated below:

Java
public static String apiKey = "Your API Key Here";
public static String secretKey =  "Your Secret Key Here";

Now let's walk through each screen and examine the integration code.

MainActivity.java

In this screen, we initialize WarpClient with the developer's API key and secret key that we have defined in Constants.java. We then keep a reference of this instance that we will use in this activity.

Java
private void init(){
    WarpClient.initialize(Constants.apiKey, Constants.secretKey);
    try {
        theClient = WarpClient.getInstance();
    } catch (Exception ex) {
        Utils.showToastAlert(this, "Exception in Initialization");
    }
}

Once WarpClient is initialized, we go ahead and connect with AppWarp Cloud Service. This happens when the user selects a monster, enters a name and clicks on the play button. In order to receive callback result from the connect operation, we need to add a connection request listener. We make the MainActivity class implement the ConnectionRequestListener and implement the required methods.

Java
theClient.connectWithUserName(userName);

If we get a successful callback for this operation, we go ahead and enter the RoomlistActivity.

Java
@Override
public void onConnectDone(final ConnectEvent event) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            progressDialog.dismiss();
            if(event.getResult()==WarpResponseResultCode.SUCCESS){// go to room  list 
                Intent intent = new Intent(MainActivity.this, RoomlistActivity.class);
                startActivity(intent);
            }else{
                Utils.showToastAlert(MainActivity.this, "connection failed ");
            }
        }
    });
}

RoomListActivity.java

This screen shows a list of active game rooms to the user. The list contains rooms with at least one user. We use our matchmaking API to build this list.

Java
theClient.getRoomWithNUser(1);// trying to get room with at least one user

The user has the option to either join a room from this list or to start a new room.

Join An Existing Room

To receive the callback for the above request, we need to add a zone request listener as this is a zone level request. We make the RoomlistActivity implement the zone request listener interface and add itself as the listener. In the callback, we set up the list adapter with the room ids of all the matched rooms.

Java
@Override
public void onGetMatchedRoomsDone(final MatchedRoomsEvent event) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            RoomData[] roomDataList = event.getRoomsData();
            if(roomDataList.length>0){
                roomlistAdapter.setData(roomDataList);
                listView.setAdapter(roomlistAdapter);
            }else{
                roomlistAdapter.clear();
            }
        }
    });
}

Join a New Room

To join a new room, we first need to create a room with the defined properties before joining it. In this game, we are defining four locations in a room which will be used later in the game play. This will simply create a new room with the name given (random in this case) by the user and specify maxUsers as 4 and the local user as the owner. The result of the request will be invoked on our zone request listener interface.

Java
Hashtable<String, Object> properties = new Hashtable<String, Object>();
properties.put("topLeft", "");
properties.put("topRight", "");
properties.put("bottomLeft", "");
properties.put("bottomRight", "");
theClient.createRoom(""+System.currentTimeMillis(), "owner", 4, properties);

Once the room is created successfully, we extract the room id from the event and join that room. Similarly, if the user clicks on the join button of one of the rooms from the list, we go ahead and send a join room request.

Java
theClient.joinRoom(roomId); 

The result of the request will be invoked on our room request listener interface. If successful, we move to the next activity.

Java
@Override
public void onJoinRoomDone(final RoomEvent event) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            progressDialog.dismiss();
            Log.d("onJoinRoomDone", ""+event.getResult());
            if(event.getResult()==0){// Room created successfully
                goToGameScreen(event.getData().getId());
            }else{
                Utils.showToastAlert(RoomlistActivity.this, "Room joining failed");
            }
        }
    });
}

AndEngineTutorialActivity.java

This screen represents SimpleBaseGameActivity(andengine). In this, we have defined hashmap to maintain online users that are playing game in this room. We initialize andengine in onCreateEngineOptions() and load all resources used in game in onCreateResources()

To handle all events in game, we have used EventHandler.java which implements RoomRequestListener and NotifyListener to register and listens to all the relevant game events. Whenever the user taps on the screen, we need to notify other players in the room of its movement. We do this by simply constructing a json object representing the coordinates and send that using the WarpClient chat API.

Java
private void sendUpdateEvent(float xCord, float yCord){
    try{
        JSONObject object = new JSONObject();
        object.put("X", xCord+"");
        object.put("Y", yCord+"");
        theClient.sendChat(object.toString());
    }catch(Exception e){
        Log.d("sendUpdateEvent", e.getMessage());
    }
}

The above code will trigger a chat event whose notification will be received by all those inside the room in EventHandler.java.

Java
@Override
public void onChatReceived(ChatEvent event) {
    String sender = event.getSender();
    if(sender.equals(Utils.userName)==false){// if not same user
        String message = event.getMessage();
        try{
            JSONObject object = new JSONObject(message);
            float xCord = Float.parseFloat(object.get("X")+"");
            float yCord = Float.parseFloat(object.get("Y")+"");
            gameScreen.updateMove(sender, xCord, yCord);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

Now players can move fruits to the four corners of the rooms and others can see all this happen in realtime. To do this, the user selects a fruit and then presses on any corner where he has to put the fruit. Then we send an updateRoomProperty request in which we update the property whose key represent destination e.g.(topLeft) and value is index of fruit.

Java
private void updateProperty(String position, String objectType){
	Hashtable table = new Hashtable();
	table.put(position, objectType);
	theClient.updateRoomProperties(roomId, table, null);
} 

Finally, all users get a notification in EventHandler.java when a property of the room changes. It the property is updated by a remote user, then we update UI with this new value according to the property values in the event.

Java
@Override
public void onUserChangeRoomProperty(RoomData roomData, String userName,Hashtable properties) {
    if(userName.equals(Utils.userName)){
        properties = tableProperties;
        return;
    }
    Enumeration keyEnum = properties.keys();
    while(keyEnum.hasMoreElements()){
        String key = keyEnum.nextElement();
        String value = properties.get(key).toString();
        int fruitId = Integer.parseInt(value);
        gameScreen.placeObject(fruitId, key, userName);
    }
}

History

  • 25th June, 2013: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)