【心得】【1.16+】在地图中使用名条显示动画的方式与教学(附超简单使用的工具、数据报)

先上效果图

大家好,我是猫狗喵

1.16 出了一个方便的东西叫做自订字体档,不过目前好像没看到它被拿来做什么有趣的应用。那刚好最近趁八月去当兵前帮 Terry 做还原枫谷的系统,其中很多特效就使用名条动画来呈现,所以今天就来分享如何靠自订字体档做到名条动画的效果吧!
对了如果有人有兴趣这个在 minecraft 还原枫谷的计划,近期应该会以制作日志的形式发文,其中也会包含一些应用技术分析,有兴趣的可以追踪一下
喔还有,根据过往经验,每次我发技术文大多都是大家看看觉得有趣,然后还是没看到有人拿来应用,所以这次我打算更改一下我的文章内容安排。这次开头就上如何快速把这个功能套用在你地图里的方法,后面才讲解原理,想了解运作原理的记得看到后面嘿

一步步教你在地图中套用名条动画

1. 首先下载 Font Animation Creator 这个程序

度的我写的,这两天才赶工把他改写成图形接口的程序所以写得很丑

原码都附在里面了,想改写请注明原作,然后如果有 BUG 可以跟我说但我不见得会修

2. 解压缩到文件夹后会看到下面四个文件,运行 Font Animation Creator.exe 就对了

3. 点开后等他一段时间会出现下面这个画面

功能解释:

  • A:动画要导入哪一个资源包文件夹内,右边的按钮可以选择文件夹
  • B:添加一张图片列表 E 时,该画格缺省的停留时间
  • C列表 E 中目前选择的画格停留的时间
  • D:选择一个 GIF 档导入列表 E
  • E:动画画格列表,顺序由上到下,可以用拖曳的方式调整画格顺序
  • F:添加一张图片到列表 E,要注意所有图片都会置中对齐
  • G:移除列表 E 选择中的画格
  • H:清空列表 E 的内容
  • I:预览动画效果,在游戏中会显示原本的大小,但分辨率最高就是如预览的这样
  • J:当你在游戏里绕着图片跑的时候,他会以哪边为旋转轴面向你
  • K:如何把当前动画间隔转换成 minecraft 中的动画间隔,不懂就用默认值就好
  • L:把列表 E 的内容转换成 minecraft 的名条动画,并在目标资源包内保存相关素材

4. 全部设置好后按「创建」按钮,他会叫你帮动画文件取一个名字,高兴取什么都行

5. 创建完成后会跳出字体档存放的文件夹,里面有一个 mcfunction 文件,就是用来生成名条动画的

6. 下载倒退字符资源包,把它的内容全部丢进你自己的资源包里面

要注意使用这个资源包是需要原作表示的,不过内容的修改等等就完全没有限制

7. 在这里下载 Font Animation datapack 这个数据报,或是在 Font Animation Creator 的文件夹里面也有。把它丢到你地图的 datapacks 文件夹里面

8. 上一步的数据报有安装成功的话,进去游戏应该会看到安装成功的消息。

这时候就可以把上面的 summon.mcfunction 丢到自己的数据报里面,并且运行来看看效果了!

如何?是不是真的超简单?这次大家总该把这技术拿来用了吧?

如果大家有使用这套工具的话希望可以在地图中注明一下,不过真的没标注我也不会咬你就是了

如果你想知道其中的一些选项实际有什么功能,可以跳到最后选项效果解说的部分来看


动画名条的原理教学

终于来到众所期待的教学环节了(还是说其实没人想知道,大家只想要工具而已?)
这次的教学我也会改变一下内容呈现的方式,不同于以往直接把一卡车的内容倒下去,这次我会试着把我一些思路历程跟主要的技术点列出来,有兴趣的不妨跟着思考看看粗体字的问题要怎么解决,想好了或是想不出来再往下看我的解法

==============   正文开始   ===============

  • 如何让文本图片照顺序更替?
(如果你在这边想到用 list 的作法的人不要急,这作法我后面再讲)
在过去版本中最直觉的想法应该是:透过分数穷举对应的文本图片。不过穷举这种东西就是浪费性能,又没有泛用性,每次做新的动画就要再穷举一次、多做一套连闪侦测
不过到了 1.16 出了自订字体档后就不一样了,在游戏中我们可以不用穷举自动依串行出文本的方式就是数字显示,不管是记分板还是 nbt 数值,我们可以轻易的运算然后用 json 格式显示出来。如果还不清楚如何把分数写进 json 字符串可以看这篇,我过去都是用 loot table 法不过听说告示牌法比较省,所以现在也换成告示牌法了。有了依串行出文本的方式后,我们只要把

图片对应的数字文本写进自订字体档,然后在我们的 json 字符串声明使用的字体就可以了。

那这边又会遇到两个问题:

1. 要怎么声明我们 json 字符串要用哪个字体?

声明字体好像很单纯,只要把 font 写进 json 里面就好了,然而问题在于怎么知道要写什么 font 进去。如果每个动画个别使用不同的 json 声明,那还是没有解决穷举法一个动画需要一套连闪的问题

这时候就要用一点小技巧了,那就是利用 json 解析的特性

常用 json 生成器的人应该会发现,生成器产生的中括号 […] 的内容,开头第一个对象基本上都是空字符串,以前我也一直觉得意义不明,后来才知道它的功能是什么。在 WIKI 页面中也有提到格式的继承关系。如果你用 data get 把中括号解析后的新字符串抓出来看会发现,中括号其实就是被解析成第一个对象 extra 其它对象的格式

利用这个特性,我们只要把字符串以中括号或 extra 形式写好,第一个对象填入我们要的字体格式的空字符串,第二个对象填入我们要显示的数字就完成了。不过这里又会遇到一个小问题

怎么针对每个不同的动画填入不同字体的空字符串?


我的作法是事先写好,以字符串形式存在显示名条的实体身上,例如 ‘{“text”:””,”font”:”test:main”}’。然后当要解析 json 的时候,只要用 json  当中的 nbt 搭配 interpret 的效果就可以还原出那个有字体的空字符串了。

2. 数字只有 10 个,动画画格数超过 10 个怎么办?

要想打破数字的数量限制,势必得使用更多的字体档。在上一个问题我们已经知道要把有字体的空字符串存在名条实体身上,那接下来的问题就是

要怎么存更多的字体,并且依序替换?

我的作法很简单,就是使用 list 来保存那些字符串,解析 json 时固定填入 list 的第一项,然后每显示完 10 个一组的数字就把 list 第一个对象移除掉。

听到这里,一开始就想到 list 法的人应该已经按耐不住了 我这不是来了吗.jpg

我也是在打这篇文章的时候才想到,其实还有一套不需要数字,也不需要多个字体档的作法。那就是事先把每个画格的图片存成自订字体档中的各个文本,然后把那些文本全部依序存在 list 里面,这样我们只要每个画格显示 list 的第一个字,然后移除第一个 list 的对象就搞定了

说到这里,感觉好像制作名条动画的工具都已经俱备了,但其实还有一个小问题还没解决

每个画格的停留时间该怎么设置?

我们刚刚说的「每次」更换一个显示的文本,原则上就是每 tick 运行一次。但是 1 tick 就是 50 毫秒,先不考虑实际动画中每个画格的停留时间常常不是 50 毫秒的整数倍的问题,假设现在同一个动画中有的画格停留 100 毫秒,有的停留 200 毫秒,我们要怎么处理呢?

或许你会想到另外再开一个 list 保存每个画格的停留 tick 数量,不过这个方法有点复杂,也需要比较多的运算。这里我采用的方法是:一个画格不够,那不会再一个吗?

以我的显示数字的作法来说,假设第一个画格会停留 200 毫秒,那我就把 0123 四个数字全部都设置成同样的图片不就搞定了吗(茶

那如果你用 list 法原理也是一样,同样的一个字塞四次就解决了

到这里一套优雅的,免穷举的名条动画显示系统就完成了。只需要一套连闪,召唤的时候填入不同的字符串就会自动显示不同的动画。下一步要提到的则是进一步优化相关的技巧,如果对系统性能不在意的可以跳到下个分隔线后,关于 Font Animation Creator 部分选项效果解说的部分

  • 如何透过 药水云(area_effect_cloud) 来当显示名条的实体?
或许有些人还不清楚,不过药水云在性能上比起盔甲架或掉落物等实体节省了 10 倍左右,因此非必要的情况下使用药水云作为实体可以大幅节省资源
于是我就在想这个功能是不是可以只用药水云来达成,显示名条的部分只要是实体就能做到,用药水云绝对没问题。问题出在字体的 list 该存在哪里
盔甲架或掉落物可以透过道具字段的虚拟 nbt 轻松创建一个字符串的 list 来访问字体 (还不知道虚拟 nbt 是什么的自己回去看这篇),但是药水云可就没有那种方便的东西了。翻遍药水云的 nbt 数据不要说是字符串 list 了,就连字符串都找不到几个。撇除 CustomName 是我们要用的,剩下的字符串数据就只有 Particle 而已,设成原版没有的 particle 还会被强制改回去。就在打算放弃的时候突然想到还有一个东西可以用,那就是所有实体都可以有的 Tags
不过如果你直接开开心心的把那些字体的 json 字符串丢进 Tags 你会发现,那个顺序是在哈啰?
如果他是单纯的单个数字的字符串,看起来好像又会照顺序,但只要加上其他字以后整个顺序就找不出规律了。这时候有点程序 sense 的人应该就会猜到,结合这个摸不着头绪的顺序,以及内容不能重复的特性,答案就是……
没错 Tags 是用 HashSet 去存的,没学过程序的只要知道他会经过一串数学公式去得出他所属的位置就好了
那因为 Java Edition 的 Minecraft 是用 Java 写的(废话),可是我又查不到 Java 的 Hash 公式是什么,为了验证我把人生第一次写 Java 的经验就用在这上面了。(后来听强者我同学说 Java String 的 Hash 公式是把第一个字符乘以 31 再加下一个字符,重复以上动作到最后一个字。不过不知道溢出的话怎么处理,我也懒得验证所以就算了)
而 Font Animation Creator 当中我给 Tags 排序的方法就是先丢进 Java 程序存到 HashSet 再吐回来给我,想要的可以直接运行 PrintSet.exe 那个文件,输入几个字符串然后用空格隔开,他就会回传 Hash 后的顺序了,或是你直接开 Minecraft 把 Tags 写进去再抓结果也可以知道顺序。
那知道 Tags 的顺序之后我们就可以像一般字符串 list 那样使用 Tags 来访问数据了,要注意的只有不能给它乱加其他的 tag 进去,要不然你不知道他被排到哪,哪天他就被拿来当成字体格式字符串你都不知道
另外前面提到的完全用 list 来保存每个画格要显示内容的方法,在这边也需要一些调整。前面提到如果一个画格要显示 4 tick 那你就要把同样的图片文本塞 4 个进去,但是 Tags 是不可重复的,也就是说你没办法塞 4 个相同的字进去 Tags 里面,这时候你就必须同一张图片用 4 个不同的字来显示,而且这 4 个字的顺序要排在一起,在计算顺序的时候相对来说麻烦了一点

做到这边,数据报的部分就可以划下完美的句点了,至少我也没想到什么更好的做法了,可喜可贺
接下来就是 Font Animation Creator 中一些选项与效果的解说

Font Animation Creator 部分选项效果解说

终于来到最后的部分了,这篇文章打到现在已经花了一天多了,幸好巴哈现在有备份功能,要不然想隔一段时间再编辑还要先复制原码真够麻烦的
  • 图片分辨率与大小关系
在自订字体档中有一个限制,那就是字体读取的图片长宽都不能超过 256 像素,超过就会死图
不过在游戏里面显示的大小就没有限制了(至少一般大小不可能超过),因此只要在分辨率最高 256 * 256 的限制下,还是可以在游戏里显示原始图片的大小比例
而 Font Animation Creator 中间预览的区块的大小就是 256 * 256,也就是说成品的分辨率最多就是像预览画面中的那样。为了保持各个图片大小比例的关系,如果有图片长或宽超过 256 的话,所有图片都会缩小「让图片列表中最大的图片压缩回 256 * 256 内的压缩比例」
另外在游戏中没有标准的图片大小的概念,所以我缺省在游戏中显示的图片长度数值是原图片的一半,这是我认为看起来最贴近图片在 Minecraft 中应该显示的大小比例。然后我懒得再把这个比例的控制写进程式了(排版好麻烦R),所以想要改的自己研究原码来改或是放大缩小原始图片的大小吧
  • 图片锚点功能解说
在 Minecraft 中名条的显示是会以中心点为球心旋转面向玩家的,球心就如下图红点所示,位于背景海苔条的中心
图片会自动置中,所以左右的旋转是固定的,但是上下的旋转就得看图片相对球心的高度了,这东西是由字体档控制的,看你需要以图片的哪个点为旋转中心就调到那个点吧
下面三张图由左至右分别是锚点为 0.0 / 0.5 / 1.0 时的图片与旋转轴相对位置
  • 帧分割公式解说
这应该是大家最看不懂的东西了,不用 Google 了,这两个选项的名词都是我取的
这部分主要就是要解决前面说的,每个画格停留时间不会刚好是 50 毫秒的倍数的问题
这里就拿下面这张图来解释一下 (没错这是魔力爪的画格停留时间图)
横轴是时间线,蓝线代表实际画格切换的时间,红色代表每个 tick 的时间,绿色待会再说
  • 时间门槛法
这个算法的逻辑非常直觉,就是我每个 50 毫秒(红线位置)都个别判断现在处于哪个原始画格的范围内(包含开头,不含结束),以上图来说,红色的 0, 50, 100 都属于第一个画格,150, 200 属于第二个画格,以此类推直到 600 毫秒的瞬间就消失了,也不用再切换画格了
一般情况下都建议使用这个算法,虽然偶尔会有画格延迟的感觉出现,但是 50 毫秒的间距并不会让这个感觉太明显。使用这个算法的优点是可以较还原原始动画的速度,并且在很多画格的停留时间小于 50 毫秒的时候,可以节省一些未使用到的画格图片的文件
时间门槛法还原枫谷天怒特效(每个画格固定 120 毫秒),偶尔有卡顿的感觉但不明显
  • 最小间距差法
这个算法其实也很直觉,只是有些特殊状况需要处理。这个算法的结果就如上图绿线所示
最小间距差,顾名思义就是最小化「显示的画格停留时间」,与「实际画格停留时间」的差距
以上图来说,各个画格停留的时间依序为 120, 90, 120, 90, 150 毫秒
在以 50 毫秒为最小单位的情况下,最接近的停留时间依序为 100, 100, 100, 100, 150 毫秒,也就是上图中绿线的分布情形
这个算法的优点是,当原始动画的各个画格停留时间很稳定,但并不是 50 毫秒的整数倍时,它可以有效的保持原始动画的流畅度,而不会有画格延迟的感觉出现
然而相对来说它就会导致动画的播放有变速的感觉,假设原始画格停留时间固定是 60 毫秒,用这个算法跑出来的动画就会有快进 1.2 倍的效果(显示的画格停留时间都是 50 毫秒)
而所谓的的特殊状况就是,当原始画格停留时间小于 25 毫秒时,这个画格最接近的停留时间就会变成「0」,没错毫无悬念直接死去。这就代表假如你把 40 FPS 以上的动画丢进这个算法里面,你会发现就跟把钱丢进枫谷的金苹果一样,噗通一声就不见了
为了避免这样的状况,所以我的程序在运行这个算法的时候,有限制每个画格最小的停留时间就是 50 毫秒,虽然这样就不会丢东西进去然后什么都没跑出来,不过你会体会到什么叫做「世界越快,心则慢」的超级慢动作特效
最小间距差法还原枫谷天怒特效(每个画格固定 120 毫秒),有了快进 1.2 倍的效果

好啦这次的教学就到这边结束了,真有够长的
这种可以自由显示图片的字体档其实从 1.13 版本就有了,我在浮光战记地图跟 DIO 数据报都有应用到,只是以前只能改原版的文本,所以不能乱改数字之类的,现在 1.16 有自订字体后终于更加活用了
关于字体档的格式说明大家可以看这篇,虽然是英文就是了
如果看不懂的话在下面留言敲碗,有人敲我再考虑写一篇相关的教学 (゚∀゚)
本文来自网络,不代表3楼猫立场,转载请注明出处:https://www.3loumao.org/3421.html
返回顶部