这是适用于Minecraft Java版1.21.4的Fabric模组开发系列教程专栏第十一章------创建方块。想要阅读其他内容,请查看或订阅上面的专栏。
方块(Block) 是构成Minecraft世界的主要组成部分,是组成游戏地图的最基本单元,也是模组开发的核心元素之一。
与创建物品类似,方块同样也需要在游戏注册表中注册,也同样需要创建对应的模型文件、模型描述文件和方块纹理。方块的复杂程度要高于物品,因此方块需要创建更多的配置文件来完成方块各种功能的设置。如果是首次阅读到本文且没有Fabric模组开发基础,请先访问我的世界Java版1.21.4的Fabric模组开发教程(二)创建物品;
在本章,我们将创建一个自定义方块------浓缩泥土(condensed_dirt)。文章将先以最简单方块的形式详细讲解创建方块的步骤,然后在最简单方块的基础上,拓展更多关于方块其他功能的配置方式。
通常,如果是首次创建方块,以最简单的方块为例,整个过程应当按照以下步骤推进:
- 创建方块注册类;
- 封装
register()
方法; - 注册方块并将其添加到指定物品组中;
- 在语言文件中为方块添加翻译键值对;
- 创建方块的模型文件、模型描述文件和方块纹理;
- 创建方块状态定义文件;
此外还可以为方块:
- 配置掉落物;
- 配置挖掘工具。
创建方块注册类
对于简单的方块,我们可以直接将其在游戏注册表中注册。不过,在此之前可以提前封装Minecraft API中提供的Registry.register()
方法,使注册过程更加简单。
一般,方块注册类中有三种内容:
register()
:封装了Registry.register()
方法并用于注册方块的核心方法,将在下一小节详细讲解;initialize()
:用于初始化方块注册类,需要在入口点类中调用;- 类型为
Block
的方块注册静态常量:用于注册自定义方块。
1.在com/example/test/utils
目录中创建ModBlocks.java
,作为方块注册类;
java
public class ModBlocks {}
2.声明静态方法register()
,用于注册方块;
java
public static Block register(){}
下一小节将详细讲解方法体中的内容;
3.声明静态方法initialize()
,用于初始化方块注册类;
java
public static void initialize(){
Test.LOGGER.info("注册方块!");
}
其中可以输出日志信息;
4.在入口点类的onInitialize()
方法中调用ModBlocks.initialize()
,完成方块注册类的初始化;
java
@Override
public void onInitialize() {
...
ModBlocks.initialize();
...
}
封装register()
方法
根据Fabric官方文档所述,应当使用下面的写法封装Registry.register()
方法,来简化注册方块的代码;
java
private static Block register(String name, Function<AbstractBlock.Settings, Block> blockFactory, AbstractBlock.Settings settings, boolean shouldRegisterItem) {
// Create a registry key for the block
RegistryKey<Block> blockKey = RegistryKey.of(RegistryKeys.BLOCK, Identifier.of(FabricDocsReference.MOD_ID, name));
// Create the block instance
Block block = blockFactory.apply(settings.registryKey(blockKey));
// Sometimes, you may not want to register an item for the block.
// Eg: if it's a technical block like `minecraft:moving_piston` or `minecraft:end_gateway`
if (shouldRegisterItem) {
// Items need to be registered with a different type of registry key, but the ID can be the same.
RegistryKey<Item> itemKey = RegistryKey.of(RegistryKeys.ITEM, Identifier.of(FabricDocsReference.MOD_ID, name));
BlockItem blockItem = new BlockItem(block, new Item.Settings().registryKey(itemKey));
Registry.register(Registries.ITEM, itemKey, blockItem);
}
return Registry.register(Registries.BLOCK, blockKey, block);
}
方法中需要传递四个参数:
String name
:指定方块名,即标识符中的路径;Function<AbstractBlock.Settings, Block> blockFactory
:抽象方块设置内部类对象和方块对象的函数表达式,仅用于创建Block
对象;AbstractBlock.Settings settings
:抽象方块设置内部类对象,可以用于配置方的属性;boolean shouldRegisterItem
:指定是否需要为方块注册方块物品,使其可以在创造模式物品栏中显示;
方法首先使用RegistryKey.of()
方法获取方块注册键对象,其中按顺序传递了注册键为方块RegistryKeys.BLOCK
和由模组Id和方块路径组成的Identifier
标识符对象。然后通过RegistryKey<Block>
注册键创建方块Block
对象。至此,方块对象创建完毕;
接着,根据shouldRegisterItem
变量的值,来确定是否需要注册方块对应的方块物品。如果需要注册,则再次使用RegistryKey.of()
方法获取物品的注册键对象,其中按顺序传递了注册键为物品RegistryKeys.Item
和由模组Id和方块路径组成的Identifier
标识符对象。然后调用BlockItem
类的构造方法来创建方块物品BlockItem
对象,方法中按顺序传递了方块对象和物品注册键对象。最后调用Registry.register()
方法将方块物品在游戏注册表中注册,方法中按顺序传递了注册键常量Registries.ITEM
、方块物品注册键对象和方块物品对象;
如果不需要注册方块物品,则直接调用Registry.register()
方法将方块在游戏注册表中注册,方法中按顺序传递了注册键常量Registries.BLOCK
、方块注册键对象和方块对象。
关于Identifier
和Registry
类的详细用法说明请参考我的世界Java版1.21.4的Fabric模组开发教程(二)创建物品;关于RegistryKey.of()
方法的详细用法说明请参考我的世界Java版1.21.4的Fabric模组开发教程(五)创建高级物品:盔甲。
方块类Block
Block
类是Minecraft中所有方块的基类,定义了方块的核心行为和属性 。通常,创建带有复杂自定义行为和属性的方块时,可以创建继承了Block
类的自定义方块类。在游戏中,同一类型的方块共享同一个Block
实例,例如,一个世界中的所有石头方块只共享一个石头方块实例,而不是为每一个石头方块都创建实例。创建方块对象后对应的方块物品对象不会自动创建,创建方块物品对象还需调用Registy.register()
方法。
Block
类中提供了许多方法,可以在涉及到方块的任何场景调用:
asItem()
:方法返回与方块对应的物品对象;
在后续章节中用到的方法将在此处补充。
抽象方块类AbstractBlock
及其设置内部类AbstractBlock.Settings
AbstractBlock
作为一个抽象类,定义了所有方块的基础属性和通用行为 。AbstractBlock
是Block
类的父类,但AbstractBlock
不能直接继承自定义方块类。
方块的自定义属性由内部类AbstractBlock.Settings
的实例控制,其构造方法已经被私有化,想要创建AbstractBlock.Settings
的实例,只能调用其静态方法create()
,直接返回一个内部类AbstractBlock.Settings
的实例;
java
public static AbstractBlock.Settings create() {
return new AbstractBlock.Settings();
}
AbstractBlock.Settings
类中提供了许多方法来配置方块的属性,所有方法均支持链式编程,包括:
requiresTool()
:配置方块只能由工具采集;sounds()
:配置方块与玩家交互的声音,通常传递一个BlockSoundGroup
类中的静态常量;hardness()
:指定方块硬度。参考值:橡木木板2.0f;
在后续章节中用到的方法将在此处补充。
方块物品类BlockItem
BlockItem
类继承了Item
类,用于将方块和物品关联起来,使得方块能够以物品的形式存在于玩家的背包、快捷栏或合成表中,并允许玩家在世界中通过方块物品来使用方块。
一般,调用其构造方法来创建BlockItem
类的对象;
java
public BlockItem(Block block, Item.Settings settings) {
super(settings);
this.block = block;
}
其中需要传递两个参数:
Block block
:指定要创建方块物品的方块对象;Item.Settings settings
:指定物品设置内部类对象,在注册时通常通过此参数传递注册键;关于内部类Item.Settings
的详细用法说明,请参考我的世界Java版1.21.4的Fabric模组开发教程(二)创建物品。
直接将register()
方法体复制到方块注册类ModBlocks.java
的register()
方法中,然后将访问修饰符改为private
。
注册方块并将其添加到指定物品组中
现在,我们将方块"浓缩泥土"在游戏注册表中注册,然后将其方块物品添加到物品组中。方块注册逻辑可以写在方块注册类ModBlocks.java
中,但将方块物品添加到物品组的逻辑依然需要写在入口点类中。
1.在ModBlocks.java
中声明静态常量CONDENSED_DIRT
,类型为Block
,并调用register()
方法对其初始化;
java
public static final Block CONDENSED_DIRT = register(
"condensed_dirt",
Block::new,
AbstractBlock.Settings.create().sounds(BlockSoundGroup.GRASS),
true
);
按顺序依次设置了物品名为"condensed_dirt"、抽象方块设置内部类对象和方块对象的函数式Block::new
、交互声音为BlockSoundGroup.GRASS
并要求注册方块对应的方块物品。
2.在入口点类的onInitialize()
方法中,将方块添加到指定物品组中;
java
ItemGroupEvents.modifyEntriesEvent(CUSTOM_ITEM_GROUP_KEY)
.register((itemGroup) -> {
...
itemGroup.add(ModBlocks.CONDENSED_DIRT.asItem());
...
});
需要调用asItem()
方法将方块转换为物品。
在语言文件中为方块添加翻译键值对
打开语言文件zh-cn.json
,为方块添加中文翻译;
json
{
...
"item.test.condensed_dirt": "浓缩泥土",
...
}
"condensed_dirt"为注册方块时使用的路径名。
创建方块的模型文件、模型描述文件和方块纹理
同物品一样,方块也需要创建模型文件、模型描述文件和对应的方块纹理。但是这些配置文件和物品的配置文件存放的位置不同。如果是首次创建自定义方块,可能需要创建新的目录。
1.在assets/test/models
目录中创建block
目录,用于存放方块的模型文件。在目录中创建condensed_dirt.json
;
java
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "test:block/condensed_dirt"
}
}
此时我们使用的模型为block/cube_all
,textures
配置项中,需要添加all
配置项,值为test:block/condensed_dirt
,即"模组Id+:block/+标识符",代表方块的所有面应用的纹理图位置;
2.在assets/test/items
中创建condensed_dirt.json
,代表方块的模型描述文件;
json
{
"model": {
"type": "minecraft:model",
"model": "test:block/condensed_dirt"
}
}
此处与物品模型描述文件的写法大致相同;
3.在assets/test/textures
目录中创建block
目录,将方块纹理图移动到目录中;

图片大小为16*16,文件名为"condensed_dirt.png",即方块路径名。不能使用其他格式的图片, 只能使用.png文件。
创建方块状态定义文件
方块状态定义用于指示游戏基于当前方块的状态要渲染哪个模型。目前,还不需要编程式的方块状态定义,只需要创建方块状态定义JSON文件即可。
"浓缩泥土"方块并没有复杂的状态,方块状态定义文件中只需要添加一条配置项;
在assets/test
目录中创建blockstates
目录,用于存放方块的状态定义文件。在其中创建condensed_dirt.json
,文件名应当与方块路径名相同;
json
{
"variants": {
"": {
"model": "test:block/condensed_dirt"
}
}
}
其中的配置项包含:
"variants"
:设置变种与对应的模型,内部需要列出此方块的所有变种;""
:变种名。不含有方块属性的方块状态使用""
作为变种名;"model"
:指定模型文件的标识符;
其中有更多的配置项,将在后续章节详细讲解关于方块状态的知识。
启动游戏测试
现在,我们打开游戏测试一下"浓缩泥土"方块的各种功能。
1.启动游戏,打开创造模式物品栏,找到"浓缩泥土";
可以看到方块物品已经成功注册,方块纹理和中文名称显示正常。将其添加到背包,然后主手持"浓缩泥土",右键点击使用方块;
可以看到方块显示正常。
至此,一个最简单的方块已经创建完毕。如果想给方块添加更多自定义功能和属性,还请继续阅读下文。
添加方块的掉落物/战利品列表
现在,无论是在创造模式,还是生存模式,使用任何工具或徒手破坏方块都不会出现掉落物。我们可以为其添加掉落物 ,由于某些方块破坏后掉落的东西不止一种,方块的掉落物也称之为战利品列表。
在开始前,确保你的项目已经启用数据生成(即使不使用数据生成类)。关于启用项目的数据生成说明,请参考我的世界Java版1.21.4的Fabric模组开发教程(二)创建物品中的"为物品添加合成配方"小节。
在data/test
目录中创建loot_table
目录,用于存放方块战利品列表JSON配置文件,在其中创建blocks
文件夹,代表方块的掉落物/战利品列表JSON配置文件,然后继续在其中创建condensed_dirt.json
,文件名与方块注册时使用的路径相同。
对于"浓缩泥土"方块,破坏方块时只需掉落其本身即可,其配置文件的写法应当如下:
json
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "test:condensed_dirt"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}
其中的配置项包含:
"type"
:战利品上下文的参数集类型。指定了调用该战利品时要应用的上下文环境,用于验证其他配置项的合法性,当某些配置错误或缺失时,游戏日志中会打印警告信息;"pools"
:战利品表的随机池的列表。主要定义了若干待选的抽取项;"rolls"
:指定该随机池的抽取次数;"entries"
:指定随机池中的抽取项。抽取项分为单一抽取项和复合抽取项,单一抽取项定义了单个物品生成行为,是随机池中最终要抽取的带权重的项目。如果不使用物品修饰器,物品数量默认为1。此处我们使用的是单一抽取项,下面给出类型为item的战利品池抽取项的数据格式:"type"
:"minecraft:item"
;"name"
:物品的标识符;
"conditions"
:战利品表谓词列表。仅当满足列表中的所有条件时,该随机池才会被使用;"condition"
:战利品表谓词,又称战利品表物品条件,用于在战利品表中制定战利品的产生条件。此处使用了"minecraft:survives_explosion"
,代表物品可以通过爆炸掉落;
启动游戏,在创造模式下将"浓缩泥土"放入背包,然后切换为生存模式,放置方块,然后破坏方块,可以看到掉落物。
配置推荐的挖掘工具
如果想限制挖掘方块的工具,可以继续添加配置文件。例如,这里我们令"浓缩泥土"只能由锹类工具挖掘时才会掉落。
在data
目录中创建minecraft
文件夹,然后在其中依次创建tag/block/mineable
目录,最后创建shovel.json
;
配置文件中的结构如下:
json
{
"values": ["test:condensed_dirt"]
}
"values"
配置项中直接提供方块的标识符。将"浓缩泥土"的标识符添加到文件中,代表只能使用锹挖掘方块才能获得掉落物,否则挖掘速度将很慢且没有掉落物;
shovel.json
文件中存放推荐使用锹类工具破坏的方块的集合。此外,还有其他配置文件:
hoe.json
:推荐使用锄类工具破坏;axe.json
:推荐使用斧类工具破坏;pickaxe.json
:推荐使用镐类工具破坏;
这些文件和Minecraft原生配置文件的文件名和文件位置相同,数据将会追加到原生配置文件中,而不是完全替换原生配置文件。
配置指定的工具等级
如果想限制挖掘方块所用工具的材质级别,可以继续添加配置文件。例如,这里我们令"浓缩泥土"只能由"铁锹"及以上的材料(钻石锹、下界合金锹)挖掘时才会掉落。
在data/minecraft/tags/block
目录中创建needs_diamond_tool.json
,文件结构与文的shovel.json
相同;
json
{
"values": ["test:condensed_dirt"]
}
为了演示效果,我们调用hardness()
方法为方块设置硬度,使其破坏需要一定时间。找到ModBlocks.java
,修改register()
方法中的参数;
java
public static final Block CONDENSED_DIRT = register(
"condensed_dirt",
Block::new,
AbstractBlock.Settings.create()
.sounds(BlockSoundGroup.GRASS)
.requiresTool()
.hardness(2.5f),
true
);
将硬度改为2.5。启动游戏,使用铁锹破坏方块;
可以看到掉落物。使用钻石锹或下界合金锹破坏方块也可以获得掉落物。
本章小结
本章详细阐述了创建一个自定义方块的步骤。本文篇幅较长,但难度一般,阅读本文要求开发者有创建物品的知识基础,才能理解文中的部分写法。感谢各位的阅读,有兴趣可以订阅此专栏!