Walk through of Space Warfare
SpaceWarFare is a sample game for AppWarp S2 with clients developed in Marmalade and Flash. Here we will be walking through the Marmalade code. The corresponding flash sample is similar.
Note You will first need to create an application zone first through the admin dashboard. This is described in in our getting started page.
In SpaceWarFare, there is a dragon which is always moving in the game. The player can shoot the dragon and kill him. Once dead, the dragon re-spawns after few seconds.
The dragon is a game object stored at server. Therefore every player seems him exactly at same location with same health. To create the dragon, we created a Class named DragonUser.
The Room adapter contains an object of DragonUser. The DragonUser class contains the logic for him. The dragon is updated continuously through handleTimerTick() method of room adapter.
First we implemented Server Adapter. In Server Adapter, every time a zone is created Zone Adapter is set to the newly created zone. In Zone Adapter, for every room created, we set the Room Adapter to the newly created room.
In room adapter we implemented two functions, handleTimerTick() and handleChatRequest(). In handleTimerTick(), the dragon is updated. In handleChatRequest() we analysis the chat messages. If the chat message says the player has hit the dragon, we reduce the dragon’s health. If his health goes below 0, he is declared as dead and removed from the game. After few seconds, the dragon is re-spawned.
Client Side
The client side has been developed for Marmalade using Cocos2d-X game engine. Appwarp S2 has full support for Marmalade platform. First we need to initialize the SDK, then set listeners and finally connect to the server.
AppWarp::Client *warpClient;
Edit the GameLayer.h and replace with your values of AppKey, Address and Room Id as described in the Getting Started wiki.
const std::string IP = "127.0.0.1"; const std::string API_KEY = "49130234-abf8-402b-b"; const std::string ROOM = "91586126";
Now in GameLayer.cpp
AppWarp::Client::initialize(API_KEY, IP); warpClient = AppWarp::Client::getInstance(); warpClient->setConnectionRequestListener(this); warpClient->setRoomRequestListener(this); warpClient->setNotificationListener(this); warpClient->connect(name,"");
Next we have to define, listeners. We are only using onConnectDone, onJoinRoomDone and OnChatRecieved, hence we need to define these only.
void onConnectDone(int res); void onJoinRoomDone(AppWarp::room revent); void onChatReceived(AppWarp::chat chatevent);
Whenever, our player moves a considerable, distance, we send his position to the server. The information is sent in JSON format, for which we have used cJSON. cJSON is already provided with AppWarp S2 SDK.
cJSON *json; json = cJSON_CreateObject(); cJSON_AddNumberToObject(json, "type", 1); cJSON_AddNumberToObject(json, "x", (int)player->getPositionX()); cJSON_AddNumberToObject(json, "y", (int)player->getPositionY()); cJSON_AddStringToObject(json, "name", name.c_str()); char* cRet = cJSON_PrintUnformatted(json); std::string message = cRet; free(cRet); warpClient->sendChat(message);
In JSON message, we are sending, type of message, here 1 means movement, x and y of position and the name of player. In this sample, we have used time stamp as name to connect. Next, when we tap on screen, bullets are shot. If any bullet hits the dragon which resides at server, we send a JSON message to represent the hit.
cJSON *json; json = cJSON_CreateObject(); cJSON_AddNumberToObject(json, "type", 2); cJSON_AddNumberToObject(json, "x", location.x); cJSON_AddNumberToObject(json, "y", location.y); cJSON_AddStringToObject(json, "p", "dragon"); char* cRet = cJSON_PrintUnformatted(json); std::string message = cRet; free(cRet); warpClient->sendChat(message);
Here, type = 2 and p=”dragon” is used to represent that dragon has been hit by the player’s bullet.
Whenever, the dragon moves on server, a chat message is sent to all players. We parse that information and reflect it on all clients. The server also sends the message in JSON format similar to the message sent by the Players. When we hit the dragon, his health is reduced by 1, if his health goes below 0, he is considered dead, server sends a message to all clients, telling that dragon has been killed and we remove it from the clients.
Similarly, all players are sending there position, the first time a message is received, we add him to the screen, and then every time other player’s position is received, we move him to his new position in our client side.
Server Side
To run this server side application, please first go through Running your first application. You need to follow the same steps for this sample as well. Following are details specific to this sample.
On server side, we need to implement adapters for server, zones and rooms. On server side, we have created a class named ‘DragonUser’ defined in file DragonUser.java. An instance of this Dragon is present in all rooms as we create the object for DragonUser in our Room Adaptor, which is assigned to all static rooms.
Our room adapter overrides the handleTimerTick() function of base class. You can define, the interval for timer in AppConfig.json file. In this function, after every 1 second, we move our dragon. If his health is below 0 i.e. he is dead, we wait for 10 seconds and re-spawn our dragon.
if(time - ticks > 1000){ if(dragon.GetHealth() > 0) { dragon.MoveRandomStep(100,100,2560-100, 1536-100); JSONObject tobeSent = new JSONObject(); try { tobeSent.put("name", "Dragon"); tobeSent.put("type", 1); tobeSent.put("x",dragon.GetX()); tobeSent.put("y", dragon.GetY()); tobeSent.put("health",dragon.GetHealth()); } catch(JSONException ex) { } m_room.BroadcastChat("dragon", tobeSent.toString()); ticks = time; } else if(time-ticks > 10000){ dragon.Spawn(20); dragon.SetPosition(1200, 800); ticks = time; } }
To send position of dragon, we use JSON with same format as the client is using to send his position. The JSON contains type = 1, representing that the message is describing a movement with x and y position of dragon and his health. Also, we have used name “dragon” while sending message to let clients now that dragon is moving.
Next, we have overridden, handleChatRequest() function to handle the chat messages received from clients. The clients send JSON messages with type = 2, representing they have shot someone along with “p” containing the name of person they have shot. So, in our handleChatRequest(), we check if type = 2 and p = ‘dragon’, then we reduce the health of our dragon by 1. And if the health becomes less than 0, the dragon is considered dead and we send this information to all clients.
JSONObject json = new JSONObject(message); if(json.getInt("type") == 2 && json.getString("p").equals("dragon")){ if(dragon.ReduceHealth() <= 0){ JSONObject tobeSent = new JSONObject(); try { tobeSent.put("name", "Dragon"); tobeSent.put("type", 3); } catch(JSONException ex) { } m_room.BroadcastChat("dragon", tobeSent.toString()); } }
When our dragon, dies, we send the JSON message with type = 3 representing death and name = "Dragon".