Cocos2d-x中替换动画(Armature)中的节点与粒子

Cocos2d-x游戏开发中常用到骨骼动画Armature,Armature真是个好东西啊,不仅占用资源不大(相对于帧动画来说),而且还能添加帧事件,它还自带有动画的播放、停止、循环事件...balabala

废话少说,直入主题。拿到一个骨骼动画的时候,我们往往会有这样的需求:在情况A下,动画的骨骼a需要显示为样式1,当发生情况B时,这个动画的骨骼a需要显示为样式2。有一种方法,就是将骨骼a单独作为一个动画,这样在使用时可以随意替换,这里不讨论这种方法。

情景:
进行角色动画处理时,当玩家装备不同的武器时,我们需要在动画上显示出玩家装备的这个武器(假设所有的武器都只是外观不同)。所以我们需要将动画中表示武器的这个骨骼进行外观的替换。同理,如果武器有发光、移动时拖尾等(用粒子系统实现的)效果,我们同样需要替换这个粒子资源。


需要用到的API

首先来说,替换Armature中的节点常用到以下几个函数:

  • virtual Bone *getBone(const std::string& name) const; //获得节点
  • void changeDisplayWithIndex(int index, bool force); //根据索引改变显示内容
  • void changeDisplayWithName(const std::string& name, bool force); //根据名称改变显示内容
  • void addDisplay(DisplayData *displayData, int index); //添加一个显示内容
  • void addDisplay(cocos2d::Node *display, int index); //添加一个显示内容
  • void removeDisplay(int index); //移除一个显示内容
  • cocos2d::Node *getDisplayRenderNode(); // 获得Display实际显示的Node
  • DisplayType getDisplayRenderNodeType(); //查询显示内容的类型
  • virtual DisplayManager *getDisplayManager() const { return _displayManager; } //获取Display的管理器

替换骨骼(Bone)的显示内容(Display)的方法

因为在实际拿到动画的时候可能有多种情况,这里我们分情况解释。

举例中所使用的动画资源是使用Cocos Studio 1.6版本资源

动画中已经包含了多个Display

虽然我在项目中是直接使用.csb来创建Armature,但是美食大大还是会很慷慨的共享整个动画工程给我。所以,可以打开.ExportJson文件来看一个Name为btn_icon的Bone所包含的Display数据:

Bont-btn_icon.jpeg

上面看到"bone_data":后面就是动画中包含的骨骼了,然后可以看到"bone_data"下面第一行就是一个Bone的Name属性。跳过中间一堆位置、循环等属性,往下可以看到一个"display_data"的标签,它所代表的就是当前这个Bone中包含的所有Display。这里可以看到美术大大放置了3个Display,分别名为icon1.png、icon2.png、icon3.png。因为"display_data"所指的值是一个json数组,所以自然我们也知道对应三个Display的Index分别为0、1、2.
在使用这个动画文件生成Armature对象时,Name属性为btn_icon的这个Bone默认显示的是索引为0的Display。
此时,如果我们需要改变这个Bone的显示内容,只需要如下语句即可:

auto pArm = cocostudio::Armature::create("myArmatureName"); //生成Armature对象
auto pBone = pArm->getBone("btn_icon"); //获取Bone对象指针
pBone->changeDisplayWithIndex(1, true); //修改Bone的Display为索引1的Display

这是在动画中已经包含了多个Display的情况下,进行Bone的Display的切换。如果美术大大没有在Bone中添加好所有需要的Display怎么办呢?我们可以自己添加。

动画中没有包含需要的Display

这里就不另外放图了,假设上面Name为btn_icon的Bone中只包含了3个Display,而我们需要显示另外一个样式,怎么办呢?我们可以手动添加一个Display。代码如下:

auto pArm = cocostudio::Armature::create("myArmatureName"); //生成Armature对象
auto pBone = pArm->getBone("btn_icon"); //获取Bone对象指针
auto pSprite = Sprite::create("icon4.png"); //生成需要显示的Node
pBone->addDisplay(pSprite, 3); //将新生成的Node添加到Bone中
pBone->changeDisplayWithIndex(3, true); //修改Bone的Display为索引3的Display

在上面两种方式中,都有出现Index参数,这个参数有点讲究。例如当新增一个Display时,Index参数值如果为0、1、2,就会导致新的Display覆盖原来的Display,如果为3,则正好新增一个Display,如果超过3,则会在addDisplay这一行报错,原因是被断言:Assert failed: the _index value is out of range
还有上面changeDisplayWithIndex中的第二个参数force,测试后再详细来写。


替换骨骼(Bone)的粒子效果(Particle)的方法

看过上面方法,替换Bone上的Display就很容易了。如果某个Bone的显示内容就是粒子,使用上面的两种方法也是可以达到解决问题的效果。这里再列出另外一种替换Bone上的粒子效果的方法。

Display是一个粒子

遇到这种情况,再放一张图好了:


Bone-particle.jpeg

同样是在上面提到的.ExportJson动画文件中,这里可以看到Bone的Name属性为pr1,它的"display_data"所表示的不是图片名,而是一个plist文件,这里就是粒子系统(ParticleSystem)文件。
将这张图中"display_data"的内容与上一张图(Bont-btn_icon)中的进行对比,可以看到"displayType"的值不同。
我们看看源码中的这个属性:

/**
* DisplayType distinguish which type your display is.
*/
enum DisplayType
{
    CS_DISPLAY_SPRITE,                //! display is a single Sprite
    CS_DISPLAY_ARMATURE,         //! display is a Armature
    CS_DISPLAY_PARTICLE,            //! display is a CCParticle.

    CS_DISPLAY_MAX
};

可以了解到,Display是包含三种属性的,一是精灵(Sprite),资源就是png图片;二是动画(Armature);三是粒子(Particle),也就是我们现在遇到的。它们的枚举值分别为0、1、2,所以上图中的"displayType"值为2,表示资源是粒子文件。

然后粒子文件要如何来替换呢?其实可以直接获得这个Display显示的Node,然后来修改Node的内容。看下面代码:

auto pBone = pArm->getBone("pr1"); //获得Bone
auto pDisplayNode = (ParticleSystem*)(pBone->getDisplayRenderNode()); //获得Bone的Display的Node,并强转为ParticleSystem(因为已知了它是粒子系统)
pDisplayNode->initWithFile("my_particle.plist"); //使用新的粒子文件重新初始化粒子系统

这样在播放动画时,我们看到的就是新的粒子系统的效果了。

其实这种方式,对于上面所说的Sprite类的Display也适用。


总结:

  • 没有什么好总结的啊。。。
  • 好吧,强行要总结,我也没什么好总结的
  • 其实还有一些情况是我没有写到的,就是如果Display是一个Armature,不过方法应该都差不多

还有几个问题:

  • 如果在Armature刚刚生成好,还没有播放任何动画时,去切换Display,如果force参数填true,则这个Bone会强行显示出来,如果填false,则根本切换不过来。不知道这里会不会有我操作失误,待测。
  • 在更换粒子效果时,如果粒子效果在当前帧还没有显示,此时使用getDisplayRenderNode获取到的值为nullptr。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容