前言:没想到好多年没来,CSDN 竟然支持了 Markdown 的编辑,而且还是直接 fork 了 StackEdit 过来的,开始我还在想是否要换个写博客的地方,毕竟我不是一个很勤快的人,而且我也想界面能尽量简洁,CSDN 的界面太过花眼。本想到 Github 上逛逛看,有没有适合的简单的技术博客程序,既然这里的书写可以让我如此顺畅,那我就暂时再写一篇吧。
一般做 RPG 相关的游戏才会比较多得用到 2D 骨骼系统,毕竟,一提 骨骼 这个词,想到的就是 脊椎动物,有角色有人物有怪物的,也就 RPG 偏多了。但是其实在 UI 界面上,放上骨骼动画的话,也会让交互体验上升一个档次。
有幸这两年来公司让我和另外两个同事一起开发了一个挂机类的 RPG 游戏,全部都从头搭起,包括策划、游戏框架、服务端、客户端。虽然到目前看来挺失败的,但作为个人来讲,还是得到了很多的经验和教训,并且现在回头看看,也许游戏比较失败,但是整套游戏框架还是挺不错的。如果让我再开发一个新的 RPG 游戏,也许我还是会选择这套框架来做。
一般大家耳熟能详的 2D 骨骼编辑器估计也就 Spine。
当然,貌似 Unity 开发套组里面也自带了一个骨骼编辑器,不过 Unity 我没接触过,不好妄加评论,我主要是接触 cocos2d-x 的引擎,做过一些 2D 的游戏。这篇文章也是主要讨论在 cocos2d-x 下的骨骼系统的选择。
其实稍微搜一下还能找到其他两款骨骼系统,一款也是国外的 Creature,还有一款是国内 白鹭时代 开发的 DragonBones。我还是罗列下吧,否则看起来比较乱。
我稍微介绍下骨骼动画的编辑和运行。
知道的童鞋请跳过本节,不知道的可以稍微扫扫盲,但是这个也仅仅是我的理解,说实话我也没对这个有太深的了解,理解有误的地方也请提示我更正,不过你们看我最近发博客的频率也知道我不常来,唉,自便吧。
骨骼动画的开发其实分为3大块:
对于设计师来讲,主要是需要前两点,也是就是骨骼动画的设计、装配,动作设计。貌似3个都有比较好的设计界面,而且都基本支持 网格(Mesh,减少纹理填充率)、皮肤(Skin,换肤)、自由变换(FFD,变形,可以做伪3d效果),其中 Spine 应该算是业界比较响当当的了,也是大部分接触 cocos2d-x 用户会选择的骨骼动画方案(特么谁让 cocos2d-x 直接在源码中提供了它的 runtime 库呢)。
这里我也想吐槽下官方的 CocosStudio,这个方案被毙了,现在替代的应该是 CocosCreator。之前 CocosStudio 有点想做大而全,结果是一大口没咽下反而噎死了的感觉。工具链能统一提供固然很好,但是还是需要有品质保证的,比如可以考虑去收购一些既有的成熟的场景编辑器公司来balabala的,当然这是当笑话来讲了,哈哈哈。
设计完后,导出对应的 骨骼数据文件,然后由 运行时库 解析和运行展现。在运行时,代码逻辑可以根据需要展现对应的动作,代码还可以访问各个子部件,从而方便控制骨骼动画的细节和展现。
针对 2D 动画大致分两种:帧序列动画 和 骨骼动画。
帧序列动画的优势在于,基本哪里都可以用,因为本身就是图片的切换,适用范围广。但是劣势也比较明显,纹理大小会根据动作的多少成线性上涨,如果一个角色有两个动作,就有两套序列纹理,3 个动作就是 3 套。纹理的大小基本在动作的倍数上。
比如一个骑兵的三个动作:跑、攻击、死亡,帧动画就是 3 套纹理,骨骼动画的话其实是一套纹理(拆分到关节),3 个动作描述文件。
但也不是说帧动画相对骨骼动画就一定不好,这个其实是一个使用场景的问题,比如做一个爆炸的特效,帧动画就比骨骼动画要适合,除非你需要多种不同爆炸的效果(有人估计要说了,用粒子系统啊,好吧,我这个例子举得不是那么恰当,自己脑补下即可,不要咬文嚼字)。
骨骼动画也有其劣势,比如他依赖引擎的实现。引擎要解析骨骼动画导出的标准数据来转化为自己可以实现的动画。
帧序列动画其实是适合做一些固定的动画效果,比如刀光、闪电等。骨骼动画比较适合做一些角色的动作。两者结合起来,会有很好的表现效果,比如一个刺客挥刀劈砍出现一个刀光,这个动画其实是需要两个动画形式结合来展现的。
骨骼动画其实最大的优势在于:
一些带有角色基本动作的游戏比较适合骨骼动画。
比如街机上 名将,它每个角色都有许多攻击动作,敌人也是五花八门的动作。
跑酷游戏也是比较适合的。
比如 DOTA传奇,主要的游戏模式就是场景战斗。还有一些三消的游戏,上面带了几个角色,根据不同的消除组合会触发角色的战斗技能。还有些带战斗动画的挂机类游戏也非常适合。
现在大多数骨骼动画的解决方案都是比较成熟的,基本已经把设计和使用分开了,并且都会支持许多不同的平台,这也是发展进化后,市场细分的结果。
在我看来,其思想就是:让专业的人做专业的事,让设计能够复用。
原本其实我是自己想过去实现一套骨骼动画的模块的,但是这仅仅是站在的程序员的角度。比如我看了【贪婪洞窟】后的感觉就是,角色的攻击模式都是固定的,其实要我去实现这样的攻击动作,就是写好对应的 Action,然后让这些 Action 串联起来播放即可。可能,当时的第一套动作系统也是这么做的,但是这样明显有个跨引擎平台的问题,不同的客户端引擎都要根据自身的动作系统自己重新实现一次,并且,这种模块的接口其实是面向程序员的,很难让设计人员参与进来,一般外行人做外行事,程序员做出来的动画,细节上基本没法看。更关键的是这明显很不好用,生产效率低下,让程序员每天调整动画细节也真是醉了,于是可能(我猜)就在此基础上催生了 骨骼动画编辑器 和 骨骼动画运行时库 的分离,从而实现跨引擎(跨平台?看你把平台比作什么了)。
动作是一个描述(是一个数据接口),是动画编辑器导出的一个数据,然后运行时库根据不同的引擎来实现这个动作的显示。
上文提到的 3 个骨骼动画解决方案都提供了这两个工具模块:骨骼动画编辑器、骨骼动画运行时库。
骨骼动画编辑器其实是给动作设计师用的,他们可以用编辑器设计出一些非常漂亮的动作,然后导出成运行时库能理解的动作数据文件,可以理解为写 功夫秘籍。
骨骼其实是一个很形象的比喻,如同人的手臂,外部的皮是就是依附在骨头上的,骨头动了,皮自然跟着一起动。(当然,细究起来还有肌肉,但是我只能说,呵呵。)
动作就是指导每一个骨骼每一帧要摆动到什么位置,然后带动上面的贴图一起动。
运行时库其实就是一个 翻译。
你可以想象这样一个场景:动作数据 就是一本用 中文 写的 功夫秘籍,然后一个阿拉伯习武者(假设是 cocos2d-x 显示模块吧)想要学,那就需要一个阿拉伯翻译(运行时库的动作文件解析模块),告诉那个阿拉伯习武者如何打出这套功夫的动作(cocos2d-x 用自己的动画模块展现)。然后一个英国习武者(假设是 Unity 的显示模块)也想学,那就再来一个英语翻译(Unity 中解析动作文件)把这个中文的秘籍翻译成英文(Unity 中的动画数据格式),告诉这个英国习武者如何打(展现)。
运行时库是针对不同引擎的,一般这个骨骼解决方案中会提供多种适配的引擎供选择和使用。
说到这里,其实程序员占的比重不大,因为一个游戏的给玩家带来的感受,很大程度是在 界面 UI 以及 画面展现 上。毕竟视觉感官是很重要的,这就是所谓的眼缘。所以,角色的 人设 以及 动作设计 非常重要。
基础的骨骼动画,其实是每一帧你把人物的各个部位摆一个姿势,类似于帧动画,每一帧一个新的位置,顺序播放的话就动起来了。
但是玩过 Flash 的都知道 补间动画 这个概念。最简单的就是你告诉编辑器,对象在第一帧坐标是(0,0),15 帧坐标是(50,0),中间的位置,每一帧由差值算法来补上,这样就节省了大量的动画制作时间。
骨骼动画编辑器蛮多也就是用这种思想来实现高效率的动画制作的,当然 补间动画 不仅仅针对对象的 平移、旋转 上,还可以实现更高级的 网格、自由变换 等特效,而且这些都是可以通过关键帧之间做补间动画实现的。
骨骼动画不仅有简单的 FK(正向动力学,父骨骼带动子骨骼定位,比如腰部的前后动作带动上身和脖子、头部的骨骼),编辑器额外还支持 IK(反向动力学,子骨骼带动父骨骼定位,比如手腕和脚尖移动带动手臂和小腿大腿骨骼),而且这些也是可以通过关键帧做补间动画的。其实接触过 3DMax 或者 Maya 的,都会了解些许关于 3D 骨骼的 FK 和 IK 概念,这里是同样适用的,只不过这里是 2D 的平面的骨骼动作,相对 3D 要简单不少。
针对一般的比如跑酷类的游戏,这样的工具都已经足够使用了,主要技术方案还是跟着策划的走的。现在市面上大多的跑酷游戏都是提供多个不同的人物角色,角色自己会带多套皮肤(静态换装),这样的方案其实大多的骨骼方案都能满足,但是诸如【奇迹暖暖】这样的 动态换装 游戏(其实我猜这个游戏是动态换装),就有点麻烦了,为啥呢?这要从这些骨骼动画解决方案的纹理加载说起了。
骨骼数据导出的纹理,一般为了节约空间,都会选择把碎图打包成一整张大图,这样能节省部分的纹理空间数据,比如单个的纹理都有对应的文件头和文件内部数据描述的额外信息,合并成一个大图后,这部分的信息就只有一份了,并且可以过滤掉一些透明的部分,使得展现同样对象的 碎图纹理 和 纹理图集,纹理图集 加载到内存后的数据量会小许多(除非本身不含透明层)。
这种格式会导出两个文件,纹理集图片文件,和一个 纹理定位数据描述文件 (描述组成对象的零件小图在整张纹理图集的坐标和宽高)。
换肤这个功能,runtime 大多都是直接替换一套 skin 的 ID
接口,一旦是用 ID
了,那必定是有内部预对应的分组,也就是所有的皮肤都必须在这个纹理集中,载入的时候已经知道有几套皮肤纹理(至少我接触的这几类换肤,都是这么设计的)。打包纹理集的好处前面说了,但是也有其弊端,就是不同的设备,对单张图片纹理的分辨率有要求的,一般移动端根据显示硬件的内存的大小,比如,Android 建议不要超过 1024*1024
的图片(毕竟机型太复杂);有些引擎也会预先判断下图像分辨率的大小。
让我们想象一下,主打换装的游戏,势必会拥有大量的装饰性皮肤,而且随着游戏的运营,还会有很多后续的新的饰品推出,这样的更新一般不可能去整体更新打包到一起的纹理集,因为有大小限制,也不可能无限更新纹理到纹理集中。所以 动态换装 对这类游戏的支持是必须的。
静态换装就是当前的外观纹理都是打包在一个纹理图片集中的,程序只需要设定对应显示的皮肤就可以更换部位的展现图片了。
外观的纹理是独立的形式放在游戏文件系统中的,可以根据需要,指定对应的纹理替换对应的位置。所以,一些资源就可以通过后期更新的方式,增量更新到游戏文件系统中。
动态换装 在支持基础的 图片 的动态替换基础上应该还需要支持 子骨骼 的动态替换,比如一个带有特效的武器——武器周围有个能量球绕着武器旋转,这本身就是一个独立的骨骼系统。
纸娃娃系统也叫 布偶系统(Rag Doll System)。女孩子可能比较有感触,芭比娃娃是有很多套衣服可以换着穿的,你给可以给它换上不同的上衣和裤子搭配。
一个应用案例就是,游戏中的人物的武器,会根据你选择装备的不同,使用不同的贴图直接展现在人物身上。这样让玩家能切实感受到你选择不同装备穿戴是会影响到你人物的外观的,也让装备的选择多一个维度——外观,这也催生了另一个系统的诞生——时装。
早期的游戏,一般都没有纸娃娃系统,比如 FC 和 PS1 上的 最终幻想,你无论给角色装备上什么武器、衣服,角色的外观不会有任何的变化,唯一能看出区别的就是装备面板和属性面板。
其实,纸娃娃系统就是动态换装的一个案例。比如你给游戏更新了一个装备,如果是静态换装,好了,能使用这个武器的角色都要再纹理库中增加一个这个武器的贴图,如果每更新一个装备都要把原有的角色纹理图都修改合并一遍,那美工岂不是要崩溃了?假设有1000件衣服,就算美工不崩溃,程序加载纹理,内存也会崩溃的。
有了纸娃娃系统,能让 RPG 游戏增色不少,并且可以满足玩家更多个性化的需求。
balabala 讲了一大堆,还是需要有个对比吧,那最后我就来根据我自己的经验讲下几个场景下,哪个解决方案是比较合适的。其实没有绝对的优劣,在某个场景下才会出现优劣,而且不同的场景下,选择也会不同。
先说下 Creature,这个方案我去官网大致了解了下,看起来和 Spine 非常类似,并且商业模式也很类似(我指的是收费模式),细节我没有仔细看,至少在支持的引擎上,我看到了 cocos2d-x。所以,下面,我就和 Spine 合并了讲了。其实对比,就仅限在 Spine 和 DragonBones 之间。
编辑器 | Windows | MacOS | Linux |
---|---|---|---|
Spine | ✅ | ✅ | ✅ |
DragonBones | ✅ | ✅ | ❌ |
编辑器的支持情况,Spine 会好一点。
如果你是在 Linux 下工作的话,只能选 Spine 了。
他们都支持基本的主流游戏引擎,比如 Unity3D、cocos2d-x 等等,但 Spine 完爆 DragonBones,我也懒得罗列了,自己看去吧。
Spine 支持的运行库
功能 | Spine | DragonBones |
---|---|---|
Mesh* | ✅ | ✅ |
FFD* | ✅ | ✅ |
FK* | ✅ | ✅ |
IK* | ✅ | ✅ |
Path | ✅ | ❌ |
帧序列动画导出 | ✅ | ✅ |
GIF 输出 | ✅ | ✅ |
视频导出 | ✅ | ✅ |
纹理集 | ✅ | ✅ |
洋葱皮 | ✅ | ✅ |
自动关键帧 | ✅ | ✅ |
Pose | ✅ | ✅ |
Skins | ✅ | ✅ |
Boundingbox | ✅ | ✅ |
动画平滑缓冲 | ✅ | ✅ |
动态换装 | ❌ | ✅ |
还有很多功能我没有罗列出来,有一些是因为可能不大常用(我自己认为的),还有一些本身就是不可比较,比如 DragonBones 本身可以导入 Spine 输出的骨骼数据建立一个骨骼项目并且能大部分正确还原对应的动画效果;再比如它还能直接输出 Spine 格式的类型文件等等。
我觉得 DragonBones 功能本身也是照着 Spine 在比较的,提供对应的兼容性也是再正常不过,这些特性功能本身不具备对比性。
从功能性,Spine 还是对 DragonBones略胜一筹。但是有一项功能能让你直接抛弃 Spine 从而选择 DragonBones,那就是 动态换装。
当然,Spine 也可以通过修改源码来实现,但是这样做真是谁用谁知道。
每次官方更新 runtime 都要重新合并一次,更麻烦的是,当你换界面引擎后,原来的 runtime 修改就无法合并过来,而是要根据当前引擎再重新实现一次。
根据我之前搜索 动态换装 相关的信息时,从 知乎 上得到的结论是 Spine 本身在设计整个骨骼数据结构的时候,就不适合 动态换装,并表示好像作者也不准备为这个功能去重构代码,那好吧,呵呵。
Spine 提供了基础版和专业版(企业用户价格会不同),并且上面功能性对比上打 * 的功能,是只有专业版才提供的。
DragonBones 是开源免费的(好吧,就这点,在我这里你就赢了),并且由国人研发维护。虽然英文的文档并不会成为阅读障碍,但是有中文文档自然阅读成本会更低,并且在和开发人员的交流上也会舒畅许多。
如果你需要 动态换装,那建议你选择 DragonBones,而如果没有这方面的需求,那还是考虑下 Spine,因为功能和运行表现上,还是 Spine 略胜一筹。
当然,和你使用的游戏引擎也有很大关系,Spine 支持的引擎数量大大超过 DragonBones 的,并且如果你使用的是 cocos2d-x,那对 Spine 的支持本身就很好。DragonBones 的 runtime 我只用过 cpp for cocos2d-x
版本的,本身的变量创建方式和 cocos2d-x 的方式有点不同,导致敲代码的时候有点别扭。
DragonBones 还是比较看好的,基本 Spine 有的功能大部分都有了,并且最近编辑器也发布了 5.1 版本,动画设计的体验上有了很大的改进,只不过 runtime 好多平台都没有更新,导致好多功能暂时还不能使用。但是这毕竟只是暂时的,我相信 DB 以后会越来越好用。
暂时不能在 cocos2d-x 引擎中使用的功能有:
- 插槽 Z 轴 变化帧(Animation slot zOrder)
- 包围盒判定(Boundingbox)
说句实话,我还是挺希望 DB 能找到一个收费模式的,毕竟免费的东西难以长期持续。无论公司还是个人,都是以 生存下去 为第一需求的,活下来了后面的斗好说,为了事业为了情怀都可以有,死了,就啥都没了。