本篇教程的视频

本篇教程的源代码

Github地址:TutorialMod-Armor-1.21

介绍

在游戏中,有我们常见的盔甲,分别是头盔胸甲护腿靴子四类盔甲

它们和工具一样,都是物品,不过能为玩家提供一定的护甲值,减少其受到的伤害

除了乌龟壳单独可以作为头盔之外,其他的盔甲都是由基本的五种材质制成的,这个和工具是一样的

在这篇教程中,我们将会制作四种盔甲,分别是头盔胸甲护腿靴子

查看源代码

这里我们先看一下Items类中的DIAMOND_XXX这类盔甲

1
2
3
4
5
6
7
8
9
10
11
12
13
public static final Item DIAMOND_HELMET = register(
"diamond_helmet", new ArmorItem(ArmorMaterials.DIAMOND, ArmorItem.Type.HELMET, new Item.Settings().maxDamage(ArmorItem.Type.HELMET.getMaxDamage(33)))
);
public static final Item DIAMOND_CHESTPLATE = register(
"diamond_chestplate",
new ArmorItem(ArmorMaterials.DIAMOND, ArmorItem.Type.CHESTPLATE, new Item.Settings().maxDamage(ArmorItem.Type.CHESTPLATE.getMaxDamage(33)))
);
public static final Item DIAMOND_LEGGINGS = register(
"diamond_leggings", new ArmorItem(ArmorMaterials.DIAMOND, ArmorItem.Type.LEGGINGS, new Item.Settings().maxDamage(ArmorItem.Type.LEGGINGS.getMaxDamage(33)))
);
public static final Item DIAMOND_BOOTS = register(
"diamond_boots", new ArmorItem(ArmorMaterials.DIAMOND, ArmorItem.Type.BOOTS, new Item.Settings().maxDamage(ArmorItem.Type.BOOTS.getMaxDamage(33)))
);

我们可以发现它和我们之前制作的工具类似,实例化了各自的盔甲类,也有对应自己的材质

那么我们废话不多说,先来看一下ArmorMaterials这个类

1
2
3
4
5
6
7
public static final RegistryEntry<ArmorMaterial> DIAMOND = register("diamond", Util.make(new EnumMap(ArmorItem.Type.class), map -> {
map.put(ArmorItem.Type.BOOTS, 3);
map.put(ArmorItem.Type.LEGGINGS, 6);
map.put(ArmorItem.Type.CHESTPLATE, 8);
map.put(ArmorItem.Type.HELMET, 3);
map.put(ArmorItem.Type.BODY, 11);
}), 10, SoundEvents.ITEM_ARMOR_EQUIP_DIAMOND, 2.0F, 0.0F, () -> Ingredient.ofItems(Items.DIAMOND));

这是其中的DIAMOND这个材质

(如果你是从1.20.X及其以下版本过来的)我们还可以发现一点,这个类不再是枚举类了,而变成了一个普通的类,这里的材质也都变成了注册语句

那么我们现在来看这里的注册语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private static RegistryEntry<ArmorMaterial> register(
String id,
EnumMap<ArmorItem.Type, Integer> defense,
int enchantability,
RegistryEntry<SoundEvent> equipSound,
float toughness,
float knockbackResistance,
Supplier<Ingredient> repairIngredient
) {
List<ArmorMaterial.Layer> list = List.of(new ArmorMaterial.Layer(Identifier.ofVanilla(id)));
return register(id, defense, enchantability, equipSound, toughness, knockbackResistance, repairIngredient, list);
}

private static RegistryEntry<ArmorMaterial> register(
String id,
EnumMap<ArmorItem.Type, Integer> defense,
int enchantability,
RegistryEntry<SoundEvent> equipSound,
float toughness,
float knockbackResistance,
Supplier<Ingredient> repairIngredient,
List<ArmorMaterial.Layer> layers
) {
EnumMap<ArmorItem.Type, Integer> enumMap = new EnumMap(ArmorItem.Type.class);

for (ArmorItem.Type type : ArmorItem.Type.values()) {
enumMap.put(type, (Integer)defense.get(type));
}

return Registry.registerReference(
Registries.ARMOR_MATERIAL,
Identifier.ofVanilla(id),
new ArmorMaterial(enumMap, enchantability, equipSound, repairIngredient, layers, toughness, knockbackResistance)
);
}

这里一共是两个注册方法,前一个是除了皮革之外的材质的注册,它也调用了后一个注册方法;而后一个注册方法是皮革直接使用的注册方法,也是我们这里的主要注册方法

其实比较一下,下面的那个注册方法多了一个List<ArmorMaterial.Layer> layers参数,这个参数是用来指定这个材质的的,为什么呢?

我们想一下,皮革材质的这些盔甲是不是可以被染色?翻过盔甲的那些材质文件的同学也可以发现,皮革盔甲的材质是灰白色的,并没有像别的材质那样直接给了颜色

所以皮革的颜色是后期渲染的时候设置的,也可以根据染料的颜色来设置

那么现在我们来看看这里注册方法的参数

String id,材质的ID

EnumMap<ArmorItem.Type, Integer> defense,护甲值,这个不是耐久值,而是护甲值,在游戏中也就是显示在生命值上面的那个衣服形状的HUD

int enchantability,附魔能力,这个和工具的附魔能力是一样的,是指这个物品在附魔台上获得更好、更高级附魔的概率

RegistryEntry<SoundEvent> equipSound,装备声音,这个是指装备这个盔甲的时候会发出的声音

float toughness,韧性,这个是指这个盔甲的韧性,也就是抵抗伤害的能力(原版只有钻石和下界合金有)

float knockbackResistance,击退抗性,这个是指这个盔甲的击退抗性,也就是抵抗击退的能力(原版只有下界合金有)

Supplier<Ingredient> repairIngredient,修复用材料,这个是指这个盔甲的修复用材料

List<ArmorMaterial.Layer> layers,层,这个可参考皮革的写法

然后里面的defense,各个护甲部位的护甲值是不一样的。新版本有一个BODY,这个是狼铠用的那个护甲值,这里我单独说一下,因为视频里面没讲

注册盔甲

那么现在我们来写我们的盔甲

创建ModArmorMaterials类

1
2
3
public class ModArmorMaterials {

}

然后我们把ArmorMaterials的注册方法搬过来,然后修改一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private static RegistryEntry<ArmorMaterial> register(
String id,
EnumMap<ArmorItem.Type, Integer> defense,
int enchantability,
RegistryEntry<SoundEvent> equipSound,
float toughness,
float knockbackResistance,
Supplier<Ingredient> repairIngredient
) {
List<ArmorMaterial.Layer> list = List.of(new ArmorMaterial.Layer(Identifier.of(TutorialMod.MOD_ID, id)));
return register(id, defense, enchantability, equipSound, toughness, knockbackResistance, repairIngredient, list);
}

private static RegistryEntry<ArmorMaterial> register(
String id,
EnumMap<ArmorItem.Type, Integer> defense,
int enchantability,
RegistryEntry<SoundEvent> equipSound,
float toughness,
float knockbackResistance,
Supplier<Ingredient> repairIngredient,
List<ArmorMaterial.Layer> layers
) {
EnumMap<ArmorItem.Type, Integer> enumMap = new EnumMap(ArmorItem.Type.class);

for (ArmorItem.Type type : ArmorItem.Type.values()) {
enumMap.put(type, (Integer)defense.get(type));
}

return Registry.registerReference(
Registries.ARMOR_MATERIAL,
Identifier.ofVanilla(id),
new ArmorMaterial(enumMap, enchantability, equipSound, repairIngredient, layers, toughness, knockbackResistance)
);
}

一定一定要把Identifier.ofVanilla改掉!!!

写上我们自己的MOD_ID

然后我们来写我们的盔甲材质

1
2
3
4
5
6
7
public static final RegistryEntry<ArmorMaterial> ICE_ETHER = register("ice_ether", Util.make(new EnumMap(ArmorItem.Type.class), map -> {
map.put(ArmorItem.Type.BOOTS, 3);
map.put(ArmorItem.Type.LEGGINGS, 6);
map.put(ArmorItem.Type.CHESTPLATE, 8);
map.put(ArmorItem.Type.HELMET, 3);
map.put(ArmorItem.Type.BODY, 11);
}), 15, SoundEvents.ITEM_ARMOR_EQUIP_NETHERITE, 3.0F, 0.1F, () -> Ingredient.ofItems(ModItems.ICE_ETHER));

这里我们注册了一个ICE_ETHER的盔甲材质,这里面的参数按照上面的解释自己写好了,这里我就不再赘述

注册盔甲

然后我们来注册我们的盔甲

1
2
3
4
5
6
7
8
public static final Item ICE_ETHER_HELMET = registerItems("ice_ether_helmet", new ArmorItem(ModArmorMaterials.ICE_ETHER, ArmorItem.Type.HELMET,
new Item.Settings().maxDamage(ArmorItem.Type.HELMET.getMaxDamage(37))));
public static final Item ICE_ETHER_CHESTPLATE = registerItems("ice_ether_chestplate", new ArmorItem(ModArmorMaterials.ICE_ETHER, ArmorItem.Type.CHESTPLATE,
new Item.Settings().maxDamage(ArmorItem.Type.CHESTPLATE.getMaxDamage(37))));
public static final Item ICE_ETHER_LEGGINGS = registerItems("ice_ether_leggings", new ArmorItem(ModArmorMaterials.ICE_ETHER, ArmorItem.Type.LEGGINGS,
new Item.Settings().maxDamage(ArmorItem.Type.LEGGINGS.getMaxDamage(37))));
public static final Item ICE_ETHER_BOOTS = registerItems("ice_ether_boots", new ArmorItem(ModArmorMaterials.ICE_ETHER, ArmorItem.Type.BOOTS,
new Item.Settings().maxDamage(ArmorItem.Type.BOOTS.getMaxDamage(37))));

注册的时候用maxDamage方法来设置最大耐久,这里的数值是一个乘数,并不是其最大的耐久值

我们跳到ArmorItem.Type.XXX去看看

1
2
3
4
5
HELMET(EquipmentSlot.HEAD, 11, "helmet"),
CHESTPLATE(EquipmentSlot.CHEST, 16, "chestplate"),
LEGGINGS(EquipmentSlot.LEGS, 15, "leggings"),
BOOTS(EquipmentSlot.FEET, 13, "boots"),
BODY(EquipmentSlot.BODY, 16, "body");

这里的几行语句中的数值是baseMaxDamage,也就是基础的最大耐久值

那么我们最终的耐久值是baseMaxDamage乘以我们传入的数值,比如以头盔为例,它的baseMaxDamage11,我们传入的数值是37,那么最终的耐久值就是407,这个也是下界合金头盔的耐久值

写入物品栏

记得把我们的盔甲写入物品栏

1
2
3
4
entries.add(ModItems.ICE_ETHER_HELMET);
entries.add(ModItems.ICE_ETHER_CHESTPLATE);
entries.add(ModItems.ICE_ETHER_LEGGINGS);
entries.add(ModItems.ICE_ETHER_BOOTS);

这样我们的盔甲就注册完了

数据文件

语言文件

1
2
3
4
translationBuilder.add(ModItems.ICE_ETHER_HELMET, "Ice Ether Helmet");
translationBuilder.add(ModItems.ICE_ETHER_CHESTPLATE, "Ice Ether Chestplate");
translationBuilder.add(ModItems.ICE_ETHER_LEGGINGS, "Ice Ether Leggings");
translationBuilder.add(ModItems.ICE_ETHER_BOOTS, "Ice Ether Boots");

模型文件

盔甲的模型文件是要注意一下的,它们有单独的注册方法,这里的语句也会生成最终三维(也就是穿到身上的)模型文件

1
2
3
4
itemModelGenerator.registerArmor((ArmorItem) ModItems.ICE_ETHER_HELMET);
itemModelGenerator.registerArmor((ArmorItem) ModItems.ICE_ETHER_CHESTPLATE);
itemModelGenerator.registerArmor((ArmorItem) ModItems.ICE_ETHER_LEGGINGS);
itemModelGenerator.registerArmor((ArmorItem) ModItems.ICE_ETHER_BOOTS);

ItemTags

盔甲可以被锻造,而要想让我们的盔甲实现这个功能,我们就得写Tag

1
2
getOrCreateTagBuilder(ItemTags.TRIMMABLE_ARMOR)
.add(ModItems.ICE_ETHER_HELMET, ModItems.ICE_ETHER_CHESTPLATE, ModItems.ICE_ETHER_LEGGINGS, ModItems.ICE_ETHER_BOOTS);

随后跑数据生成的时候,我们会发现它生成了一堆文件,毕竟锻造模板挺多的,所以各种各样的花纹也很多

材质文件

这里的材质文件是要注意一下的,它们的材质文件是分开成两个的(上半身和下半身分开的),也是单独在特定的文件夹下的