Skip to content

4c. Connecting with cocos2d x

fyf edited this page Aug 21, 2014 · 1 revision

Connecting with cocos2d-x

For any non-trivial use of CocosBuilder you will need to connect your ccb-files with your code. This section explains how this works.

Using Custom Classes

The way you can link your code with CocosBuilder is to use custom classes. To assign a custom class to an object in CocosBuilder, just select the object then enter the name of your custom class in the property inspector. Remember that your custom class needs to be a sub class of the selected object.

When loading the ccbi-file, you need to create two custom classes (could be one). The custom loader class derives from cocos2d::extension::CCLayerLoader.

The custom layer class derives from cocos2d::extension::CCBSelectorResolver ,cocos2d::extension::CCBMemberVariableAssigner , and cocos2d::extension::CCNodeLoaderListener classes.

In your custom loader class you need to add code for initialization such as

public:
	CCB_STATIC_NEW_AUTORELEASE_OBJECT_METHOD(CustomLayerLoaderClass, loader);
	CCB_VIRTUAL_NEW_AUTORELEASE_CREATECCNODE_METHOD(CustomLayerClass));

CCBReader will initialize your custom layer class using the loader class's loader method.

image

Please note that CCBReader will not be able to use any custom init methods. To use a custom init method, you can call it from the custom layer class constructor.

Linking Member Variables

References to objects in your ccbi-file can be linked to member variables when the file is loaded. These member variables can be either in the root node of the document, in which case it must have been assigned a custom class.

image

To link an object, simply declare them in the header file,

To initialize member variables, you can override the onAssignCCBMemberVariable function in the custom layer class and use something like

CCB_MEMBERVARIABLEASSIGNER_GLUE(this, "sprtBurst", CCSprite *, this->mSprtBurst);

where sprtBurst is the property name set in CocosBuilder.

Select the object in CocosBuilder, under Code Connections change the Don't assign popup menu to either Doc root var or Owner var. Then enter the name of your member variable to the right of the popup menu.

Adding Callbacks to Menus

To add a callback when a CCMenuItemImage is tapped, simply select the CCMenuItemImage in CocosBuilder, then add the name of the method you want to call in the Selector field. Set the target either to the Document root or the Owner.

image

The callback will send the CCMenuItemImage as its only parameter to the method that you specify (it uses the id type, and is often named sender). You can also chose to leave the parameter out.

In your custon class, you override the onResolveCCBCCMenuItemSelector function and add code such as

CCB_SELECTORRESOLVER_CCMENUITEM_GLUE(this, "pressedA:", MenuTestLayer::onMenuItemAClicked);

inside the function.

where MenuTestLayer is the name of your custom class.

MenuTestLayer::onMenuItemAClicked can then be declared as

void MenuTestLayer::onMenuItemAClicked(cocos2d::CCObject *pSender) {
}

Adding Callbacks to CCControl

Adding a callback to a CCControl is similar to adding a callback to a CCMenuItemImage, it just have a few extra options.

image

Tick the event types that you want to receive callbacks for. For CCControlButton it is most common to use the Up inside callback only. Select your target, either Document root or Owner, and the name of your callback method. The callback method can optionally take two arguments, the sender (i.e. the CCControl) and the type of event. The event types are defined in CCControl.h.

In the custom class, you override the onResolveCCBCCControlSelector function and add code such as

CCB_SELECTORRESOLVER_CCCONTROL_GLUE(this, "pressedMenus:", MenuTestLayer::onPressedMenus);

inside the function. Where MenuTestLayer is the name of your custom class.

MenuTestLayer::onPressedMenus can then be declared as

void HelloCocosBuilderLayer::onMenuTestClicked(CCObject * pSender, cocos2d::extension::CCControlEvent pCCControlEvent) {
}

Options for Loading ccb-files

CocosBuilder documents, or ccb-files, needs to be published into a compact binary format, ccbi, before they can be loaded into your application. Once published they can be easily loaded with a single line of code. To load a node graph, add the CCBReader.h and CCBReader.m files to your Cocos2D project, then call the nodeGraphFromFile: method as follows.

CCBReader *ccbReader = new cocos2d::extension::CCBReader(ccNodeLoaderLibrary); 
CCNode* myNode = ccbReader->readNodeGraphFromFile("MyNodeGraph.ccbi");

The initialization for ccNodeLoaderLibrary can be done in two ways.

  1. If you're using a custom class:

     CCNodeLoaderLibrary * ccNodeLoaderLibrary = CCNodeLoaderLibrary::newDefaultCCNodeLoaderLibrary(); 
     
     ccNodeLoaderLibrary->registerCCNodeLoader("HelloCocosBuilderLayer", HelloCocosBuilderLayerLoader::loader());
    

    In this case, HelloCocosBuilderLayer is the name of the custom class specified in CocosBuilder

  2. If not using a custom class, you can initialize a default NodeLoader:

         CCNodeLoaderLibrary * ccNodeLoaderLibrary = CCNodeLoaderLibrary::newDefaultCCNodeLoaderLibrary();
    

You may need to cast the returned value depending on what sort of object is the root node in your ccbi-file and how you will use it in your code. For instance, if you load a CCParticleSystem, use the following code.

CCParticleSystem* myParticles = (CCParticleSystem*) ccbReader->readNodeGraphFromFile("MyParticleSystem.ccbi");

For your convenience, CCBReader can also wrap your node graph in a scene. To load your ccbi-file in a scene call sceneWithNodeGraphFromFile:

CCScene* myScene = ccbReader->sceneWithNodeGraphFromFile("MyScene.ccbi");

Passing an Owner Variable

Sometimes you need to be able to access member variables from and get callbacks to another object than the root node of a ccb-file. To do this you will need to pass a owner to the CCBReader. To get the variable or callback assigned to the owner, make sure that you've selected owner when declaring the member variable name or callback in CocosBuilder. The call the nodeGraphFromFile(file, owner) or sceneWithNodeGraphFromFile(file, owner) method of CCBReader when loading your file.

HelloCocosBuilderLayer *pOwner = new HelloCocosBuilderLayer();
CCNode* myNode = ccbReader->readNodeGraphFromFile("MyNodeGraph.ccbi", pOwner);

Accessing Variables and Callbacks in a sub ccb-file

If you are using sub ccb-files specifying the root node as target will refer to the root node of the sub ccb-file. The owner target is the object that you pass to the CCBReader.

Example

Please take a look at HelloCocosBuilderLayer.h, HelloCocosBuilderLayer.cpp, and HelloCocosBuilderLayerLoader.h from the ExtensionsTest in the TestCPP project of cocos2d-x.

Setting scale and design size

For CocosBuilder based projects in cocos2d-x, the AppDelegate needs to setup the game to read the correct resources from the correct directories from the project files. It is based on the device screen size. You also need to set the scaling factor and the design resolution size of the GL view.

For portrait mode, you can add this code to AppDelegate.cpp in AppDelegate::applicationDidFinishLaunching

CCSize designSize = CCSizeMake(320, 480);
CCSize resourceSize = CCSizeMake(320, 480);
CCSize screenSize = CCEGLView::sharedOpenGLView()->getFrameSize();

std::vector<std::string> searchPaths;
std::vector<std::string> resDirOrders;

TargetPlatform platform = CCApplication::sharedApplication()->getTargetPlatform();
if (platform == kTargetIphone || platform == kTargetIpad)
{
    searchPaths.push_back("Published-iOS"); // Resources/Published-iOS
    CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);

    if (screenSize.height > 768)
	{
    	resourceSize = CCSizeMake(1536, 2048);
        resDirOrders.push_back("resources-ipadhd");
	}
 	else if (screenSize.height > 640)
	{
    	resourceSize = CCSizeMake(768, 1536);
        resDirOrders.push_back("resources-ipad");
	}else if (screenSize.height > 480)
    {
        resourceSize = CCSizeMake(640, 960);
        resDirOrders.push_back("resources-iphonehd");
    }
    else
    {
        resDirOrders.push_back("resources-iphone");
    }
    
    CCFileUtils::sharedFileUtils()->setSearchResolutionsOrder(resDirOrders);
}
else if (platform == kTargetAndroid || platform == kTargetWindows)
{

    if (screenSize.height > 960)
    {
        resourceSize = CCSizeMake(640, 960);
        resDirOrders.push_back("resources-large");
    }
    else if (screenSize.height > 480)
    {
        resourceSize = CCSizeMake(480, 720);
        resDirOrders.push_back("resources-medium");
    }
    else
    {
        resourceSize = CCSizeMake(320, 568);
        resDirOrders.push_back("resources-small");
    }
    
    CCFileUtils::sharedFileUtils()->setSearchResolutionsOrder(resDirOrders);
}

pDirector->setContentScaleFactor(resourceSize.width/designSize.width);

CCEGLView::sharedOpenGLView()->setDesignResolutionSize(designSize.width, designSize.height, kResolutionShowAll);

For landscape mode, you can change the order of resolutions. So (320, 480) becomes (480,320) , (640, 960) becoms (960, 640) etc. in all places.