[转载]一个高效简洁的Aseprite to Unity导入工具
原文链接 https://zhuanlan.zhihu.com/p/28644268
期待原作者上传至AssetStore.
今天,我的第一个 Unity 插件 MetaSprite 正式发布了它的 0.1 版本,所以想趁这个机会写一篇文章做下记录。
MetaSprite 是一个高效、灵活的 Aseprite to Unity 导入插件。它可以把像素动画软件 Aseprite 生成的 .ase 文件导入 Unity,作为 Mecanim 动画系统的 Animation Clip 和 Animator Controller 使用。
MetaSprite 不是第一个完成这件事的插件,但相较它的先来者(talecrafter/AnimationImporter),有以下的改进点和新功能:
- 不依赖外部的 Aseprite 可执行程序以导入
- 内建 ase 文件的 parser,因此导入速度非常的快,可以达到前者的10倍以上
- 在创建图集(atlas)的时候会略去空白区域,大大提高了空间利用率
- 更简单的工作流,通过右键菜单来实现导入
- 导入设置单独存储,不需要在一个全局配置上改来改去
- 完善的metadata(元数据)支持
项目的源代码在这里 WeAthFoLD/MetaSprite。接下来,我想简单说一说在开发这个插件过程中的一些想法和心得。
1. 动机
我在过去的一段时间一直和同学做一个像素风格的横版动作游戏。在多次试验试错之后,我们最终确定了以像素帧动画为核心表现形式,基于 Aseprite 绘制的帧动画进行导入的工作流。很长一段时间,我们用的是手动导入,通过 Aseprite 导出图集,然后在 Unity 里手动切图、设置锚点,再手动创建关键帧。这样的重复工作占用了大量的时间,导致动画编辑的效率一直上不去。现在想想,当时可谓是我们动画编辑的石器时代(雾)。
暑假,我在上海的一家独立游戏工作室实习。非常凑巧的是,这里同样使用了基于 Aseprite 的一套像素动画导入的工作流。但是这里的引擎大大写了一个非常棒的 ase 导入器(跑在基于lua的自研引擎上),把 ase 文件放在项目中就可以直接播放使用。
这样顺畅的工作流让我恍然大悟:如果在 Unity 里使用自动化工具进行 ase 文件的导入,那么会大大降低重复工作量,从而提高工作速度。我就此开始了 ase 导入工作流的探索。
初步的搜寻以后,我找到了 talecrafter/AnimationImporter 这一导入工具。初步使用起来感觉效果还行,但是有一些问题很大的影响了体验:
- 需要外部的 Aseprite 可执行文件来运行。这个工具通过调用 Aseprite 的 CLI-mode 来获取 ase 文件的 metadata 以及生成 atlas。这个过程相当消耗时间 (一个30帧左右的 ase 文件,在我的电脑上导入要5秒以上);
- 导入操作不符合直觉。我需要打开一个专门的 Animation Importer 窗口,然后把文件拖进去实现导入。并且导入设置是全局的,每次导入都要费力气把设置改来改去,可以预想到会消耗很多的时间;
- Aseprite 自己的 atlas 生成不是很给力,有大量留白。理想的状况是没有内容的区域全部忽略掉,让里面的 sprite 紧紧的贴在一起。
除此之外,我们还有一个最大的痛点没有被满足:通过 ase 文件来操纵一些非图像的数据。一个最典型的例子就是攻击判定框:因为我们是对反馈要求比较严格的动作游戏,碰撞框需要和动画比较好的同步,才能带来比较好的体验。对此,最好的方式就是美术直接在帧动画中绘制碰撞框。因此,我们需要某种方式来区别 ase 文件中的内容层和这种功能层,并对应的去解析这些层里的数据。
综上,现有的工具完全无法满足我对一个完善的 Aseprite 导入器的要ye求xin。自己造一个轮子的想法应运而生。
2. 开发小记
作为 proof-of-concept,我首先做的事是沿用 AnimationImporter 基本的工作流,并在上面加入自己的一些想法。也就是说核心还是调用 Aseprite 可执行文件,读取数据和生成,但会慢慢换掉其中的各个流程。
首先从最想做的 metadata 支持入手,设计了一些最基本的 metadata 规则,包括:
- 可以用 // 注释掉层或者动画片段(这里把frameTag译作动画片段,代表动画中的一段时间区间)
- 可以在动画片段名字后面用 #loop 让生成的 clip 循环播放
- '@' 字符开头的层是 meta层。meta层不会参与到 atlas 的生成,会被对应的 MetaLayerProcessor 读取并进行对应处理,比如说生成操纵 BoxCollider2D 的动画轨。
实现上,基本就是通过读取 Aseprite CLI 生成的 json 文件到一个 ASEMetadata 的数据结构中,然后再根据 metadata 进行接下来的 atlas生成 → clip生成 → controller生成 → 处理 meta layer。
工作流方面,实现了一个单独的导入配置文件作为 ScriptableObject 存在项目中。多个 ase 文件可以复用同一个导入配置,解决了之前在全局配置上改来改去的问题。导入的方式也改成了选择要导入的文件 -> 右键导入,便利了许多。
至此,这个项目的工作方式已经基本成型。我对新插件的工作流相当满意,除了一个严重的问题:慢。调用 Aseprite CLI 会带来不可避免的性能瓶颈。单生成一个 30 帧的 Atlas 就花了3秒左右的时间,Unity 导入这个 atlas 又要花去一秒多的时间。如果一个文件里有多个 meta 层的话,每个 meta 层在处理过程中都要单独生成一个 atlas,最后的时间消耗是非常恐怖的。因此,我最终还是下定决心,从头写一个自己的 ase 文件解析器,一劳永逸的解决性能上的问题。
非常幸运的是,aseprite 的官方 repo 里就有文件格式的描述文档(aseprite/aseprite),文件格式也很简单,因此在写 parser 的过程中阻力很小,连带 parser 和一个简单的 atlas generator 在一个周末的时间就写完了。最后的效果也很振奋人心,导入的时间从 5 秒以上起步变到了基本可以忽略不计(1秒以内)。
最后的大致效果可以看下面的演示:
3. 公开发布和未来计划
在这个工具做到一半的时候,我们的美术同学就开始怂恿我把这个东西公开出来。我自己也非常的看好这个工具,因为它真的切切实实解决了我们项目工作流的核心痛点。因此,在插件基本成型之后,我选择把它尽快公开,一方面希望这个工具可以让更多有和我们同样问题的开发者的需求得到解决,一方面希望能得到更多改善这个工具的建议。最终目标:让 MetaSprite 成为最好的 Aseprite to Unity 导入工具!
这个工具在 alpha 阶段会一直免费并且 MIT 开源,持续的对这个插件进行改进。毕竟作为一个刚成型的插件,还有很多重要的feature没有完工。
如果你和我一样也是一个 Aseprite 使用者和 Unity 开发者,也希望你能受益于这个工具,并且对这个工具提出各方面的批评建议。You will be my biggest motivation :-)