2013年12月8日 星期日

cocos2d-X 网络动态下载资源图片

http://zgame.blog.51cto.com/6144241/1061850


 游戏中经常会把一些资源放在服务器,玩家玩到的时候再动态下载,缓存,显示。
下面介绍下主要实现逻辑。
 1.游戏初始化的时候,登陆服务器, 服务器返回一些基本信息,包含外部资源图片的网络地址。
2. 网络请求图片下载
  1. void HttpDownload::onMenuPostBinaryTestClicked(cocos2d::CCObject *sender ,  char * setUrl_ ,  char * childpath , char * filename) 
  2.     CCHttpRequest* request = new CCHttpRequest(); 
  3.      if (this->container) 
  4.     { 
  5.         this->observerID = CCImageNotificationCenter::sharedNotificationCenter()->addObserver(filename,container,useMask); 
  6.     } 
  7.  
  8.     std::string url_ = ""
  9.     url_ += setUrl_; 
  10.     url_+=childpath; 
  11.     url_+= filename; 
  12.     this->filename_ = filename; 
  13.  
  14.     request->setUrl(url_.c_str()); 
  15.     request->setRequestType(CCHttpRequest::kHttpGet); 
  16.     request->setResponseCallback(this, callfuncND_selector(HttpDownload::onHttpRequestCompleted)); 
  17.  
  18.     request->setTag("GET PIC"); 
  19.     CCHttpClient::getInstance()->send(request); 
  20.     request->release(); 
  21.  
  22.      
3.网络返回图片文件,保存,通知动态加载显示部分--图片下载完成 
  1. void HttpDownload::onHttpRequestCompleted(cocos2d::CCNode *sender, void *data) 
  2.  
  3.    CCHttpResponse *response = (CCHttpResponse*)data; 
  4.  
  5.    if (!response) 
  6.    { 
  7.        return
  8.    } 
  9.     
  10.    // You can get original request type from: response->request->reqType 
  11.    if (0 != strlen(response->getHttpRequest()->getTag()))  
  12.    { 
  13.        CCLOG("%s completed", response->getHttpRequest()->getTag()); 
  14.    } 
  15.     
  16.    int statusCode = response->getResponseCode(); 
  17.    char statusString[64] = {}; 
  18.    sprintf(statusString, "HTTP Status Code: %d, tag = %s", statusCode, response->getHttpRequest()->getTag()); 
  19.  
  20.    CCLOG("response code: %d", statusCode); 
  21.     
  22.    if (!response->isSucceed())  
  23.    { 
  24.        CCLOG("response failed"); 
  25.        CCLOG("error buffer: %s", response->getErrorBuffer()); 
  26.        return
  27.    } 
  28.     
  29.    // dump data 
  30.    std::vector<char> *buffer = response->getResponseData(); 
  31. std::string path = CCFileUtils::sharedFileUtils()->getWriteablePath(); 
  32. std::string bufffff(buffer->begin(),buffer->end()); 
  33.  
  34.  
  35.  
  36. //保存到本地文件 
  37. path+=this->filename_; 
  38. CCLOG("path: %s",path.c_str()); 
  39.  FILE *fp = fopen(path.c_str(), "wb+"); 
  40.  fwrite(bufffff.c_str(), 1,buffer->size(),  fp); 
  41.  fclose(fp); 
  42.  
  43. //传入container的下载请求会添加侦听,待下载完毕自动添加到container上 
  44.  if (this->container) 
  45.  { 
  46. // container 是一个CCLayer ,用来显示动态加载的资源
  47.  CCImageNotificationCenter::sharedNotificationCenter()->postNotification(this->observerID.getCString()); 
  48.  } 
  49.  
4.专门负责动态加载资源的消息监听,并且当接到文件下载完成的消息后,回调显示该图片
  1. CCString CCImageNotificationCenter::addObserver(const char *imageName,CCLayer* layer,bool useMask) 
  2.     CCString* observerIDstr =  CCString::createWithFormat("%d",m_observerID); 
  3.      
  4.     m_notificationCenter.addObserver(this, callfuncO_selector(CCImageNotificationCenter::imageLoaded), observerIDstr->getCString(), new imgstruct(imageName, observerIDstr->getCString(), layer, useMask)); 
  5.      
  6.     m_observerID++; 
  7.     return observerIDstr->getCString(); 
  8.  
  9. void CCImageNotificationCenter::removeObserver(const char *name) 
  10.     m_notificationCenter.removeObserver(this, name); 
  11. }  
  12.  
  13. void CCImageNotificationCenter::postNotification(const char *name, CCObject *object) 
  14.     m_notificationCenter.postNotification(name, object); 
  15.  
  16. void CCImageNotificationCenter::imageLoaded(imgstruct* img) 
  17.     CCLOG("imageLoaded success,imageName:%s",img->imageName.c_str()); 
  18.     CCSprite* sprite = GOEUtilies::getSpriteFromWriteablePath(img->imageName.c_str()); 
  19.     CCLOG("got sprite 0x%X", sprite); 
  20.     if (img->useMask) 
  21.     { 
  22.         img->layer->addChild(GOEUtilies::createMaskedSprite(sprite,"mask.png")); 
  23.     } 
  24.     else
  25.         float scale_ = (float) img->layer->getContentSize().width  / (float)sprite->getContentSize().width; 
  26.         sprite->setAnchorPoint(ccp(0,0)); 
  27.         sprite->setScale( scale_ ); 
  28.         img->layer->addChild(sprite); 
  29.     } 
  30.     this->removeObserver(img->observerId.c_str()); 
  31.     img->release(); 
5.以后再显示该图片,则从本地SD卡缓存中读取文件,有判断方法
  1. CCSprite* GOEUtilies::getSpriteFromWriteablePath(const char* name){ 
  2.     std::string path = CCFileUtils::sharedFileUtils()->getWriteablePath(); 
  3.     path+=name; 
  4.     FILE* fp = fopen(path.c_str(),"rb"); 
  5.     if (!fp) 
  6.     { 
  7.         return NULL; 
  8.     } 
  9.     fseek(fp,0,SEEK_END); 
  10.     int len = ftell(fp);   
  11.     fseek(fp,0,SEEK_SET); 
  12.     char* buf = (char*)malloc(len); 
  13.     fread(buf,len,1,fp); 
  14.     fclose(fp); 
  15.     CCImage* img = new CCImage; 
  16.     img->initWithImageData(buf,len); 
  17.     free(buf); 
  18.     cocos2d::CCTexture2D* texture = new cocos2d::CCTexture2D(); 
  19.     bool isImg = texture->initWithImage(img); 
  20.     img->release(); 
  21.     if (!isImg) 
  22.     { 
  23.         delete texture; 
  24.         return CCSprite::create("50black.png");//加载资源并非图片时返回的默认图 
  25.     } 
  26.     CCSprite* sprite = CCSprite::createWithTexture(texture); 
  27.     texture->release(); 
  28.     return sprite; 


总结,该逻辑实现后,可以动态加载网络资源,并缓存本地,什么时候加载完成自动显示,并且可以同时进行多张图片的显示缓存,效果很好。