RUBE exports its level information in a neat and tidy JSON file. We can create a complete physics world from this exported JSON file by using a JSON parser along with a class called b2dJson
. You can find the required files in the RUBE download package as well as in the source bundle for this chapter.
Before we go ahead, let's discuss how our Box2D world will be created for this chapter. We will split the world creation into two main functions: CreateWorld
and CreateGameObjects
. In the CreateWorld
function, we will use the b2dJson
class to create a b2World
object, based on data exported from RUBE. In the CreateGameObjects
function, we will create sprites for all the physics bodies within the world.
Without further ado, let's begin with some code. This is the CreateWorld
function from GameWorld.cpp
:
void GameWorld::CreateWorld(b2dJson* json, int level) { // get file data and parse it to get b2dJson char buf[32] = {0}; sprintf(buf, "Level%02d.json", level); //sprintf(buf, "testing.json"); unsigned long size; char* data_uc = (char*)CCFileUtils::sharedFileUtils()-> getFileData(buf, "rb", &size); // error message std::string msg = "could not load file"; world_ = json->readFromString(data_uc, msg); // tell world we want to listen for collisions world_->SetContactListener(this); // delete char buffer delete data_uc; #ifdef ENABLE_DEBUG_DRAW debug_draw_ = new GLESDebugDraw(PTM_RATIO); world_->SetDebugDraw(debug_draw_); uint32 flags = 0; flags += b2Draw::e_shapeBit; flags += b2Draw::e_jointBit; debug_draw_->SetFlags(flags); #endif }
The CreateWorld
function is called when GameWorld
is created, and takes a pointer to a b2dJson
object along with the level number. In this function, we generate the name for the respective level file and use the getFileData
function from CCFileUtils
to read the file's contents.
We then pass the file data into the readFromString
function of class b2dJson
, which will return a pointer to a newly created b2World
object. This is how simple it is to generate a physics world using the data exported from RUBE. We wind up this function by setting GameWorld
as the contact listener and setting up debug draw like you've seen in previous chapters.
The b2dJson
class provides an extensive set of functions that can be used to query almost everything related to the physics world it created using the data exported from RUBE. We will use some of the functions to save references to a few relevant bodies and extract the custom properties we set in the editor.
Let's take a look at how this is done in the CreateGameObjects
function from GameWorld.cpp
:
void GameWorld::CreateGameObjects(b2dJson* json) { // save references to a few important bodies boundary_body_ = json->getBodyByName(string("ground")); catapult_body_ = json->getBodyByName(string("catapult")); catapult_joint_ = (b2RevoluteJoint*)json->getJointByName( string("catapult_joint")); // extract the list of fish (comma separated string) for this level fish_list_ = json->getCustomString((void*)world_, "ListOfFish", ""); // get all bodies from the world that have a sprite name i.e. GameObjects b2Body* body_in_list = world_->GetBodyList(); while(body_in_list != NULL) { string sprite_name = json->getCustomString((void*)body_in_list, "SpriteName", ""); if(sprite_name.compare("")) { // append file extension...sorry we don't have spritesheets at the moment! :( sprite_name = sprite_name + ".png"; // see if this game object is a cat if(json->getCustomBool((void*)body_in_list, "IsCat", false)) { // create the Cat Cat* cat = Cat::create(this); // save the body cat->SetBody(body_in_list); // add & save this Cat addChild(cat, E_LAYER_CATS); cats_.push_back(cat); ++ num_cats_; } else { // create the GameObject with the respective sprite name GameObject* game_object = GameObject::create(this, sprite_name.c_str()); // save the body game_object->SetBody(body_in_list); // add & save this GameObject addChild(game_object, E_LAYER_OBJECTS); game_objects_.push_back(game_object); ++ num_game_objects_; } } // continue checking body_in_list = body_in_list->GetNext(); } // reorder catapult to be above the fish reorderChild((CCSprite*)catapult_body_->GetUserData(), E_LAYER_FISH + 1); }
The CreateGameObjects
function is called when GameWorld
is created, and accepts a pointer to a b2dJson
object. We begin by storing references to the bodies of the ground and the catapult, followed by a reference to the catapult's b2RevoluteJoint
object.
We then extract the world's custom property with the name of ListOfFish
by calling the getCustomString
function of the b2dJson
class. This function accepts a void*
object, so we can use this very function to get the custom properties for our b2Body
objects as well. This will return a std::string
object that we will use when creating the set of Fish
objects for a particular level.
We then iterate through the list of bodies, looking for bodies that possess the SpriteName
custom property; this will tell us which bodies need GameObject
objects created. Within this loop, we also compare the value of the IsCat
custom property by calling the getCustomBool
function and, passing in the current b2Body
object. If this value is true
, we create an object of the Cat
class; otherwise, we create an object of the GameObject
class. We also add the object created to the respective list belonging to the GameWorld
class. To wind up the CreateGameObjects
function, we reorder the catapult's sprite so that it is rendered on top of the fish.
Now that we have created the game's physics world and all the GameObjects
, using the data exported from RUBE, we can define the behavior of the different kinds of fish.
18.118.20.231