文章目录

  1. 设置插槽的显示对象索引
  2. 替换插槽的显示对象数据
  3. 设置插槽的显示对象
  4. 设置插槽的子骨架
  5. 动画共享
  6. 皮肤共享

本教程以Egret引擎为例,讲解龙骨换装的方法。其他引擎使用方法也是类似的。
如何使用 DragonBones Pro 制作动画,请参考DragonBones Pro的入门视频教程。

关于加载并解析龙骨数据,创建骨架,播放动画等基础操作可以参考这个源码

- 设置插槽的显示对象索引

这种换装的方式就是将所有需要更换的显示对象都预先放置在插槽内,动画并不会直接使用或切换这些显示对象。而是由程序,通过龙骨运行时的 API 控制他们显示或切换。例如将下面的五种武器图片预先放置在同一个插槽内,以便在程序中切换。

将该 DragonBones Pro 项目工程导出为龙骨数据,在程序中使用如下的龙骨运行时 API 修改插槽的显示对象索引:

const slot = armatureDisplay.armature.getSlot("weapon");
slot.displayIndex = 2;

从上边的图可以看到,插槽 weapon 中,weapon_1004的displayIndex是0,所以顺着数下来,weapon_1004c的displayIndex就是2,所以设置slot.displayIndex = 2 , 就将插槽 weapon 的显示对象切换成 weapon_1004c了。

再复杂一些,修改为通过鼠标点击来循环切换显示对象:

this.stage.addEventListener(egret.TouchEvent.TOUCH_BEGIN, () => {
this._displayIndex++;
this._displayIndex %= 5;

const slot = armatureDisplay.armature.getSlot("weapon");
slot.displayIndex = this._displayIndex;
}, this);

现在便可以通过点击来切换插槽的显示对象了。请参看下边的实例:

如果想让插槽不显示任何图片,可以设置插槽内显示对象为空,只需要执行下面的操作:

slot.displayIndex = -1;

上面这种换装方式还有一些局限性,那就是在 DragonBones Pro 中制作动画的过程中不能再添加切换该插槽显示的关键帧或与之相关的其他关键帧(例如子骨骼的动画切换)。
因为这样可能会造成动画关键帧的设置与 API 设置冲突,从而导致每当API设置动画切换后,如果动画运行到时间轴上设置的切换显示对象关键帧,插槽的显示对象还是会切换为关键帧中设置的显示对象,而使得之前使用 API 设置的该值失效。为了避免这个问题,我们需要使用另一个 API 来防止此类的情况发生:

slot.displayController = "none";

该 API 的作用就是禁止动画状态修改此插槽的显示属性(只有名叫none的动画才有权利修改。换言之,当没有任何动画叫none时,就意味着没有任何一个动画可以修改此插槽的显示属性),不过这样也就意味着该插槽的所有显示属性动画都被禁用了,包括透明度,颜色,混合和 FFD 。

这种换装方式的优点是非常容易使用,而缺点则是需要将所有更换的显示对象都预先放置到插槽内部,这些图片资源在最终发布时都会合并到贴图集中。通常一个贴图集能包含的图片资源是有限的(贴图集宽高不宜超过 2048 x 2048),如果需要换装的显示对象非常之多或者需要频繁更新,采用此种换装方式并不是最理想的方案。

- 替换插槽的显示对象数据

这种换装的方式就是将所有需要更换的显示对象制作在其他骨架中(甚至可以是其他的 DragonBones Pro 工程项目的骨架中),动画本身并不会直接通过关键帧来使用或切换这些显示对象,而是由龙骨运行时的 API 将其替换到指定的插槽上。

同样以上面的五把武器为例,这次不需要将全部武器预置到同一个插槽中,而是将待更换的武器制作到另一个骨架原件(或影片剪辑原件)中。(本例将两个骨架制作在同一个 DragonBones Pro 工程项目中,你也可以自己动手尝试,分开到多个 DragonBones Pro 工程项目中。)

在库面板中新建一个元件选择类型为影片剪辑,将全部显示对象同时选中拖拽放置到舞台,右键分散到关键帧,删除多余图层,并将图层名重命名(图层名对应为插槽名)。

然后使用锚点工具,将每个武器的锚点定位到合理的位置。(其实锚点位置就是插槽的父骨骼的位置,只不过使用影片剪辑原件操作更方便一些,如果能理解这其中的小窍门,完全可以使用骨架原件而不是影片剪辑原件,你可以自己动手尝试使用骨架而不是影片剪辑来制作。)

将该 DragonBones Pro 工程项目导出为龙骨数据格式,在程序中用如下龙骨运行时 API 将显示对象数据替换到显示对象上:

const slot = armatureDisplay.armature.getSlot("weapon");
factory.replaceSlotDisplay("replace_display", "armatureB", "weapon", "weapon_1004c", slot);

其中 replaceSlotDisplay中包含四个参数:
- replace_display - 用来替换的 DragonBones Pro 工程项目名称。本例中,两个原件在同一个项目中,都是replace_display。
- armatureB - 用来替换的原件的名称,也就是前边我们创建的额动画剪辑,在replace_display工程项目下。其中包含了用来替换的图片的来源。
- weapon - 用来替换的对象数据所在的插槽。armatureB下的插槽。
- weapon_1004c - 用来替换的对象数据名。weapon下的对象数据名。

这样就可以将replace_display Dragonbones Pro 工程项目中动画剪辑原件armatureB里,插槽weapon下的的显示对象数据 weapon_1004c 替换到replace_display DragonBones Pro 工程项目中骨架原件armature下的插槽 weapon 上了。注意这其中有两个插槽都叫weapon,分别属于不同的原件,一个是源armatureB中的,一个是目标armature中的。这个 API 需要提供四个名字参数来唯一识别一个 DragonBonesData 中的显示对象数据,所以这并不限制来源和目标必须在同一个 DragonBones Pro 工程中。

再复杂一些,修改为通过鼠标点击来循环替换显示对象数据:

this.stage.addEventListener(egret.TouchEvent.TOUCH_BEGIN, () => {
this._displayIndex++;
this._displayIndex %= 5;

const displayName = this._displayNames[this._displayIndex];
const slot = armatureDisplay.armature.getSlot("weapon");
factory.replaceSlotDisplay("replace_slot_display", "armatureB", "weapon", displayName, slot);
}, this);

现在可以通过点击随意的替换插槽的显示对象数据了。

这种换装方式的优点是插槽的动画关键帧不会再和 API 的设置冲突。而且也可以将图片资源分散到多个贴图集中,从而避免全都挤在同一个贴图集中而导致贴图集过大。而缺点是需要在更换的过程中提供额外的四个名字来明确显示对象的来源。并且只有在程序中才可以真正预览到换装后的实际效果。所以这种方式通常用来更换大量的制式武器装备或服装。本例中,更换的武器只需要确定刀柄的锚点位置即可,通常不用再关心换装后的实际效果(或者说该效果应该早在原画设计之初就已经考虑妥当,而不应等到实际换装后查看设计效果)。

- 设置插槽的显示对象

这种换装方式,通常并不是用来换装。因为这种方式功能很强大,可以将任何其他的显示对象通过插槽挂载到骨架上。比如一些特效,按钮,文本框,或者其他任何显示对象。这个方式非常灵活,可以扩展出无限可能的使用方式。

在上面的例子的基础之上做一些简单的修改:

const text = new egret.TextField();
text.text = "Hello DragonBones";
slot.display = text;

这样就可以将一个文本显示到骨架上了,不过这种方式替换后,显示对象替换的位置可能不会符合预期,各个渲染引擎对锚点的定义甚至坐标系都不相同,修正显示对象位置的方法有很多,比如修改显示对象自身的锚点:

text.anchorOffsetX = 70;
text.anchorOffsetY = 12;

武器已经被更换成了一个文本框。可以思考一下为什么这里需要设置锚点坐标为 [70, 12] 呢?

再复杂一些,将事例修改为可以交替显示原来的显示对象或文本框:

this.stage.addEventListener(egret.TouchEvent.TOUCH_BEGIN, () => {
const slot = armatureDisplay.armature.getSlot("weapon");
if (slot.display === slot.rawDisplay) {
slot.display = this._text;
}
else {
slot.display = slot.rawDisplay;
}
}, this);

现在可以通过点击切换武器和文本框了。

这种换装方式的优点是非常自由,可以换装为任何你想显示的东西,缺点则是显示的位置需要后期调整,通常是通过调整显示对象的锚点或者设置 bone.offset 来进行偏移。

上述三种方式的源码下载地址如下:

程序工程源代码

- 设置插槽的子骨架

这种换装方式,通常是要实现比较复杂的动画控制效果。通过更换插槽中的子骨架,让子骨架跟骨架或骨架的动画间建立某种联系。比如这个官方例子,机器人的左右武器均是通过更换子骨架实现的换装。因为机器人的攻击动画中有对子骨架的动画控制,会让子骨架也播放一个攻击动画,并且子骨架的攻击动画中还带有攻击事件。

slot.childArmature = factory.buildArmature("weapon_1005");

使用WASD来控制机械人移动,Q和E用来切换左右的武器,鼠标点击开枪,枪口会跟随鼠标。

这是一种进阶的换装方式,通常是用来更换复杂的武器动画或跟骨架有关联的子骨架,更加详细的原理和过程可以参考程序源代码和 DragonBones Pro 工程项目。

程序源代码

DragonBones Pro 工程项目

- 动画共享

这其实并不是一种换装方式,不过确实可以达到预期的效果。通过将动画共享给其他具有相似结构的骨架,看起来确实像是换装了一样,这样只需要制作一套骨架的动画,而其他的骨架都不需要制作动画了。

factory.copyAnimationsToArmature(armatureDisplay.armature, "mecha_2903d");

鼠标点击切换动画

更加详细的原理和过程可以参考程序源代码和 DragonBones Pro 工程项目。

程序源代码

DragonBones Pro 工程项目

- 皮肤共享

这个部分咱们以后再说。这次先空着。