Friday, June 28, 2013

Make realtime multiplayer AndEngine games

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.


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:
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.
private void init(){
    WarpClient.initialize(Constants.apiKey, Constants.secretKey);
    try {
        theClient = WarpClient.getInstance();
    } catch (Exception ex) {
        Utils.showToastAlert(this, "Exception in Initilization");
    }
}
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.
theClient.connectWithUserName(userName);
If we get a successful callback for this operation, we go ahead and enter the RoomlistActivity.
@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.
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.
@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 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.
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.
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.
@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 user those are playing game in this room. We initilize andengine in onCreateEngineOptions() and load all resources used in game in onCreateResources()
To handle all event 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.
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
@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 the press 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.
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.
@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);
    }
}
The Original source for this blog is an article posted on Codeproject: http://www.codeproject.com/Articles/611201/Make-realtime-multiplayer-AndEngine-games

No comments:

Post a Comment