cocos2dx v3.9 与SpriteFrameCache和AnimationCache之间的对话
我:前段时间去过动画制作组,你们两个的名字与动画制作组中的SpriteFrame和Animation很相似,难道说你们之间有什么关系? 我:还是来说说你们是如何工作的吧。SpriteFrameCache,既然AnimationCache需要你的协助,那么还是从你开始,先来说说如何使用你。 // 如何使用图片的参数存放在plist文件中,图片名
void addSpriteFramesWithFile(const std::string& plist,const std::string& textureFileName);
/* 函数内部
* 调用Director::getInstance()->getTextureCache()->addImage()将图片加载为纹理。
* 调用addSpriteFramesWithFile()。
*/
当然,如果您已经创建好了纹理也可以, void addSpriteFramesWithFile(const std::string&plist,Texture2D *texture);
/* 函数内部
* 调用FileUtils::getInstance()->getValueMapFromFile()读取plist文件内容。
* 调用addSpriteFramesWithDictionary()。
*/
又或者,不指定plist文件,您将plist文件的内容指定给我也没问题, void addSpriteFramesWithFileContent(const std::string& plist_content,Texture2D *texture);
/* 函数内部
* 调用FileUtils::getInstance()->getValueMapFromData()读取plist文件内容。
* 调用addSpriteFramesWithDictionary()。
*/
再或者,您将图片名称放在plist文件中也ok, void addSpriteFramesWithFile(const std::string& plist);
/* 函数内部
* 使用FileUtils::getInstance()->fullPathForFilename()获取plist文件的全路径。
* 调用FileUtils::getInstance()->getValueMapFromFile()读取plist文件内容。
* 尝试从plist中找metadata域,如果找到了则从metadata域的textureFileName域得到图片的文件名,
* 之后将plist所在路径与该图片名使用FileUtils::getInstance()->fullPathFromRelativeFile()拼在一起作为图片的完整路径名。
* 如果没有在plist中找到图片名,则将plist文件的全路径中文件名的后缀由.plist更改为.png,以此更改后的全路径作为图片的完整路径名。
* 调用Director::getInstance()->getTextureCache()->addImage()将图片加载为纹理。
* 调用addSpriteFramesWithDictionary()。
*/
最后,如果您已经创建好了SpriteFrame,那我是再高兴不过的了, // 每个SpriteFrame在SpriteFrameCache中都有个名字,这里作为参数传递了,通常这个名字放在之前提到的plist文件中。
void addSpriteFrame(SpriteFrame *frame,const std::string& frameName);
/* 函数内部 * 调用_spriteFrames.insert()存储SpriteFrame与其名字的映射。 */
此外还要说明一点,我存储的这些SpriteFrame不仅可以用于动画制作,您还可以使用他们直接来创建Sprite, // xxx.plist中存储了名为xxx.png的SpriteFrame信息。
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("xxx.plist");
// Sprite::createWithSpriteFrameName()会从SpriteFrameCache中查找指定的SpriteFrame,然后使用找到的SpriteFrame创建Sprite。
auto sprite = Sprite::createWithSpriteFrameName("xxx.png");
我:很多函数都调用了addSpriteFramesWithDictionary()。 <key>frame</key> <string>{{2,2},{250,30}}</string>
也可以使用四个key-value表示 <key>x</key>
<float>2</float>
<key>y</key>
<float>2</float>
<key>width</key>
<float>250</float>
<key>height</key>
<float>30</float>
这些不同的表示形式就对应不同的format。其中当format为3时在plist文件中frames域中aliases域会给出SpriteFrame的别名,这些别名与原SpriteFrameName的映射我就会存在_spriteFramesAliases变量中。 void removeSpriteFramesFromFile(const std::string& plist);
/* 函数内部 * FileUtils::getInstance()->fullPathForFilename()读取plist文件的内容。 * 调用removeSpriteFramesFromDictionary()。 */
void removeSpriteFramesFromFileContent(const std::string& plist_content);
/* 函数内部 * 调用FileUtils::getInstance()->getValueMapFromData()读取plist文件内容。 * 调用removeSpriteFramesFromDictionary()。 */
// 以上两个函数都调用了removeSpriteFramesFromDictionary()。
void removeSpriteFramesFromDictionary(ValueMap& dictionary);
/* 函数内部 * dictionary中存储了plist文件的内容,其中可以找到待删除的SpriteFrame的名字,一一从_spriteFrames中删除。 */
或者通过texture, void removeSpriteFramesFromTexture(Texture2D* texture);
/* 函数内部 * 遍历_spriteFrames中的每一个映射,通过映射获得每一个SpriteFrame。 * SpriteFrame->getTexture()与给定的texture比对,相同则删除该SpriteFrame。 */
又或者通过SpriteFrame的名字, void removeSpriteFrameByName(const std::string& name);
/* 函数内部 * 如果给定的是SpriteFrame的别名,则会在_spriteFramesAliases中找到其原本的名字。 * 使用SpriteFrame原本的名字删除_spriteFrames中的此SpriteFrame。 */
或者直接删除所有的, void removeUnusedSpriteFrames();
/* 函数内部 * 清空_spriteFrames。 */
此外,还有一个比较有用的方法,删除掉未被使用的SpriteFrame, void removeUnusedSpriteFrames();
/* 函数内部 * 删除_spriteFrames中引用计数为1的SpriteFrame(引用计数为1代表此SpriteFrame只被SpriteFrameCache使用)。 */
我:我看还有个获取的方法。 SpriteFrame* getSpriteFrameByName(const std::string& name);
/* 函数内部
* 用给定的name在_spriteFrames中寻找。
* 如果没找到则用name在_spriteFramesAliases中查找别名,并用别名在_spriteFrames中寻找。
* 最终找到了返回SpriteFrame,未找到返回nullptr。
*/
我:你在介绍使用方式的同时也介绍了不少实现方式,同时提到了许多你使用的变量,简单做个总结。 Map<std::string,SpriteFrame*> _spriteFrames; // 存储SpriteFrame的名字与SpriteFrame之间的映射。
ValueMap _spriteFramesAliases; // 存储SpriteFrame的别名与SpriteFrame的名字之间的映射。
std::set<std::string>* _loadedFileNames; // 存储加载过的plist文件名。加载过的plist不会重复加载。
其中最核心的就是_spriteFrames这个变量。每个SpriteFrame在我这里都有个名字,从我这里取走SpriteFrame或是删除SpriteFrame都需要提供他们的名字。 我:和SpriteFrameCache聊了很长时间,现在终于轮到你了AnimationCache。 void addAnimationsWithFile(const std::string& plist);
/* 函数内部 * 读取plist文件的内容。 * 调用addAnimationsWithDictionary(); */
void addAnimationsWithDictionary(const ValueMap& dictionary,const std::string& plist);
/* 函数内部 * 根据plist的内容,获取自己需要用到的spritesheets,并将他们添加进SpriteFrameCache中。 * 根据plist的format,解析出创建AnimationFrame所需信息,并创建它。 * 根据plist的format,解析出创建Animation所需信息,并创建它。 * 将Animation与其名字作为映射存入_animations变量中。 */
一个实际的例子, auto cache = AnimationCache::getInstance();
cache->addAnimationsWithFile("xxx.plist");
auto dance_animation = cache->getAnimation("dance");
或者您已经创建好了Animation,我也是再高兴不过的了, void addAnimation(Animation *animation,const std::string& name);
/* 函数内部 * _animations.insert(name,animation); */
删除Animation的方式只有一个, void removeAnimation(const std::string& name);
/* 函数内部 * _animations.erase(name); */
获取Animation的方式也只有一个, Animation* getAnimation(const std::string& name);
/* 函数内部
* _animations.at(name);
*/
此外要说明一点,在plist文件中您可以为每一个动画帧指定userInfo,通过在每一个动画帧中加入如下key-value, <key>notification</key>
<dict>
...
</dict>
具体点的例子, <key>notification</key>
<dict>
<key>key1</key>
<integer>1234</integer>
<key>key2</key>
<false/>
</dict>
在解析plist中每一动画帧的信息时,会把这些作为用户信息存入AnimationFrame::_userInfo中。还记得Animate的工作方式吗,在动画播放此帧时他将发送这些信息,您只需要在程序中接收这些信息即可, /* AnimationFrameDisplayedNotification定义在cocos/base/ccMacros.h, * #define AnimationFrameDisplayedNotification "CCAnimationFrameDisplayedNotification" * 是用户自定义事件的名字。 * 当动画帧播放完成时,Animate会将该帧的userInfo通过名为CCAnimationFrameDisplayedNotification的自定义事件发送。 * userInfo会以AnimationFrame::DisplayedEventInfo结构体的形式发送。 */
auto listener = EventListenerCustom::create(AnimationFrameDisplayedNotification,[](EventCustom *e) {
auto userdata = static_cast<AnimationFrame::DisplayedEventInfo *>(e->getUserData());
log("target[%p],data[%s]",userdata->target,Value(*(userdata->userInfo)).getDescription().c_str());
});
我:你的内容真的少很多,那么同SpriteFrameCache一样,对你使用的变量,做个简单的总结。 Map<std::string,Animation*> _animations; // 存储Animation的名字与Animation之间的映射。
每个Animation在我这里都有个名字,从我这里取走或是删除Animation都需要提供他们的名字。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |