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:
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 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.
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){
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);
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 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.
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){
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.
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){
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.
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);
}
}
History
- 25th June, 2013: Initial version