这是适用于Minecraft Java版1.21.4的Fabric模组开发系列教程专栏第六章——创建自定义物品组。想要阅读其他内容,请查看或订阅上面的专栏。
物品组是创造模式物品栏中存储物品的一个标签页。 在本章中,我们将创建自定义的物品组并将所自定义物品添加到这个物品组中。
创建自定义物品组,通常要完成以下步骤:
- 创建物品组对象;
- 创建物品组注册键对象;
- 在游戏注册表中注册物品组;
- 将物品添加到自定义物品组中。
创建物品组对象
一般,创建一个自定义物品组的代码量较小,因此相关代码可以直接写在入口点类中。
物品组类ItemGroup
ItemGroup
类用于组织、管理和创建游戏中创造模式物品栏中的每个标签页,是创建自定义物品组务必要创建的对象。在ItemGroup
类中有构造ItemGroup
对象的构造器内部类ItemGroup.Builder
。
物品组构造器内部类ItemGroup.Builder
ItemGroup.Builder
是Minecraft API提供的用于创建ItemGroup
对象的内部类。ItemGroup.Builder
提供了几个方法用于配置物品组相关属性,这些方法均支持链式编程;
displayName()
:指定物品组的名称。传递一个Text
对象;icon()
:指定物品组的图标。传递一个Supplier<ItemStack>
对象;entries()
:指定物品组中的物品。传递一个ItemGroup.EntryCollector
对象;build()
:构造ItemGroup
对象,必须在链式编程结尾调用;
但是,Fabric对此构造器进行了封装,要创建ItemGroup
对象,现在可以使用FabricItemGroup
类。
Fabric物品组类FabricItemGroup
和Fabric物品组构造器实现类FabricItemGroupBuilderImpl
FabricItemGroup
和FabricItemGroupBuilderImpl
两个类均对ItemGroup.Builder
进行了封装,改变了使用ItemGroup.Builder
创建ItemGroup
对象的繁琐步骤。
FabricItemGroup
类用于创建ItemGroup.Builder
对象,其中只有一个静态方法builder()
,返回一个ItemGroup.Builder
对象;
public static ItemGroup.Builder builder() {
return new FabricItemGroupBuilderImpl();
}
不过在这期间,builder()
方法首先调用了FabricItemGroupBuilderImpl
类的构造方法,用于返回ItemGroup.Builder
对象;
FabricItemGroupBuilderImpl
类继承了ItemGroup.Builder
类,是Fabric对其父类的封装,从而使开发者避免了调用ItemGroup.Builder
类中的构造方法来创建自定义物品组。FabricItemGroupBuilderImpl
类中重写了其父类的build()
等方法,改进了父类中的代码逻辑。
物品收集器内部函数式接口ItemGroup.EntryCollector
ItemGroup.EntryCollector
接口在ItemGroup
类内部声明,是调用ItemGroup.Builder
对象的方法entries()
时传递的参数,旨在将物品添加物品组当中。ItemGroup.EntryCollector
被@FunctionalInterface
注解修饰,因此调用接口时可以写成一个函数表达式;
@FunctionalInterface
public interface EntryCollector {
void accept(ItemGroup.DisplayContext displayContext, ItemGroup.Entries entries);
}
内部接口中只有一个accept()
方法,添加物品时需要调用ItemGroup.Entries
对象的add()
方法。当然,也可以使用原始的ItemGroupEvents.modifyEntriesEvent()
方法将物品添加到指定物品栏。
在入口点类声明静态常量CUSTOM_ITEM_GROUP
,类型为ItemGroup
作为物品组对象。使用FabricItemGroup.builder()
方法创建继承了ItemGroup.Builder
类的FabricItemGroupBuilderImpl
对象。
public static final ItemGroup CUSTOM_ITEM_GROUP = FabricItemGroup.builder()
.icon(() -> new ItemStack(BEST_SWORD))
.displayName(Text.literal("我的物品"))
.build();
调用icon()
方法设置物品栏图标为“究极神剑”的图标,传递一个Supplier
接口函数式,在接口的get方法中返回一个ItemStack
对象;调用displayName()
方法设置物品栏的名称,传递一个Text
类的对象,使用静态方法Text.literal()
将字符串转换为Text
对象,最后使用build()
方法构造ItemGroup
对象;
同时,也可以将Supplier
接口函数式改写为匿名内部接口,功能与使用函数式相同;
public static final ItemGroup CUSTOM_ITEM_GROUP = FabricItemGroup.builder()
.icon(new Supplier<ItemStack>() {
@Override
public ItemStack get() {
return new ItemStack(BEST_SWORD);
}
})
.displayName(Text.literal("我的物品"))
.build();
此外,可以使用entries()
方法在物品栏中添加物品;
public static final ItemGroup CUSTOM_ITEM_GROUP = FabricItemGroup.builder()
.icon(() -> new ItemStack(BEST_SWORD))
.displayName(Text.literal("我的物品"))
.entries((displayContext, entries) -> entries.add(ARMOR_SUITE_CHESTPLATE))
.build();
调用ItemGroup.Entries
对象的add()
方法将一个物品添加到物品组中,传递一物品对象。也可以在稍后使用ItemGroupEvents.modifyEntriesEvent()
方法将物品添加到指定物品栏;
也可以改为匿名内部类new ItemGroup.EntryCollector(){...}
的形式;
public static final ItemGroup CUSTOM_ITEM_GROUP = FabricItemGroup.builder()
.icon(() -> new ItemStack(BEST_SWORD))
.displayName(Text.literal("我的物品"))
.entries(new ItemGroup.EntryCollector() {
@Override
public void accept(ItemGroup.DisplayContext displayContext, ItemGroup.Entries entries) {
entries.add(ARMOR_SUITE_CHESTPLATE);
}
})
.build();
创建物品组注册键对象
创建物品组的注册键对象就是要创建类型为RegistryKey<ItemGroup>
的对象,因此需要使用Registry.of()
方法;
关于Registry.of()
方法的详细用法请参考我的世界Java版1.21.4的Fabric模组开发教程(五)创建高级物品:盔甲。
在入口点类中声明静态常量CUSTOM_ITEM_GROUP_KEY
,类型为RegistryKey<ItemGroup>
作为自定义物品组键对象;
public static final RegistryKey<ItemGroup> CUSTOM_ITEM_GROUP_KEY =
RegistryKey.of(RegistryKeys.ITEM_GROUP, Identifier.of(FabricDocsReference.MOD_ID, "lei_item_group"));
使用RegistryKey.of
方法创建物RegistryKey<ItemGroup>
对象,传递两个参数,第一个参数为注册键,创建类型为ItemGroup
的注册键时固定使用静态常量RegistryKeys.ITEM_GROUP
或方法Registries.ITEM_GROUP.getKey()
,第二个参数为Identifier
对象,即标识符,此处使用模组Id和路径作为标识符,路径为“lei_item_group”;
关于标识符类Identifier
的详细用法说明,请参考我的世界Java版1.21.4的Fabric模组开发教程(二)创建物品。
在游戏注册表中注册自定义物品组
这里需要使用原生的Register.registry()
方法注册自定义物品组,而不是之前封装的ModItems.registry()
。
在入口点类的onIntialize()
方法中调用Registry.register()
方法;
Registry.register(Registries.ITEM_GROUP,CUSTOM_ITEM_GROUP_KEY,CUSTOM_ITEM_GROUP);
第一个参数传递一个注册键,即要注册物品(方块、实体等)的类型,注册物品组固定的写法为Registries.ITEM_GROUP
;第二个参数传递注册键对象,直接使用上一小节创建的静态常量CUSTOM_ITEM_GROUP_KEY
;第三个参数传递要注册物品(方块、实体等)的对象,直接使用之前小节创建ItemGroup
对象CUSTOM_ITEM_GROUP
。
关于原生Register.registry()
方法的详细用法说明,请参考我的世界Java版1.21.4的Fabric模组开发教程(二)创建物品。
将物品添加到自定义物品组中
将自己的物品添加到自定义物品组中可以使用前几个章节中提到的ItemGroupEvents.modifyEntriesEvent()
方法,也是作者在本章中采用的方法;
ItemGroupEvents.modifyEntriesEvent(CUSTOM_ITEM_GROUP_KEY)
.register((itemGroup) -> {
itemGroup.add(DOG_POO);
itemGroup.add(TOXIC_APPLE);
itemGroup.add(BEST_SWORD);
//...
});
此时传递的参数是自定义物品组的注册键对象。当然,需要提前声明自定义物品的对象。
此外,也可以使用在之前小节中提到的其他方法,也就是创建ItemGroup
对象时,调用ItemGroup.Builder
中的entries()
方法添加物品到物品组当中。
启动游戏测试
打开游戏,调整游戏模式为“创造模式”,按e
键打开创造模式物品栏。
可以看到自定义物品组的标题、图标和其中的物品;如果没有找到自定义物品组,可以点击右上角的翻页按钮查看下一页物品组。
本章小结
本章详细阐述了创建自定义物品组的步骤,提供了部分代码解析,内容与前几章节的知识关联性不大,但期间使用到了许多新API,仍需要开发者慢慢学习。感谢各位的阅读,有兴趣可以订阅此专栏!