本篇教程的视频

本篇教程的源代码

GitHub地址:TutorialMod-1.20.1-Forge-ArmorEffect

自定义盔甲类

那么本期教程,我们来实现一个进阶盔甲,当玩家穿上全套盔甲之后,给予玩家增益效果

不过要实现这个逻辑,原版的盔甲类肯定不行,所以我们得自己去写一个自定义的盔甲类,来实现这个功能

新建类

这里我们创建一个CustomArmorItem类,继承自ArmorItem

显然易见,继承了ArmorItem类之后,我们就不用去写盔甲的基本逻辑了(穿戴、耐久、提供护甲值、伤害减免等),我们只需要在这个基础上去实现增益效果就好了

1
2
3
4
5
6
public class CustomArmorItem extends ArmorItem {

public CustomArmorItem(ArmorMaterial pMaterial, Type pType, Properties pProperties) {
super(pMaterial, pType, pProperties);
}
}

当然这种写法有一个美中不足的地方,它只能对我们新增的盔甲材料和盔甲生效,无法让原版的那些盔甲也实现增益效果

如果要让原版的盔甲也实现增益,可以使用事件监听或者Mixin来实现,在26.1 NeoForge的相关教程中,我们就是使用了事件监听来实现,理论上也可以迁移到这里来,不过就交给大家去研究了

增益效果Map

接下来我们先创建一个Map,来存储各个盔甲材料对应的盔甲效果

1
2
3
4
5
6
7
private static final Map<ArmorMaterial, List<MobEffectInstance>> MAP =
(new ImmutableMap.Builder<ArmorMaterial, List<MobEffectInstance>>())
.put(ModArmorMaterials.ICE_ETHER,
Arrays.asList(
new MobEffectInstance(MobEffects.MOVEMENT_SPEED, 1, 1, false, false, true),
new MobEffectInstance(MobEffects.JUMP, 1, 1, false, false, true)
)).build();

其中的效果我们也用了一个List来存储,这样我们就可以给玩家添加多个增益效果了

比如这里的ICE_ETHER这个材料,当玩家穿上全套这个材料的盔甲之后,就会获得速度跳跃提升这两个增益效果

关于这里的MobEffectInstance的参数,这里我们简单介绍一下,它们分别是效果类型持续时间(单位tick)等级是否来源于环境是否显示粒子是否显示图标

这里的持续时间设置为1 tick,也就是能让它实现脱下盔甲效果立刻消失

重写 inventoryTick 方法

接下来我们需要重写inventoryTick方法,这个是物品栏实时调用的方法(和tick挂钩的基本上都是实时调用的)

我们可以在这里去判断玩家是否穿上了全套盔甲,如果穿上了,就给予玩家增益效果

1
2
3
4
5
6
7
8
9
@Override
public void inventoryTick(ItemStack pStack, Level pLevel, Entity pEntity, int pSlotId, boolean pIsSelected) {
if (!pLevel.isClientSide()) {
if (pEntity instanceof Player player && hasFullSuitableArmor(player)) {
evaluateArmorEffects(player);
}
}
super.inventoryTick(pStack, pLevel, pEntity, pSlotId, pIsSelected);
}

这里同样先进行客户端和服务端的判断,因为运算逻辑要交给服务端完成

然后我们再判断pEntity是否是玩家,如果说你想让其他人形实体(僵尸等)也能穿上盔甲获得增益效果的话,这里就不需要判断了

hasFullSuitableArmorevaluateArmorEffects这两个方法分别是判断玩家是否穿上了全套盔甲,以及给予玩家增益效果的方法

这两个方法是我们待会要自己写的方法

evaluateArmorEffects 方法

我们先来写evaluateArmorEffects方法,这个方法就是用来给予玩家增益效果的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void evaluateArmorEffects(Player player) {
for (Map.Entry<ArmorMaterial, List<MobEffectInstance>> entry : MAP.entrySet()) {
ArmorMaterial material = entry.getKey();
List<MobEffectInstance> effects = entry.getValue();

if (hasCorrectMaterialArmorOn(material, player)) {
for (MobEffectInstance effect : effects) {
MobEffect effects1 = effect.getEffect();
if (!player.hasEffect(effects1)) {
player.addEffect(effect);
}
}
}
}
}

逻辑其实很简单,我们先遍历MAP,拿到每个盔甲材料和对应的增益效果列表,然后判断玩家是否穿上了这个材料的全套盔甲,如果穿上了,就给玩家添加增益效果

同样hasCorrectMaterialArmorOn也是我们自定义的方法

hasCorrectMaterialArmorOn 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private boolean hasCorrectMaterialArmorOn(ArmorMaterial material, Player player) {
for (ItemStack stack : player.getInventory().armor) {
if (!(stack.getItem() instanceof ArmorItem)) {
return false;
}
}

ArmorItem helmet = (ArmorItem) player.getInventory().getArmor(3).getItem();
ArmorItem chestplate = (ArmorItem) player.getInventory().getArmor(2).getItem();
ArmorItem leggings = (ArmorItem) player.getInventory().getArmor(1).getItem();
ArmorItem boots = (ArmorItem) player.getInventory().getArmor(0).getItem();

return helmet.getMaterial() == material
&& chestplate.getMaterial() == material
&& leggings.getMaterial() == material
&& boots.getMaterial() == material;
}

这个方法就是用来判断玩家是否穿上了指定材料的全套盔甲的

但是在判断材料之前,我们还需要进行一次对玩家盔甲槽中物品的遍历,检查盔甲槽中的物品是否是ArmorItem的实例,因为只有盔甲物品才有盔甲材料

而还有一些特殊的物品,比如鞘翅,它可以装备到盔甲槽里面,但它没有盔甲材料,也不能被强转为ArmorItem

所以如果说没有这一步遍历,恰好玩家穿了一个鞘翅,那么游戏就崩溃了

hasFullSuitableArmor 方法

1
2
3
4
5
6
7
8
private boolean hasFullSuitableArmor(Player player) {
ItemStack helmet = player.getInventory().getArmor(3);
ItemStack chestplate = player.getInventory().getArmor(2);
ItemStack leggings = player.getInventory().getArmor(1);
ItemStack boots = player.getInventory().getArmor(0);

return !helmet.isEmpty() && !chestplate.isEmpty() && !leggings.isEmpty() && !boots.isEmpty();
}

这个方法用于判断玩家的盔甲槽是否都满了

当然,这个方法可以和hasCorrectMaterialArmorOn方法合并成一个方法,这个就根据大家的实际情况去写好了

重新注册物品

最后我们需要重新注册物品

1
2
public static final RegistryObject<Item> ICE_ETHER_HELMET = ITEMS.register("ice_ether_helmet",
() -> new CustomArmorItem(ModArmorMaterials.ICE_ETHER, ArmorItem.Type.HELMET, new Item.Properties()));

这里我们就将其中一个盔甲的物品类改成我们刚才写的物品类,其他的可以不换

因为一个物品类就可以判断所有的盔甲槽

最后我们就可以进入游戏进行测试了