多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
# 创建带有自定义模型的方块 **难度分级:☆☆** 在上一章中,我们只能创建出模型为Minecraft标准立方体的方块。然而,在很多情况下,我们希望能够自定义这些方块模型,使其视觉效果更为多样化。本章我们来实现这一目的。 ## 自定义模型文件 要让方块拥有自定义模型,你需要首先为该方块准备一个模型文件。Forge为模组开发者提供了三种格式的模型文件可供选择:**Minecraft原版模型格式(.json),Blitz3D(.b3d)以及 Wavefront OBJ(.obj)**。下面将依次进行介绍。 ## 使用Minecraft原版模型格式(.json)创建带有自定义模型的方块 Minecraft本身自带有一套完整的自定义模型格式规范,其文件格式和上一章所介绍的**JSON**文件格式一致。关于Minecraft原版模型格式你可以在这里找到更为详细的描述:[Minecraft Gamepedia]([https://minecraft.gamepedia.com/Model#Block\_models](https://minecraft.gamepedia.com/Model#Block_models))(需使用科学上网访问)。目前互联网上已经有相当一部分十分优秀的Minecraft原版模型建模工具,其中十分具有代表性的一款就是**BlockBench**,你可以从这里 [链接]([https://blockbench.net/downloads/](https://blockbench.net/downloads/)) 下载到其最新版本。关于建模部分本文在此不做赘述,你可以在互联网上自行查阅建模工具的使用方法。(如果是为EOK项目制作模型可以咨询GMG) ### **模型文件的设置** 使用建模工具生成的JSON文件中对于贴图路径的定义往往和项目中不同,因此你需要手动将它们指向正确的位置。首先将你的自定义模型重命名为**该物品的RegisryName.json**放进 **\\models\\block\\** 中,将该模型所用到的所有贴图放进 **\\textures\\blocks\\** 中。使用文本编辑器(Notepad++/Sublime Text等)打开JSON模型文件,它的格式类似这样: ~~~ { "credit": "Made with Blockbench", "textures": { "0": "某贴图位置", "particle": "某贴图位置" }, "elements": [ ... ], ... } ~~~ 注意到 **"textures"** 中的贴图位置和模组中应有的格式不匹配,因此你需要手动将它们重定向到你**的贴图所在位置**,他们的格式如下: ~~~ "textures": { "贴图编号0": "你的模组modid:blocks/该模型使用到的0号贴图", "贴图编号1": "你的模组modid:blocks/该模型使用到的1号贴图", ... "particle": "你的模组modid:blocks/该模型粒子效果使用到的贴图" } ~~~ 修改完成后,就可以保存关闭了。 ### **碰撞箱(Bounding Box)** 碰撞箱是Minecraft用来描述**实体/方块占用空间多少**的一个概念,在游戏中表现为一个**矩形的空间**。在游戏中,你可以通过快捷键**F3+B**看到每个实体的碰撞箱。当游戏检测到玩家面前有一个碰撞箱时,便会**阻挡玩家向着碰撞箱方向运动**。由于自定义模型的大小可能不足一个方块,因此我们往往也希望该方块的碰撞箱能够恰好匹配模型大小。 首先你需要在自定义方块类中新建一个由**坐标描述的碰撞箱变量(Axis Aligned Bounding Box,在代码中的类型名为AxisAlignedBB)**,它的定义方式如下: ~~~ //x1,y1,z1,x2,y2,z2均为double类型 public static final AxisAlignedBB 变量名 = new AxisAlignedBB(x1, y1, z1, x2, y2, z2); ~~~ 。该类型的构造函数需要我们传入一组**矩形空间的对角线坐标**,即**描述碰撞箱体积的坐标参数**。在Minecraft世界中,**每一个方块空间**都可以抽象描述为一个以 **(0,0,0)** 和 **(1,1,1)** 为对角线端点的**矩形空间**,如下图所示: ![](https://img.kancloud.cn/a7/3f/a73f3fcb4b8da4120753da6b7aff0683_642x519.png) 因此,定义该变量的构造函数中的 **(x1,y1,z1)** 和 **(x2,y2,z2)** 分别代表该碰撞箱矩形在**每一格内部**的**对角线起始点和终止点** **(xi,yi,zi>0,i∈{1,2})**。由于Minecraft自身坐标轴的单位长度为**1/16(即0.0625D)**,因此你的每一个坐标值也必须是**0.0625D的倍数**。如果你的自定义模型超过一格,你也可以让**终点坐标大于1**。 例如在EOK中,对**双筒真空泵(Two Barrel Vacuum Pump)** 的碰撞箱 **(长1宽1高2)** 定义即为: ~~~ public static final AxisAlignedBB TWO_BARREL_VACUUM_PUMP_AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 2.0D, 1.0D); ~~~ 随后你需要将该碰撞箱变量与方块绑定。你可以通过直接**覆写**Block父类中的 **getBoundingBox()** 函数来做到这一点。例如EOK双筒真空泵方块类中的代码: ~~~ public class BlockTwoBarrelVacuumPump extends Block implements IHasModel { ... @Override public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) { return TWO_BARREL_VACUUM_PUMP_AABB; } } ~~~ ### **一些细节问题** 现在你的自定义模型方块已基本完成,不过还有一些细节问题需要处理。首先我们需要**覆写**Block父类中的两个函数:**isOpaqueCube()(是否为透视方块)** 和**isFullCube()(是否为完整方块)**。对于前者,除非为某些十分特殊的方块(如透视方块(**作弊警告!**)),请将它的返回值设置为**false**,否则会出现**地形透视**的渲染问题。对于后者,只要我们的模型不是一个**完整的1x1x1**的方块,就请将它的返回值设置为**false**。例如EOK双筒真空泵方块类中的相关代码如下: ~~~ public class BlockTwoBarrelVacuumPump extends Block implements IHasModel { ... @Override public boolean isOpaqueCube(IBlockState state) { return false; } @Override public boolean isFullCube(IBlockState state) { return false; } } ~~~ 随后,如果你的材质中含有**半透明/透明材质**,你还需要覆写Block父类中的 **getBlockLayer()** 函数。该函数只能在**客户端**上运行,因此你需要在函数前加上 **@SideOnly(Side.CLIENT)** 的注解。该函数的返回值是一种叫做**BlockRenderLayer**的Minecraft自带类型。其中**BlockRenderLayer.CUTOUT_MIPPED**为类似树叶这样**材质仅覆盖方块的一部分**的方块,**BlockRenderLayer.CUTOUT**为材质中**有光线可以透过部分**的方块,**BlockRenderLayer.TRANSLUCENT**为材质中有 **半透明部分(光线可以透过一部分)** 的方块。例如EOK双筒真空泵方块类中的相关代码如下: ~~~ public class BlockTwoBarrelVacuumPump extends Block implements IHasModel { ... @SideOnly(Side.CLIENT) public BlockRenderLayer getBlockLayer() { return BlockRenderLayer.TRANSLUCENT; } ... } ~~~ ## 使用Blitz3D(.b3d)或 Wavefront OBJ(.obj)创建带有自定义模型的方块 //待补全