cocos引擎并没有提供一套专门资源管理解决方案,仅仅只有一个TextureCache提供了针对Texture2D的(异步)加载、缓存、清理等管理工作,我们可以参照TextureCache的思路设计一个针对常见资源的可扩展的资源管理器ResourceCache,使用引用计数原理来控制每个资源的生命周期。

UML

点击查看【processon】

使用示例

  1. #include <iostream>
  2. #include "ResourceMgr.h"
  3. using namespace std;
  4. // 假设已经扩展了以下几种资源类型:
  5. // JsonData
  6. // Mp3Data
  7. // Mp4Data
  8. void main(){
  9. // 考虑以下情景:
  10. // 首先启动游戏,进入到场景1,然后从场景1切换到场景2,场景1、2之间共用了部分资源
  11. // 场景1的资源列表
  12. vector<pair<string, string>> data_scene_1{
  13. { "jsondata_1", JsonData::TYPE },
  14. { "1.mp3", Mp3Data::TYPE },
  15. { "1.mp4", Mp4Data::TYPE },
  16. },
  17. // 场景2的资源列表
  18. data_scene2{
  19. { "jsondata_1", JsonData::TYPE }, // 和场景1共享的资源
  20. { "2.mp3", Mp3Data::TYPE },
  21. { "2.mp4", Mp4Data::TYPE },
  22. }
  23. ResourceMgr::getInstance()->addResRef(data_scene_1);
  24. // 当前资源引用计数表:实际还没有加载场景1资源
  25. // {
  26. // "jsondata_1" : 1,
  27. // "1.mp3" : 1,
  28. // "1.mp4" : 1,
  29. // }
  30. // 加载当前资源引用计数表中的资源,即:jsondata_1、1.mp3、1.mp4
  31. // callback: 加载完成后的回调
  32. ResourceMgr::getInstance()->updateResRefAsync(callback);
  33. ResourceMgr::getInstance()->addResRef(data_scene_2); // 加载场景2的资源
  34. // 当前资源引用计数表:实际还没有加载场景2资源
  35. // {
  36. // "jsondata_1" : 2,
  37. // "1.mp3" : 1,
  38. // "1.mp4" : 1,
  39. // "2.mp3" : 1,
  40. // "2.mp4" : 1,
  41. //}
  42. ResourceMgr::getInstance()->removeResRef(data_scene_1); // 清除上一个场景的资源
  43. // 当前资源引用计数表:
  44. // {
  45. // "jsondata_1" : 1,
  46. // "1.mp3" : 0,
  47. // "1.mp4" : 0,
  48. // "2.mp3" : 1,
  49. // "2.mp4" : 1,
  50. // }
  51. ResourceMgr::getInstance()->updateResRefAsync(data_scene_2);
  52. //1、卸载引用计数=0的资源,即1.mp3、1.mp4
  53. //2、加载引用计数!=0且还未加载的资源,即2.mp3、2.mp4
  54. //
  55. // 当前缓存的资源如下:
  56. //{
  57. // "jsondata_1" : ...,
  58. // "2.mp3" : ...,
  59. // "2.mp4" : ...,
  60. //}
  61. }

代码设计

ResourceMgr

ResourceMgr.h

  1. #ifndef __RESOURCEMGR_H__
  2. #define __RESOURCEMGR_H__
  3. #include "cocos2d.h"
  4. #include "ResourceCache.h"
  5. /**
  6. * 资源管理的统一(唯一)入口
  7. */
  8. class ResourceMgr : public cocos2d::Ref {
  9. public:
  10. static ResourceMgr* getInstance();
  11. void addResProtocol(ResourceProtocol* data);
  12. /**
  13. * 资源引用计数管理API
  14. *
  15. * 注意,有两种引用计数:
  16. * 1、Ref引用计数
  17. * 2、资源引用计数:ResourceMgr内部定义的引用计数,资源的引用计数+1表示该资源将在下一个场景使用,
  18. * 资源并不会马上加载,而是在updateResourceReferenceAsync时,才真正加载。
  19. *
  20. */
  21. /**
  22. * 告知资源管理器将要使用哪些资源(对应资源引用计数+1)
  23. * 新增加的资源将在下一次调用updateResourceReferenceAsync的时候异步载入
  24. */
  25. void addResRef(const std::vector<std::pair<std::string,std::string>>& path_type);
  26. /**
  27. * 告知资源管理器哪些资源不再被使用(对应资源引用计数-1)
  28. * 当资源引用计数为0时将在下次调用updateResourceAsync的时候从内存中释放
  29. */
  30. void removeResRef(const std::vector<std::string>&);
  31. void removeUnusedResRef();
  32. /** 查询某个资源的引用计数 */
  33. int getResRef(const std::string& filename);
  34. /**
  35. * 资源引用计数 > 0,且资源未加载,则加载资源
  36. * 资源引用计数 = 0,则清楚该资源缓存
  37. */
  38. void updateResRefAsync(const std::function<void()>& callback);
  39. void updateResRefAsyncHandler(int handler);
  40. void unupdateResRefAsyncHandler();
  41. private:
  42. ResourceMgr();
  43. virtual ~ResourceMgr();
  44. private:
  45. ResourceCache* _resourceCache; // 自定义资源缓存管理,实现原理参考TextureCache
  46. /**
  47. * 资源引用计数表
  48. *
  49. * key : resource full path
  50. * value : resource reference count
  51. */
  52. std::unordered_map<std::string, int> _resRefMap;
  53. /**
  54. * 待加载的资源
  55. *
  56. * key : resource full path
  57. * value : resource type
  58. */
  59. std::vector<std::pair<std::string, std::string>> _resToAdd;
  60. int _addHandler;
  61. int _updateHandler;
  62. bool _isLoading;
  63. };
  64. #endif /* defined(__Resource__) */

ResourceMgr.cpp

  1. #include "ResourceMgr.h"
  2. #include "JsonData.h"
  3. USING_NS_CC;
  4. using namespace std;
  5. static ResourceMgr* _resourceInstance = nullptr;
  6. ResourceMgr* ResourceMgr::getInstance()
  7. {
  8. if (_resourceInstance == nullptr) {
  9. _resourceInstance = new ResourceMgr();
  10. }
  11. return _resourceInstance;
  12. }
  13. ResourceMgr::ResourceMgr()
  14. : _resourceCache(nullptr)
  15. , _updateHandler(0)
  16. , _addHandler(0)
  17. , _isLoading(false)
  18. {
  19. _resourceCache = new ResourceCache();
  20. }
  21. ResourceMgr::~ResourceMgr()
  22. {
  23. CCLOG("~ResourceMgr");
  24. unupdateResRefAsyncHandler();
  25. }
  26. void ResourceMgr::addResProtocol(ResourceProtocol* data)
  27. {
  28. _resourceCache->addResourceProtocol(data);
  29. }
  30. void ResourceMgr::addResRef(const std::vector<std::pair<std::string, std::string>>& path_type)
  31. {
  32. if (path_type.empty()) {
  33. return;
  34. }
  35. for (auto iter = path_type.cbegin(); iter != path_type.cend(); iter++) {
  36. auto fullpath = cocos2d::FileUtils::getInstance()->fullPathForFilename(iter->first);
  37. if (!fullpath.empty()) {
  38. auto find = _resRefMap.find(fullpath);
  39. if (find != _resRefMap.end()) {
  40. find->second++;
  41. }
  42. else {
  43. _resRefMap.insert(std::make_pair(fullpath, 1));
  44. _resToAdd.push_back(make_pair(fullpath, iter->second));
  45. }
  46. }
  47. }
  48. }
  49. void ResourceMgr::removeResRef(const std::vector<std::string>& files)
  50. {
  51. for (auto iter = files.cbegin(); iter != files.cend(); iter++) {
  52. auto fullpath = cocos2d::FileUtils::getInstance()->fullPathForFilename(*iter);
  53. if (!fullpath.empty()) {
  54. auto find = _resRefMap.find(fullpath);
  55. if (find != _resRefMap.end() && find->second > 0) {
  56. find->second--;
  57. }
  58. }
  59. }
  60. }
  61. void ResourceMgr::removeUnusedResRef()
  62. {
  63. for (auto iter = _resRefMap.begin(); iter != _resRefMap.end();) {
  64. if (iter->second == 0) {
  65. iter = _resRefMap.erase(iter);
  66. }
  67. else {
  68. iter++;
  69. }
  70. }
  71. }
  72. int ResourceMgr::getResRef(const std::string& file)
  73. {
  74. auto fullpath = cocos2d::FileUtils::getInstance()->fullPathForFilename(file);
  75. auto find = _resRefMap.find(fullpath);
  76. if (find != _resRefMap.end()) {
  77. return find->second;
  78. }
  79. return 0;
  80. }
  81. void ResourceMgr::unupdateResRefAsyncHandler()
  82. {
  83. if (0 != _updateHandler) {
  84. ScriptEngineManager::getInstance()->getScriptEngine()->removeScriptHandler(_updateHandler);
  85. _updateHandler = 0;
  86. }
  87. }
  88. void ResourceMgr::updateResRefAsyncHandler(int handler)
  89. {
  90. unupdateResRefAsyncHandler();
  91. _updateHandler = handler;
  92. auto callback = [this] {
  93. #if CC_ENABLE_SCRIPT_BINDING
  94. CommonScriptData data(_updateHandler, "", this);
  95. ScriptEvent event(kCommonEvent, (void*)&data);
  96. CCLOG("updateResourceReferenceAsyncHandler callback lua.");
  97. ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&event);
  98. return;
  99. #endif
  100. };
  101. updateResRefAsync(callback);
  102. }
  103. void ResourceMgr::updateResRefAsync(const std::function<void()>& callback)
  104. {
  105. // 第一步:清除资源,资源引用计数=0的资源。
  106. for (auto iter = _resRefMap.begin(); iter != _resRefMap.end(); iter++) {
  107. if (iter->second == 0) {
  108. _resourceCache->removeResourceForKey(iter->first);
  109. }
  110. }
  111. // 第二步:移除资源引用计数,=0的
  112. removeUnusedResRef();
  113. // 第三步:异步加载新的资源(引用计数为1的)
  114. int* reference = new int();
  115. *reference = _resToAdd.size();
  116. #if COCOS2D_DEBUG
  117. time_t* t = new time_t();
  118. time(t);
  119. int count = _resToAdd.size();
  120. #endif
  121. //资源全部加载完毕
  122. auto completed = [reference, callback, this
  123. #if COCOS2D_DEBUG
  124. , t, count
  125. #endif
  126. ]() {
  127. if ((*reference) == 0) {
  128. delete reference;
  129. #if COCOS2D_DEBUG
  130. time_t now;
  131. time(&now);
  132. CCLOG("we spend %f seconds to load {%d} files.", (float)difftime(now, *t), count);
  133. delete t;
  134. #endif
  135. _resToAdd.clear();
  136. _isLoading = true;
  137. callback();
  138. }
  139. };
  140. CCLOG("we need to load %d files", (int)_resToAdd.size());
  141. if (_resToAdd.size() == 0) {
  142. completed();
  143. return;
  144. }
  145. for (auto iter = _resToAdd.begin(); iter != _resToAdd.end(); iter++) {
  146. _resourceCache->addResourceAsync(iter->first, [&](void* data) {
  147. (*reference)--;
  148. if (*reference < 1) {
  149. completed();
  150. }
  151. }, iter->second);
  152. }
  153. }

ResourceCache

ResourceCache.h

  1. #ifndef __RESOURCECACHE_H__
  2. #define __RESOURCECACHE_H__
  3. #include <thread>
  4. #include <unordered_map>
  5. #include "cocos2d.h"
  6. #include "ResourceProtocol.h"
  7. class ResourceMgr;
  8. /**
  9. * 自定义资源缓存
  10. *
  11. * 不对外公开,全部private,由友元ResourceMgr代理
  12. */
  13. class ResourceCache : public cocos2d::Ref {
  14. private:
  15. ResourceCache();
  16. virtual ~ResourceCache();
  17. /**
  18. * 同步加载资源到缓存
  19. */
  20. void* addResource(const std::string& filename, const std::string& type = "Texture2D");
  21. /**
  22. * 异步加载资源到缓存
  23. */
  24. void addResourceAsync(const std::string& filename, std::function<void(void*)> callback, const std::string& type="Texture2D");
  25. /**
  26. * 清除所有自定义资源缓存,类似TextureCache::removeAllTextures
  27. */
  28. void removeAllResources();
  29. /**
  30. * 清除所有当前未被使用的资源,即Ref引用计数为1,类似TextureCache::removeUnusedTexture
  31. */
  32. void removeUnusedResources();
  33. /**
  34. * 删除指定资源
  35. */
  36. bool removeResource(void* data);
  37. bool removeResourceForKey(const std::string& key);
  38. /**
  39. * 注册一个自定义数据类型及解析器
  40. */
  41. void addResourceProtocol(ResourceProtocol* data);
  42. private:
  43. /**
  44. * 自定义资源加载完成的回调,schedule update每帧执行,也就是说是在GL thread中执行
  45. */
  46. void addResourceAsyncCallback(float dt);
  47. /**
  48. * 在子线程中加载自定义资源
  49. */
  50. void loadData();
  51. private:
  52. struct AsyncStruct {
  53. AsyncStruct(const std::string& fn, std::function<void(ResourceProtocol*)> cb, const std::string& type)
  54. :filename(fn)
  55. , callback(cb)
  56. , resourceType(type)
  57. {
  58. }
  59. std::string filename;
  60. std::string resourceType;
  61. std::function<void(ResourceProtocol*)> callback;
  62. };
  63. typedef struct _DataInfo {
  64. AsyncStruct* asyncStruct;
  65. ResourceProtocol* data;
  66. } DataInfo;
  67. std::thread* _loadingThread;
  68. std::queue<AsyncStruct*>* _asyncStructQueue;
  69. std::deque<DataInfo*>* _dataInfoQueue;
  70. std::mutex _asyncStructMutex;
  71. std::mutex _dataInfoMutex;
  72. std::mutex _sleepMutex;
  73. std::condition_variable _sleepCondition;
  74. bool _needQuit;
  75. int _asyncRefCount;
  76. private:
  77. cocos2d::TextureCache *_textureCache;
  78. /** 所有缓存数据 */
  79. std::unordered_map<std::string, ResourceProtocol*> _resources;
  80. /**
  81. * 自定义资源类型模板
  82. */
  83. std::map<std::string, ResourceProtocol*> _resourceTemplate;
  84. // 此类的代理
  85. friend ResourceMgr;
  86. };
  87. #endif /* defined(__ResourceCache__) */

ResourceCache.cpp

  1. #include "ResourceCache.h"
  2. USING_NS_CC;
  3. ResourceCache::ResourceCache()
  4. : _loadingThread(nullptr)
  5. , _asyncStructQueue(nullptr)
  6. , _dataInfoQueue(nullptr)
  7. , _needQuit(false)
  8. , _asyncRefCount(0)
  9. , _textureCache(Director::getInstance()->getTextureCache())
  10. {
  11. }
  12. ResourceCache::~ResourceCache()
  13. {
  14. for (auto iter = _resources.begin(); iter != _resources.end(); ++iter) {
  15. iter->second->release();
  16. }
  17. for (auto iter = _resourceTemplate.begin(); iter != _resourceTemplate.end(); iter++) {
  18. iter->second->release();
  19. }
  20. }
  21. void* ResourceCache::addResource(const std::string& filename, const std::string& type)
  22. {
  23. CCASSERT(!filename.empty(), "filename cann't be nil.");
  24. void* resource = nullptr;
  25. if (type == "Texture2D") {
  26. resource = _textureCache->addImage(filename);
  27. }
  28. else {
  29. //全路径key
  30. std::string fullpath = cocos2d::FileUtils::getInstance()->fullPathForFilename(filename);
  31. if (fullpath.empty()) {
  32. return nullptr;
  33. }
  34. //是否已加载
  35. auto iter = _resources.find(fullpath);
  36. if (iter != _resources.end()) {
  37. resource = iter->second;;
  38. }
  39. if (!resource) {
  40. do {
  41. CCLOG("add resource date type: %s", type.c_str());
  42. auto iter1 = _resourceTemplate.find(type);
  43. if (iter1 != _resourceTemplate.end()) {
  44. ResourceProtocol* data = iter1->second->cloneEmpty();
  45. if (!data->loadWithFile(filename)) {
  46. CC_SAFE_RELEASE(data);
  47. CCLOG("ResouceDataDelegate is error: %s", iter1->first.c_str());
  48. break;
  49. }
  50. _resources.insert(std::make_pair(fullpath, data));
  51. resource = data;
  52. }
  53. }
  54. while (0);
  55. }
  56. }
  57. return resource;
  58. }
  59. void ResourceCache::addResourceAsync(const std::string& filename, std::function<void(void*)> callback, const std::string& type)
  60. {
  61. CCASSERT(!filename.empty(), "filename cann't be nil.");
  62. if (type == "Texture2D") {
  63. auto func = [this, filename, callback, type](cocos2d::Texture2D* tex) {
  64. callback(tex);
  65. };
  66. _textureCache->addImageAsync(filename, func);
  67. }
  68. else {
  69. ResourceProtocol* data = nullptr;
  70. std::string fullpath = FileUtils::getInstance()->fullPathForFilename(filename);
  71. auto iter = _resources.find(fullpath);
  72. if (iter != _resources.end()) {
  73. data = iter->second;
  74. }
  75. if (data != nullptr) {
  76. callback(data);
  77. return;
  78. }
  79. //lazy init
  80. if (_asyncStructQueue == nullptr) {
  81. _asyncStructQueue = new std::queue<AsyncStruct*>();
  82. _dataInfoQueue = new std::deque<DataInfo*>();
  83. _loadingThread = new std::thread(&ResourceCache::loadData, this);
  84. _needQuit = false;
  85. }
  86. if (_asyncRefCount == 0) {
  87. Director::getInstance()->getScheduler()->schedule(schedule_selector(ResourceCache::addResourceAsyncCallback), this, 0, false);
  88. }
  89. ++_asyncRefCount;
  90. AsyncStruct* async = new AsyncStruct(fullpath, callback, type);
  91. _asyncStructMutex.lock();
  92. _asyncStructQueue->push(async);
  93. _asyncStructMutex.unlock();
  94. _sleepCondition.notify_one();
  95. }
  96. }
  97. void ResourceCache::addResourceAsyncCallback(float dt)
  98. {
  99. std::deque<DataInfo*>* datasQueue = _dataInfoQueue;
  100. _dataInfoMutex.lock();
  101. if (_dataInfoQueue->empty()) {
  102. _dataInfoMutex.unlock();
  103. }
  104. else {
  105. DataInfo* dataInfo = datasQueue->front();
  106. datasQueue->pop_front();
  107. _dataInfoMutex.unlock();
  108. AsyncStruct* asyncStruct = dataInfo->asyncStruct;
  109. ResourceProtocol* data = dataInfo->data;
  110. const std::string& filename = asyncStruct->filename;
  111. if (data) {
  112. _resources.insert(std::make_pair(filename, data));
  113. data->retain();
  114. data->autorelease();
  115. }
  116. else {
  117. auto iter = _resources.find(asyncStruct->filename);
  118. if (iter != _resources.end()) {
  119. data = iter->second;
  120. }
  121. }
  122. asyncStruct->callback(data);
  123. delete asyncStruct;
  124. delete dataInfo;
  125. --_asyncRefCount;
  126. if (0 == _asyncRefCount) {
  127. Director::getInstance()->getScheduler()->unschedule(schedule_selector(ResourceCache::addResourceAsyncCallback), this);
  128. }
  129. }
  130. }
  131. void ResourceCache::loadData()
  132. {
  133. AsyncStruct* asyncStruct = nullptr;
  134. while (true) {
  135. std::queue<AsyncStruct*>* pQueue = _asyncStructQueue;
  136. _asyncStructMutex.lock();
  137. if (pQueue->empty()) {
  138. _asyncStructMutex.unlock();
  139. if (_needQuit) {
  140. break;
  141. }
  142. else {
  143. std::unique_lock<std::mutex> lk(_sleepMutex);
  144. _sleepCondition.wait(lk);
  145. continue;
  146. }
  147. }
  148. else {
  149. asyncStruct = pQueue->front();
  150. pQueue->pop();
  151. _asyncStructMutex.unlock();
  152. }
  153. ResourceProtocol* data = nullptr;
  154. bool loaded = false;
  155. auto iter = _resources.find(asyncStruct->filename);
  156. if (iter == _resources.end()) {
  157. _dataInfoMutex.lock();
  158. DataInfo* dataInfo;
  159. size_t pos = 0;
  160. size_t infoSize = _dataInfoQueue->size();
  161. for (; pos < infoSize; pos++) {
  162. dataInfo = (*_dataInfoQueue)[pos];
  163. if (dataInfo->asyncStruct->filename.compare(asyncStruct->filename)) {
  164. break;
  165. }
  166. }
  167. _dataInfoMutex.unlock();
  168. if (infoSize == 0 || pos < infoSize) {
  169. loaded = true;
  170. }
  171. }
  172. if (loaded) {
  173. const std::string & filename = asyncStruct->filename;
  174. auto cloneData = _resourceTemplate.find(asyncStruct->resourceType);
  175. if (cloneData != _resourceTemplate.end()) {
  176. data = cloneData->second->cloneEmpty();
  177. if (!data->loadWithFile(filename)) {
  178. delete data;
  179. CCLOG("load file: %s fail.", filename.c_str());
  180. continue;
  181. }
  182. CCLOG("load file: %s success.", filename.c_str());
  183. }
  184. else {
  185. CCLOG("load file: %s fail. no parser.", filename.c_str());
  186. continue;
  187. }
  188. }
  189. DataInfo* dataInfo = new DataInfo();
  190. dataInfo->asyncStruct = asyncStruct;
  191. dataInfo->data = data;
  192. _dataInfoMutex.lock();
  193. _dataInfoQueue->push_back(dataInfo);
  194. _dataInfoMutex.unlock();
  195. }
  196. }
  197. void ResourceCache::removeAllResources()
  198. {
  199. for (auto it = _resources.begin(); it != _resources.end(); ++it) {
  200. (it->second)->release();
  201. }
  202. _resources.clear();
  203. _textureCache->removeAllTextures();
  204. }
  205. void ResourceCache::removeUnusedResources()
  206. {
  207. for (auto it = _resources.cbegin(); it != _resources.cend(); /* nothing */) {
  208. ResourceProtocol *tex = it->second;
  209. if (tex->getReferenceCount() == 1) {
  210. CCLOG("GX: ResourceCache: removing unused data: %s", it->first.c_str());
  211. tex->release();
  212. _resources.erase(it++);
  213. }
  214. else {
  215. ++it;
  216. }
  217. }
  218. _textureCache->removeUnusedTextures();
  219. }
  220. bool ResourceCache::removeResource(void* data)
  221. {
  222. return false;
  223. }
  224. bool ResourceCache::removeResourceForKey(const std::string& key)
  225. {
  226. auto it = _resources.find(key);
  227. if (it == _resources.end()) {
  228. std::string fullpath = FileUtils::getInstance()->fullPathForFilename(key);
  229. it = _resources.find(fullpath);
  230. }
  231. if (it == _resources.end()) {
  232. _textureCache->removeTextureForKey(key);
  233. return true;
  234. }
  235. else {
  236. if (!_resources.empty()) {
  237. (it->second)->release();
  238. _resources.erase(it);
  239. return true;
  240. }
  241. }
  242. return false;
  243. }
  244. void ResourceCache::addResourceProtocol(ResourceProtocol* data)
  245. {
  246. if (_resourceTemplate.find(data->getType()) == _resourceTemplate.end()) {
  247. _resourceTemplate.insert(std::make_pair(data->getType(), data));
  248. }
  249. }

ResourceProtocol

ResourceProtocol.h

  1. #ifndef __RESOURCEPROTOCOL_H__
  2. #define __RESOURCEPROTOCOL_H__
  3. #include "cocos2d.h"
  4. /**
  5. * 自定义数据类型
  6. */
  7. class ResourceProtocol : public cocos2d::Ref {
  8. public:
  9. ResourceProtocol() {};
  10. virtual ~ResourceProtocol() {};
  11. public:
  12. virtual const std::string& getType() const = 0;
  13. //返回一个空数据的实例,用于创建数据实例
  14. virtual ResourceProtocol* cloneEmpty() const = 0;
  15. //必须实现加载数据到内存方式
  16. virtual bool loadWithFile(const std::string& filename) = 0;
  17. };
  18. #endif

JsonData

JsonData.h

  1. #ifndef __JSONDATA_H__
  2. #define __JSONDATA_H__
  3. #include "ResourceProtocol.h"
  4. #include "json\rapidjson.h"
  5. class JsonData : public ResourceProtocol {
  6. public:
  7. JsonData();
  8. ~JsonData();
  9. const std::string& getType() const override
  10. {
  11. return TYPE;
  12. };
  13. ResourceProtocol* cloneEmpty() const override;
  14. bool loadWithFile(const std::string& filename) override;
  15. public:
  16. static std::string TYPE;
  17. rapidjson::Document data;
  18. };
  19. #endif /* defined(__JsonData__) */

JsonData.cpp

  1. #include "JsonData.h"
  2. using namespace std;
  3. USING_NS_CC;
  4. std::string JsonData::TYPE = "JsonData";
  5. JsonData::JsonData()
  6. {
  7. }
  8. JsonData::~JsonData()
  9. {
  10. }
  11. ResourceProtocol* JsonData::cloneEmpty() const
  12. {
  13. return new JsonData();
  14. }
  15. bool JsonData::loadWithFile(const std::string& filename)
  16. {
  17. bool bRet = false;
  18. do {
  19. std::string jsonpath = cocos2d::FileUtils::getInstance()->fullPathForFilename(filename);
  20. std::string contentStr = cocos2d::FileUtils::getInstance()->getStringFromFile(jsonpath);
  21. data.Parse<0>(contentStr.c_str());
  22. CC_BREAK_IF(data.HasParseError());
  23. bRet = true;
  24. }
  25. while (0);
  26. return bRet;
  27. }