写了一个敲木鱼的小游戏
起初我在研究 ebiten/audio ,然后发现手里的声音文件听起来很像是在敲木鱼,于是快速打开 Aseprite 画了一个敲木鱼的动画草图,手动播放音频给动画配音。感觉还挺好玩,像是某种反向的音游,于是决定把这玩意儿给写出来。
基础需求
能够想到的大概有三个模式:
- 手动模式:手动触发敲击木鱼发出声音
- 自动模式:自动循环播放敲木鱼的动画
- 音游模式:根据动画在合适的时间按下按键发出声音
另外需要一个简单的UI框架,要有文字显示,菜单之类的组件。
界面部分
核心思路是,每个元素都会在屏幕上占据一块矩形区域,其大小和位置取决于父元素的行为,所以每个元素都要有一个 SetBounds() 方法保存自己的位置和大小。除了少数元素会提前写明尺寸信息,大部分元素都是非常弹性的,会根据可用空间调整自己的尺寸,然后不同类型的容器又会根据子元素的尺寸信息调整子元素的位置信息。刚好 Ebitengine 会调用根节点的 Layout() 方法,所以只要 Layout 阶段每一层元素都计算自己的尺寸信息,再根据这些数据一层层调用 SetBounds() 方法,排版工作就完成了。事件和 Focus 状态的管理也可以这样一层一层的调用诸如 HandleInput() 和 FocusNext() 之类的方法递归完成。
然后这个框架需要能在不同的“页面”之间导航,例如从主菜单前往设置页面。核心思路是,丢给 Ebitengine 的根节点是不变的,需要加载一个新页面的时候放在后台加载资源,完成之后替换当前展示的内容。替换的时候开始播放过渡效果,这里的资源加载还有动画曲线之类的东西就是另外一个话题了。
然后一点巧思,有的元素需要边框或者边距,但是不是所有的元素都需要,于是特意加了两种单独的容器处理这个问题,这样其它元素 Layout 的时候要考虑的问题也简化了很多。
多语言和主题切换
虽然只有中文和英文,但也是支持了语言切换的,这一部分文本量不大,直接用了 Golang 自己的 message 库。
然后很取巧的一点是,在语言菜单中选择语言之后,必然会跳转到一个不同的页面(上一级菜单),所有内容都重新创建了,所以完全不需要去动态更新什么东西。包括后面的主题切换,素材切换都是这么实现的。
存档功能和文件加载
所谓存档,就是一段 JSON,只是在 Windows 上是写进文件里,而在 WebAssembly,是写进 LocalStorage 里面。然后因为 _js.go
只会在 Web 平台编译,在这里把存档读写的函数覆盖一下,其它部分完全不用修改就可以同时兼容两边。
从文件加载更多主题,在 Windows 上是通过先读取预先配置好的文件夹筛选符合要求的文件,然后加载文件内容实现的。在 Web 上也差不多,只不过本地的目录变成了网络位置,然后用正则表达式解析 HTML 拿到文件名的列表。有一个地方需要改进,在开始的时候读取所有内容,在 Web 上是一件有点耗时的事情。
DEMO和代码
Demo 托管在 itch,有 Web 版本可以体验,另外提供 Windows 下载。Linux 和 macOS 因为不方便没有构建。