cocos2d-x游戏引擎核心之十——网络通信

一、建立基本的http通信并得到返回信息

1、创建cocos2dx工程

2、项目引用外部库

如果要使用cocos2dx的CCHttpClient来进行网络访问,则需要引入cocos2dx的相关库,详细步骤如下:

右键单击项目->属性->c/c++->常规,在右边的附件包含目录中添加cocos2dx的extensions目录对应的路径。

然后,右键单击项目->属性->链接器->输入,在右边的附件依赖项中添加libcurl_imp.lib和libExtensions.lib两个库,用分号隔开。

如果不引入extensions文件夹,会出现找不到CCHttpClient的错误;如果不引入libcurl_imp.lib和libExtensions.lib两个库,编译项目时也会出现报错。另外注意引入头文件:

#include "cocos-ext.h"  

3.添加下载按钮和回调函数

CCMenuItemImage *pDownloadItem = CCMenuItemImage::create(  
            "bt_blue_light.png",  
            "bt_blue_light.png",  
            this,  
            menu_selector(HelloWorld::menuDownloadCallback)  
        );  
        CC_BREAK_IF(!pDownloadItem);  
        CCSize pWinSize = CCDirector::sharedDirector()->getWinSize();  
      
        CCMenu* pDownloadMenu = CCMenu::create(pDownloadItem, NULL);  
        pDownloadMenu->setPosition(ccp(50  ,50));  
        CC_BREAK_IF(! pDownloadMenu);  
        this->addChild(pDownloadMenu, 1);

添加按钮的回调函数:

void HelloWorld::menuDownloadCallback(CCObject* pSender)  
{  
    cocos2d::extension::CCHttpRequest* request = new cocos2d::extension::CCHttpRequest();  
    request->setUrl("http://www.oschina.net/action/api/news_list");  
    request->setRequestType(cocos2d::extension::CCHttpRequest::kHttpPost);  
    std::vector<std::string> headers;  
    headers.push_back("Content-Type: application/json; charset=utf-8");  
    request->setHeaders(headers);  
    const char* postData = "catalog=2&pageIndex=1&pageSize=5";  
    request->setRequestData(postData ,strlen(postData));  
    request->setResponseCallback(this, callfuncND_selector(HelloWorld::onHttpRequestCompleted));  
    request->setTag("Post_My_Data");  
    cocos2d::extension::CCHttpClient::getInstance()->send(request);  
    request->release();  
}  

按钮的回调函数里向服务器发起http请求了,request->setResponseCallback(this, callfuncND_selector(HelloWorld::onHttpRequestCompleted))一行代码,向请求结束时添加了onHttpRequestCompleted回调函数:

4.为http request 结束增加回调函数并读取网络数据

void HelloWorld::onHttpRequestCompleted(cocos2d::CCNode *sender ,void *data)  
{  
    AllocConsole();  
    freopen("CONIN$", "r", stdin);  
    freopen("CONOUT$", "w", stdout);  
    freopen("CONOUT$", "w", stderr);  
    cocos2d::extension::CCHttpResponse *response = (cocos2d::extension::CCHttpResponse*)data;    
     if (!response)    
    {  
        return;    
    }   
     if (0 != strlen(response->getHttpRequest()->getTag()))   
    {  
        CCLog("%s completed", response->getHttpRequest()->getTag());  
    }  
     int statusCode = response->getResponseCode();  
     char statusString[64] = {};  
     sprintf(statusString ,"Http status code:%d ,tag = %s" ,statusCode ,response->getHttpRequest()->getTag());  
     CCLog("response code:%d" ,statusCode);  
     if (!response->isSucceed())  
     {  
         CCLog("response failed");  
         CCLog("error buffer:%s" ,response->getErrorBuffer());  
     }  
     std::vector<char> *buffer = response->getResponseData();  
     printf("Http response,dump data:");  
     std::string result = "";  
     for (unsigned int i = 0; i < buffer->size(); i ++)  
     {  
        printf("%c" ,(*buffer)[i]);  
     }  
}  

debug时就能看到reponse中服务器返回的数据了

:上面操作遇到的问题

(1) 1>libExtensions.lib(HttpClient.obj) : error LNK2019: 无法解析的外部符号 __imp__pthread_create,该符号在函数 "private: bool __thiscall cocos2d::extension::CCHttpClient::lazyInitThreadSemphore(void)" (?lazyInitThreadSemphore@CCHttpClient@extension@cocos2d@@AAE_NXZ) 中被引用。

解决方法:刚开始这里我是不理解的,因为我以为lib库只需要添加一个libExtensions.lib就行...其实还需要其他俩个lib库文件,pthreadVCE2.lib,libcurl_imp.lib,添加方法(Vs2012):项目属性->链接器->输入->附加依赖项。

(2)error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“0”不匹配值“2”

error:
vtkCommon.lib(vtkSmartPointerBase.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项:值“0”不匹配值“2”(cloudviewer.obj 中)
1>vtkCommon.lib(vtkGarbageCollector.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“0”不匹配值“2”(cloudviewer.obj 中)
1>vtkCommon.lib(vtkDebugLeaksManager.obj) : error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“0”不匹配值“2”(cloudviewer.obj 中)
 
错误原因是:Debug使用了Release的库文件。
即使你连接库里面两个都添加着呢,但是release库文件放在了debug前面,也是出错的。默认按顺序使用库文件。
类似错误:如release下使用了Debug的库文件,报错类似:
error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“2”不匹配值“0”.
解决方法:把Debug模式改为Release模式,编译生成之后,在项目文件夹中运行.exe文件(这里还报了找不到图片资源的错误,把图片资源拷贝到.exe文件同等目录下则可)

 

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

#include "SimpleAudioEngine.h"
#include "cocos-ext.h" 

class HelloWorld : public cocos2d::CCLayer
{
public:
    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();  

    // there's no 'id' in cpp, so we recommand to return the exactly class pointer
    static cocos2d::CCScene* scene();
    
    // a selector callback
    void menuCloseCallback(CCObject* pSender);

    void onHttpRequestCompleted(cocos2d::CCNode *sender ,void *data);


    // implement the "static node()" method manually
    CREATE_FUNC(HelloWorld);
};

#endif  // __HELLOWORLD_SCENE_H__
#include "HelloWorldScene.h"

using namespace cocos2d;

CCScene* HelloWorld::scene()
{
    CCScene * scene = NULL;
    do 
    {
        // 'scene' is an autorelease object
        scene = CCScene::create();
        CC_BREAK_IF(! scene);

        // 'layer' is an autorelease object
        HelloWorld *layer = HelloWorld::create();
        CC_BREAK_IF(! layer);

        // add layer as a child to scene
        scene->addChild(layer);
    } while (0);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    bool bRet = false;
    do 
    {
        //////////////////////////////////////////////////////////////////////////
        // super init first
        //////////////////////////////////////////////////////////////////////////

        CC_BREAK_IF(! CCLayer::init());

        //////////////////////////////////////////////////////////////////////////
        // add your codes below...
        //////////////////////////////////////////////////////////////////////////

        // 1. Add a menu item with "X" image, which is clicked to quit the program.

        // Create a "close" menu item with close icon, it's an auto release object.
        CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
            "CloseNormal.png",
            "CloseSelected.png",
            this,
            menu_selector(HelloWorld::menuCloseCallback));
        CC_BREAK_IF(! pCloseItem);

        // Place the menu item bottom-right conner.
        pCloseItem->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20));

        // Create a menu with the "close" menu item, it's an auto release object.
        CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
        pMenu->setPosition(CCPointZero);
        CC_BREAK_IF(! pMenu);

        // Add the menu to HelloWorld layer as a child layer.
        this->addChild(pMenu, 1);

        // 2. Add a label shows "Hello World".

        // Create a label and initialize with string "Hello World".
        CCLabelTTF* pLabel = CCLabelTTF::create("Hello World", "Arial", 24);
        CC_BREAK_IF(! pLabel);

        // Get window size and place the label upper. 
        CCSize size = CCDirector::sharedDirector()->getWinSize();
        pLabel->setPosition(ccp(size.width / 2, size.height - 50));

        // Add the label to HelloWorld layer as a child layer.
        this->addChild(pLabel, 1);

        // 3. Add add a splash screen, show the cocos2d splash image.
        CCSprite* pSprite = CCSprite::create("HelloWorld.png");
        CC_BREAK_IF(! pSprite);

        // Place the sprite on the center of the screen
        pSprite->setPosition(ccp(size.width/2, size.height/2));

        // Add the sprite to HelloWorld layer as a child layer.
        this->addChild(pSprite, 0);

        bRet = true;
    } while (0);

    return bRet;
}

void HelloWorld::menuCloseCallback(CCObject* pSender)
{
    // "close" menu item clicked
    //CCDirector::sharedDirector()->end();
    cocos2d::extension::CCHttpRequest* request = new cocos2d::extension::CCHttpRequest();  
    request->setUrl("http://www.oschina.net/action/api/news_list");  
    request->setRequestType(cocos2d::extension::CCHttpRequest::kHttpPost);  
    std::vector<std::string> headers;  
    headers.push_back("Content-Type: application/json; charset=utf-8");  
    request->setHeaders(headers);  
    const char* postData = "catalog=2&pageIndex=1&pageSize=5";  
    request->setRequestData(postData ,strlen(postData));  
    request->setResponseCallback(this, callfuncND_selector(HelloWorld::onHttpRequestCompleted));  
    request->setTag("Post_My_Data");  
    cocos2d::extension::CCHttpClient::getInstance()->send(request);  
    request->release(); 

}

void HelloWorld::onHttpRequestCompleted(cocos2d::CCNode *sender ,void *data)  
{  
    AllocConsole();  
    freopen("CONIN$", "r", stdin);  
    freopen("CONOUT$", "w", stdout);  
    freopen("CONOUT$", "w", stderr);  
    cocos2d::extension::CCHttpResponse *response = (cocos2d::extension::CCHttpResponse*)data;    
    if (!response)    
    {  
        return;    
    }   
    if (0 != strlen(response->getHttpRequest()->getTag()))   
    {  
        CCLog("%s completed", response->getHttpRequest()->getTag());  
    }  
    int statusCode = response->getResponseCode();  
    char statusString[64] = {};  
    sprintf(statusString ,"Http status code:%d ,tag = %s" ,statusCode ,response->getHttpRequest()->getTag());  
    CCLog("response code:%d" ,statusCode);  
    if (!response->isSucceed())  
    {  
        CCLog("response failed");  
        CCLog("error buffer:%s" ,response->getErrorBuffer());  
    }  
    std::vector<char> *buffer = response->getResponseData();  
    printf("Http response,dump data:");  
    std::string result = "";  
    for (unsigned int i = 0; i < buffer->size(); i ++)  
    {  
        printf("%c" ,(*buffer)[i]);  
    }  
}  

二、使用libjson来解析网络json数据

 

posted @ 2014-11-12 16:09  小天_y  阅读(1706)  评论(0编辑  收藏  举报