加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

cocos2dx3.3开发FlappyBird总结四:资源管理类

发布时间:2020-12-14 20:38:35 所属栏目:百科 来源:网络整理
导读:游戏中需要全局管理很多的资源,如图片、音频文件等。下面我们设计一个骨骼资源管理类,名叫:AtlasLoader,设计为全局共享类,用于载入资源和通过资源名称获取精灵

游戏中需要全局管理很多的资源,如图片、音频文件等。下面我们设计一个骨骼资源管理类,名叫:AtlasLoader,设计为全局共享类,用于载入资源和通过资源名称获取精灵帧。

下面先上头文件:

#ifndef __EngryBird__AtlasLoader__
#define __EngryBird__AtlasLoader__

#include "cocos2d.h"

/** * The struct of the atlas file */
typedef struct tag_atlas {
  char name[255];               // the image's name
  int width;                    // the image's width
  int height;                   // the image's height
  cocos2d::Vec2 startPosition;  // the image's start position
  cocos2d::Vec2 endPosition;    // the image's end position
} Atlas;

/** * The hepler class for loading the resources of atlas.png/atlas.txt * * @Note This is a global shared class,just call the getInstance class method * to get the object */
class AtlasLoader {
public:
  /** * Get the instance of AtlasLoader */
  static AtlasLoader* getInstance();

  /** * Destroy the instance of AtlasLoader,and will free all memory it takes */
  static void destroy();

  /** * Load with file name of an atlas and default load the atlas.png to texture * * @param filename the name of an atlas file * * @note This function load the images sync,so it will delay the main thread. * You can call like that: AtlasLoader::getInstance()->loadAtlas("filename"); */
  void loadAtlas(std::string filename);

  /** * Load with file name of an atlas * * @param filename the name of an atlas file * @param texture the Texture2D object,using to create a sprite frame * * This function load the images sync,so it will delay the main thread. * You can call like that: AtlasLoader::getInstance()->loadAtlas("filename",texture); */
  void loadAtlas(std::string filename,cocos2d::Texture2D *texture);

  /** * Get the sprite frame with an image name * * @param imageName the name of image * * @return the sprite frame object related to an image */
  cocos2d::SpriteFrame* getSpriteFrame(std::string imageName);

protected:
  /** * The default constructor */
  AtlasLoader();

  /** * Initializes the instance of AtlasLoader * * @note When you are porting Cocos2d-x to a new platform,you may need to take care of * this method. * * @return true if succeeded,otherwise false */
  virtual bool init();

private:
  /** * The singleton pointer of AtlasLoader */
  static AtlasLoader* s_sharedAtlasLoader;

  /** * The container to store all the sprite frames that has already loaded */
  cocos2d::Map<std::string,cocos2d::SpriteFrame*> _spriteFrames;
};

#endif /* defined(__EngryBird__AtlasLoader__) */

声明了Atlas枚举,与atlas.txt文件中每一行结构是一一对应的。
骨骼文件中,会记录着精灵的图片名称、宽度、高度、起始位置和终止位置,这样就可以通过读取文件来获取精灵应该放置在哪里了。

此类为人全局共享的,因此必须通过下面的方法来创建或获取:

/** * Get the instance of AtlasLoader */
  static AtlasLoader* getInstance();

我们在编码的时候,尽量与cocos2dx引擎的代码风格一致,这样更易于阅读。静态方法是类方法,不是某个对象的方法,这样就是共享的了。

接下来是实现文件。
关于怎么写单例,这里只说一遍,后面的文章中不会重复再说明,因为写法是一样的,只是名称变了而已。

// Initializes the shared object to be nullptr
AtlasLoader* AtlasLoader::s_sharedAtlasLoader = NULL;

AtlasLoader* AtlasLoader::getInstance() {
  if (s_sharedAtlasLoader == NULL) {
    s_sharedAtlasLoader = new AtlasLoader();

    if (!s_sharedAtlasLoader->init()) {
      delete s_sharedAtlasLoader;

      s_sharedAtlasLoader = NULL;
      CCLOG("Error: could not init s_sharedAtlasLoader object");
    }
  }

  return s_sharedAtlasLoader;
}

静态成员变量s_sharedAtlasLoader不能放在构造函数中初始化,所以需要在全局中初始化。
下面是getInstance方法的实现,这里通过判断全局共享变量是否为NULL,如果为NULL表示没有创建过,则创建之,否则不再创建,而是直接使用。这就是所谓的单例。当创建失败时,就把资源给释放掉了。

注意:这里是没有考虑线程安全的,在iOS中,我们写单例都会考虑到线程的安全问题。

下面说说加载资源最重要的方法:

void AtlasLoader::loadAtlas(std::string filename,cocos2d::Texture2D *texture) {
// 这里通过文件操作,读取文件,如atlas.txt文件
// FileUtils是一个文件操作辅助类,是引擎自带的类,获取的是字符串
  std::string data = FileUtils::getInstance()->getStringFromFile(filename);

  // 这里是通过分割读取行,一行一行的读取后(换行符是分割符),把对应的字段写入到Atlas结构中,然后获取精灵在骨骼中的区域,就可以获取到精灵帧了,并放到_spriteFrames中,这个是一个Map类型对象,可通过精灵的名称(key)来获取到精灵帧(value)
  size_t pos = data.find_first_of("n");
  std::string line = data.substr(0,pos);
  data = data.substr(pos + 1);
  Atlas atlas;
  while (line.length() > 0) {
    sscanf(line.c_str(),"%s %d %d %f %f %f %f",atlas.name,&atlas.width,&atlas.height,&atlas.startPosition.x,&atlas.startPosition.y,&atlas.endPosition.x,&atlas.endPosition.y);

    atlas.startPosition.x *= 1024;
    atlas.startPosition.y *= 1024;
    atlas.endPosition.x *= 1024;
    atlas.endPosition.y *= 1024;

    // 读取下一行
    pos = data.find_first_of("n");
    line = data.substr(0,pos);
    data = data.substr(pos + 1);

    // fix 1px edge bug
    if (atlas.name == std::string("land")) {
      ++atlas.startPosition.x;
    }


    // use the data to create a sprite frame
    Rect rect = Rect(atlas.startPosition.x,atlas.startPosition.y,atlas.width,atlas.height);
    auto spriteFrame = SpriteFrame::createWithTexture(texture,rect);
    _spriteFrames.insert(std::string(atlas.name),spriteFrame);
  }
}

好了,这个类已经说得很明白了吧,如果还有不明白的地方,可以联系我哦!!!!

下一步,说说这个屏幕适配的问题

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读