[暴躁教学3]展示实体与你:数据包的究极加强
前言
观前提示:本教程是零基础傻瓜式教程,会做资源包的/会写点指令的/会做点模型的建议自行找别的高级教程自学。
另外用BlockBuster的就不用看了。不过基岩版倒是真能用,就是资源包什么的麻烦点——虽然可拓展性更强。

欢迎回到这个我也不知道到底多久一更新的奇怪教程。老规矩,这是上一期:

在上一期——那时候终曲告诫还在拍摄中——我大概说明了一下1.19制作MCARG(实际上是MC短片)的可选方案。
在那时,Taterzens+Replay的搭配似乎已经能够让我们小小地爆一下BlockBuster的金币。然而,奈何BB终究有一个恐怖的功能令高版本玩家们望尘莫及:

自定义模型。
简单来说,BB在不需要其他模组的情况下,允许玩家自己导入各种乱七八糟的模型,并控制它们的运动——在曾经的1.19,若要实现这种效果,唯一的办法似乎就是给盔甲架头上套个带CustomModelData的玩意然后想办法让他动两下。
这么做可行吗?确实可行,但一是用指令控制盔甲架的移动实在太麻烦,二是但凡你的模型大一点就没辙(何况只能导入JAVA版的JSON模型,虽然到现在也是这样)。
也因此高一点技术力的MC动画都会选择BB起步C4D封顶的制作方式。
直到1.20的更新。
数据包的史诗级加强
想象如何在MC中实现以下画面:
一架带有航行灯J20垂直起飞,喷射出大量烟雾,缓缓上升后收起起落架,水平飞行后以15度仰角向上飞行;
50架无人机,以不同的上升速率缓缓上升;
坦克与步兵在地面共同行进,要求坦克炮塔需要旋转;
克苏鲁画风的生物,要求触手会转;
一架武 装 直 升 机的旋翼开始不断旋转,由慢到快,最后机身脱离地面开始上升;
B-2轰炸机在飞行中打开弹舱,制导炸弹向下坠落一段时间,然后启动发动机喷射烟雾以更高的加速度向前飞行;
一架客机在空中发生剧烈爆炸,产生大量粒子效果,碎片分成几块拖着烟雾下坠;
直径几百格甚至上千格的巨型BOSS,头顶有烟雾云在旋转;
一整个航母战斗群在海面上航行,激起浪花,飞机从上方起飞,驱逐舰上的1130近防炮旋转并搜寻目标;
……
我现在告诉你:1.20原版就可以实现以上所有画面,不嫌麻烦你连Replay都不用装。
而实现这一切,都拜它所赐——
minecraft:item_display
详解
第一部分:CustomModelData
简单来说,item_display(物品展示实体)是一个极其牛b的东西,在为它赋予如下NBT时,物品展示实体可以自由展示任何CustomModelData(下文简称CMD)的模型:
其中的X是介于±16777215之间的整数,多了会溢出。
这串NBT描述了一个ID为diamond,也就是钻石的物品(其实选什么都可以),数量为1,而他的物品标签谓词中包含了这么一个值:CMD=X。
在你做好资源包后,游戏就会用资源包中指定的模型替换CMD=X的物品模型。这么说可能有些迷惑,那我实际演示一下:

ok,找到储存物品模型的文件夹models/item了吗?下面打开我们要找的diamond.json:
正常情况下,你看到的应该就是这个。
"parent"代表这个模型是从哪个模型继承来的,如果没其他情况他就会使用parent这个模型;"textures"则定义了这个模型的材质。我们看到这个模型的parent是“item/generated”,这个意思大概就是钻石的模型是由钻石的材质自己生成(generate)的,大概就是这样:

略微偏题了,现在我们回来讲怎么让钻石显示不同的模型。
格式大概是这样:
一脸懵逼?我们细看一下。
首先最开始的部分就是未经修改的diamond.json,而之后的"overrides"则制定了“在什么情况下用什么模型替换原模型”,而下面的“predicate”就是条件。
的意思就是:“在custom_model_data为1的情况下,将钻石的模型显示为model_1.json”。
根据上面那个模板,你可以一直往下写下去,具体可以参考WIKI。

第二部分:物品展示实体
我们先贴指令:
这一指令会在玩家所在处生成一个物品展示实体。你可以直接改变它的CustomModelData以便于直接显示不同模型,但我们先从基础的开始。你应该会看见这个:

目前为止,这玩意似乎像是盔甲架手持物品的Pro版本。确实,它没有碰撞箱,不产生更新,几乎不会造成任何性能负担。那么它还有什么神奇的地方吗?
把下面这段指令输到命令方块里,然后启动它感受一下就知道这玩意潜力有多大了。
发生了什么?这玩意为什么能平滑地变 大 变 高?现在我们分析一下这段指令:
/data 是用于修改或查询物品NBT数据的指令。/data merge entity 可以将一段NBT与某个实体的NBT合并并覆盖,后面的选择器则是选择类型为物品展示实体(type=XXX)、数量限制为1(limit=1),并且距离最近(sort=nearest)。
至于后面的一大串NBT则是展示实体专有的“插值变换”属性——他们是这么定义的:
transformation:包含后面所有,声明整个插值过程。
translation:在XYZ轴上的位置变化,即平移。格式为[Xf, Yf, Zf],其中f代表浮点数,XYZ代表展示实体在XYZ三轴上的位移。
scale:在XYZ轴上的大小变化,即缩放。和上面差不多,[1.0f, 1.0f, 1.0f]即原大小,XYZ代表每个轴上的缩放格数。
left_rotation或right_rotation:比较难的地方来了:旋转变换。这里用的是轴角写法,angle是弧度值,最大6.28,例如90度就是1/2π=1.57。后面的axis定义旋转轴,依然是XYZ形式,如[0.0f, 0.0f, 1.0f]代表绕Z轴旋转。旋转变换还有一种四元数写法,但太特么麻烦了所以此处略过。
然而,超过3.14的angle值将会被自动计算为沿反方向旋转的angle值——例如,4将被自动换算为3.14-4=0.86。因此,只设置其中一个最多让实体旋转半圈(180°=π)。但你可以同时将两个angle值设置为3.14,由此让实体旋转一圈(360°=2π)。
至于为什么有两个旋转变换参数,我也不知道,反正不重要。
start_interpolation:动画开始的时间,0就是立刻开始,100就是延迟100刻开始。
interpolation_duration:动画持续时间,0就是瞬间变化,100就是在100内完成变化。
关于插值变换,必须要说明一些有些反直觉的事实:
在你敲下命令的一瞬间,实体的变换值就已经设置完成,例如translation从[0f, 0f, 0f]到[1f, 0f, 0f],这个值是瞬间完成变换的,中间并不存在[0.5f, 0f, 0f]这样的“过程”。
插值变换只会在渲染上变换,实体真正的XYZ坐标是不变的。translation的那个坐标只是它“看起来”移动了多少,不信可以开F3+B。
但无论如何,它仍然提供了一种导入任意大小的自定义模型并使其运动的方式(scale和translation的大小没有上限!),而说到如何制作MC中的自定义模型,我们最终还是绕不开一款著名的建模软件:BlockBench。

第三部分:简易建模教程
BlockBench的介绍这里略过,你只需要知道BB(不是BlockBuster!)可以做JAVA版、基岩版、模组格式甚至其它游戏的体素风格模型就可以。我们只介绍它的JAVA版模型制作。
JAVA版模型本质上是描述一堆方块堆起来的JSON文件,它有几个限制:
任何方块在一个轴上旋转22.5°的倍数。例如,你不能在X轴上把一个方块旋转30°,或者在XY两个轴上旋转45°。
模型体积不能大于3x3x3,默认显示的缩放倍数无法超过4。
很容易发生Z-fighting。
无法内置动画(我们在后面会想办法解决这个问题)。
不过,这些限制也算不了什么。安装(BB官网是很慢的,建议找个镜像)并打开BB后,你将看到这个界面。


文件名建议用小写字母加下划线,父级模型不用填,后面用默认的就行。

添加地一个方块后,你可以试试自己上手。BB是个相当简单好用的建模软件,简单到我第一次用就能做出这玩意。

可观看此教程:

现在假设你已经整了一个自己的模型,那么是时候开启第四部分——数据包制作了。

第四部分:数据包
回到我们的游戏。把BB的模型(.json,不是.bbmodel!)导出到models/item,按照第一部分的教程设置好CustomModelData,然后刷新资源包。用如下命令修改CMD:
一切顺利的话你就能看见你做的模型出现在MC里了。
顺便说下,模型的材质在\assets\minecraft\textures\block或者\item里面,选哪个都问题不大。
其实模型也可以调用models\block中的模型(
现在使用/tag命令给你的展示实体分类,以后就可以精确选择了:
他将为离你最近的一个展示实体添加标签tag1。在之后修改实体的插值只需要
即可。
现在,按照差不多这样的格式(更详细的教程自己找)创建一个数据包:

如果你看过数据包教程,你就会知道tick.json定义了每刻执行的MCFUNCTION函数。换句话说,这些命令都会不断地执行。
那么使用数据包制作展示实体动画的思路就很明确了:每刻使计分板timeline增加1,并检测timeline的值,若达到X则执行对应的插值变换。相同地,我们也能生成粒子效果之类的特效。
实操步骤如下:
首先创建loop.mcfunction,用于每刻执行函数:
tickloop.mcfunction,用于增加timeline的值:
stop.mcfunction,用于停止动画执行:
start.mcfunction,用于开始动画:
animation.mcfunction,定义整个动画时间轴:
上面这个只是提供一个参考,即:在timeline达到某个值时,要求tag为“展示实体tag”的展示实体修改自身的transformation。你可以把这段复制很多行,然后修改游戏刻条件,例如交叠理论PV最后的那段B2坠毁画面(部分):
我个人十分建议你在animation.mcfunction的开头把被动画影响的展示实体的transformation值重新写一遍,也就是开头将动画“恢复到初始状态”。
当然,tick.json也需要定义。
最终的效果应该是:执行/function namespace:start后,动画开始自行播放;执行/function namespace:stop后,动画停止播放。
尽管JAVA版模型无法设置动画,你可以通过将许多个模型设置相同的tag,然后令其中一些模型在“相对运动”的基础上自行运动。如一开始说的直升机,你可以将旋翼和机身分别导出,将他们的相对位置设置好,并让他们以相同的位移上升,但只给旋翼加上旋转动画。投弹、炮塔旋转之类的动画也是如此。
由于实体的translation值旋转并不会影响它的实际坐标,你可能会遇见为实体添加粒子效果的时候,实体在移动而粒子效果无法移动的现象。一种解决方案是在实体的移动路线上每隔一段时间就释放粒子。你也可以尝试如生物绑定之类的方法。

第五部分:尾声
这次的教程显然比较复杂,但合理地运用物品展示实体确实能做出惊人的效果。在此我推荐几个教程:
展示实体/数据包

资源包/BlockBench

/execute与/data命令详解

当然,最后,也是最重要的网站:
在任何情况下,查wiki都能解决你95%的疑惑!而且wiki里是有技术向教程的!
(热心提示:这个链接指向MC维基在BWIKI的镜像站,速度非常快)

END。