Fruity Monster Multiplayer AndEngine Demo Code Walk Through
We will create a simple realtime multiplayer AndEngine game, Fruity Monster, by integrating with AppWarp.
Lets browse through the source code and walkthrough some of the key concepts in building this simple game.
First add the following to your application manifest.
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
Constants.java
To Run this sample code we need to replace api key and secret key in Constants.java
public static String apiKey = "Your API Key Here"; public static String secretKey = "Your Secret Key Here";
MainActivity
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
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 game.
Join 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 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.
Hashtableproperties = new Hashtable (); properties.put("topLeft", ""); properties.put("topRight", ""); properties.put("bottomLeft", ""); properties.put("bottomRight", ""); theClient.createRoom(""+System.currentTimeMillis(), "owner", 4, properties);
Once the room 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
This screen represents SimpleBaseGameActivity(andengine). In this we have defined hashmap to maintain online user those are playing same game. 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 implement RoomRequestListener and NotifyListener to register and listen 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.
sending update
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){ Hashtabletable = 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; } EnumerationkeyEnum = 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); } }