木匣子

Web/Game/Programming/Life etc.

动森二维码生成器 for Aseprite

最近翻到一本不错的像素书:由 Nostarch Press 出版的 Make Your Own Pixel Art。Nostrach Press 专门出版极客类的书籍,里面有很多看到标题就有兴趣读下去的书,非常适合我。

而这本 Make Your Own Pixel Art 的作者 Janeifer 拥有 30 年的像素画经验,在书中非常系统地讲解了像素画入门的各个方面,还提供了不错的练习素材。并且书中使用的编辑器正是我非常喜欢的 Aseprite。正好最近时间比较多,就又拿起来画板和鼠标瞎画点东西。

而更让我惊喜的是,这款买了很久的小而专业的像素绘画软件,居然支持自己编写插件。从 Aseprite v1.2.10-beta2 版本开始,作者引入了 Lua 语言来扩展编辑器,允许用户编写一些定制化的功能

于是我开始琢磨着用它做点什么。正好最近在玩动物森友会,游戏里允许玩家自己创做像素风格的图案用来装饰各种物品、衣服、地面。另外,新版的 Animal Crossing: New Horizons 可以通过手机 App 扫描早期版本的 Animal Crossing: New Leaf (下称 ACNL) 玩家绘制的图案的二维码,导入这些现存的图案。

但要知道,不像 3DS 上的 ACNL 可以使用双屏 + 画笔来做画。在 Nintendo Switch 上使用手柄做画有多难受,可想而知。虽然基础画板只有 32 x 32 像素,但是切换颜色、工具等操作,实再不如在电脑上作画来得舒服。我想,如果能直接在 Aseprite 这种专业软件中作画,然后直接生成二维码,再传送到游戏里使用,岂不是非常方便。

其实在电脑上作画的并生成二维码的想法,已经有人实现并开源了 Animal Crossing Pattern Tool。这是一个基于 Vue 的 Web APP 实现。虽然它的 Editor 非常简陋,远没有 Aseprite 好用。但是它实现了 ACNL 图案文件的格式解析、ACNL 调色盘数据等重要功能,还支持复杂的衣服 3D 预览,也可以导入外部图片,已经是非常强大。

从 Discord 社区的互动可以看来,确实有很多像素艺术创作者使用 Aseprite 绘制图案,然后保存成 PNG 图片,导入到 ACPatterns 生成二维码,再用手机 APP 扫描后导入游戏。如果能实现直接在 Aseprite 里生成二维码,则可以省下一大半的操作。

有了现成的 ACNL 编码方案,还需要知道如何生成二维码。(题外话:正好回型针视频上周发布了一期二维码的秘密,有兴趣的朋友可以从这里了解到二维码 QRCode 是如何工作的)。ACPatterns 使用的是 zxing-js,而我们则需要 Lua 语言的 QRCode 实现。幸运的是,我正好在 GitHub 上找到了一个开源的 LuaQRCode

通过阅读 ACPatterns 的源码,大致了解到了 ACNLFormat 的一些限制:仅支持 15 个颜色 + 1 个透明色,共 16 个颜色索引,图中的每个像素引用一个颜色索引。其中编号 0x0f 即 15 为透明。而最终编码只用了 15 个字节储放 15 种颜色。每个字节范围 0 ~ 255,表示一种预定好的颜色。颜色表则是硬编码的,在上述源码中可以看到。

核心的东西都有着落了,然后我们就可以开始写插件。Aseprite 的 API 文档可以在这里找到。同时官方还提供了一些 Demo 供开发者参考。

我需要用到的比较核心的几个接口:

  • app - 通过 app 可以获得当前活动的文档(Sprite)以及图格(Cel)。
  • app.command - 可以用来执行所有可用的命令。
  • Sprite - 精灵,即 aseprite 的文档,提供一些重要的配置信息,如图的尺寸、调色版模式、调色版、透明色等。
  • Cel - 图格,在编辑器中作画的单位画布,提供当前图像的容器尺寸及坐标。
  • Image - 在画布中的图像,存有每个像素的信息,但是如果要获得像素在画布中的位置需要加上 Cel 的偏移量。
  • Palette - 调色盘,在索引模式中,按编号储存具体的颜色信息。
  • Dlg - 对话框,绘制插件的基本界面,提供标签、输入框、按钮等组件。

第一个版本我只需要最基本的 32x32 图案二维码生成。程序的思路很简单:

  1. 检查当前的像素图是否符合标准:长宽 32 x 32;颜色模式为索引;颜色数据不超过 16 种;实现上我直接用不可点击的 Checkbox 来展示这个 Check List。虽然这并不是正确的 UX 示范,但对于一个小脚本来说,是个比较取巧的方案。
  2. 提供几个输入框供用户输入标题、作者等信息
  3. 生成 QRCode 按钮,图片不符合标准的时候不可点击。

screenshot-1

当按下按钮的时候:

  1. 将当前文档所有可见图层合并,然后从合并后的图像中读取所有像素点。记录它们引用的索引编码到一个数组中。由于 Aseprite 的图像是支持多图层的,所以需要合并后再读取比较方便。
  2. 马上执行撤消命令,还原合并操作,不破坏原本的图像文档。这一步很重要。
  3. 将用户信息、调色盘、图像信息按 ACNLFormat 中描述的二维码的数据布局生成字节缓冲数组(Buffer)。并调用 Luaqrcode 的接口生成二维码矩阵。
  4. 新建一个空的 Sprite 并绘制矩阵。

注意到图像中的每一个像素其实是由调色盘的索引表示,范围为 0x00 ~ 0x0F,只需要占用半个字节,而 32 x 32 的图像,共 1024 个像素,只需要 512 字节即可以表示。所以在编码的时候,动物森友会选用了版本 19,容错等级为 M 的二维码,可以容纳 624 字节的二进制。加上调色盘和一些画家信息,实际只使用了 620 字节。最终生成图像如下:

screenshot-2

可以直接通过 Nintendo Switch App 扫描后传送到游戏中。由于二维码的高效容错率,甚至可以将其放大后,将原图覆盖部分二维码,压制成独立的图片用于分享,依然能够正常扫描使用。

未来如果有时间,我会考虑增加更复杂的图案的二维码生成,例如各类衣服、帽子等。不过 Aseprite 暂不支持 3D 预览,所以还没有比较好的用户体验方案。

项目的源码已发布到 GitHub 上,可以在这里获得。


Jun 25, 2020 Update: 带娃之余的时间,给插件增加了服装类二维码生成,还自己实现了软件渲染器,可以生成 3D 模型设计预览。有空会另外写一篇博客记录一下最近学到的东西。