我的世界Java版1.21.4的Fabric模组开发教程(九)创建药水

这是适用于Minecraft Java版1.21.4的Fabric模组开发系列教程专栏第九章——创建药水。想要阅读其他内容,请查看或订阅上面的专栏。

药水(Potion) 是能为实体提供效果的消耗品。玩家可以通过饮用药水,为自己添加指定的状态效果。

创建一个药水最简单的方法就是直接在入口点类中调用Registry.register()方法,在游戏注册表中注册药水。另外,也可以为药水添加配方和自定义的状态效果。

直接在游戏注册表中注册药水

这是创建药水的最简单写法。

在入口点类中调用Registry.register()方法,其中传递三个参数:

  • Registry<V> registry:注册键类型,注册药水固定的写法为Registries.POTION
  • Identifier id:标识符,传递一个Identifier对象;
  • T entry:物品类型。此处固定传递一个Potion对象;

关于原生Register.registry()方法和Identifier类的详细用法说明,请参考我的世界Java版1.21.4的Fabric模组开发教程(二)创建物品


药水类Potion

Potion类是管理药水效果的核心类,用于创建药水并定义药水的基础效果类型和基础属性。其构造方法创建的对象一般作为注册药水时调用的Registry.register()方法的第三个参数。

构造方法用于构造Potion对象;

public Potion(String baseName, StatusEffectInstance... effects) {
	this.baseName = baseName;
	this.effects = List.of(effects);
}

其中传递两个参数:

  • String baseName:指定药水名称;
  • StatusEffectInstance... effects:指定状态效果对象。可以传递多个对象。

关于状态效果对象的创建相关内容的详细说明,请参考我的世界Java版1.21.4的Fabric模组开发教程(三)创建高级物品:食物


在入口点类声明静态常量TATER_POTION,类型为Potion,调用Registry.register()方法初始化常量;

public static final Potion TATER_POTION = Registry.register(
		Registries.POTION,
		Identifier.of(FabricDocsReference.MOD_ID, "tater"),
		new Potion("tater",new StatusEffectInstance(StatusEffects.DARKNESS,3600,0)));

第一个参数固定传递Registries.POTION,代表注册键;第二个参数传递一个Identifier对象,使用模组Id和路径“tater”作为标识符;第三个参数传递Potion对象,应当调用Potion类的构造方法;

构造方法中传递两个参数,第一个参数传递字符串“tater”作为药水名,第二个参数使用StatusEffectInstance类的构造方法传递一个状态效果对象,参数列表中按顺序分别设置了效果为黑暗StatusEffects.DARKNESS、持续时间为1200游戏刻(60秒)以及状态效果增幅为0。

关于原生Register.registry()方法和Identifier类的详细用法说明,请参考我的世界Java版1.21.4的Fabric模组开发教程(二)创建物品

现在直接打开游戏,在创造模式物品栏中可以找到已经创建好的药水,普通药水、喷溅型和滞留型药水会同时被创建;
在这里插入图片描述
可以看到状态效果为黑暗,持续时间为1分钟。

由于还未添加语言文件中的翻译键值对,所以药水不显示中文名字而是显示标识符。而且,目前的药水只能通过创造模式物品栏或指令获得,在生存模式下无法使用酿造台制作。我们接下来将为药水添加酿造配方和中文名称。

在语言文件中为药水添加翻译键值对

打开语言文件zh-cn.js,添加键值对数据;

{
	...
	"item.minecraft.potion.effect.tater": "土豆药水",
	"item.minecraft.lingering_potion.effect.tater": "滞留型土豆药水",
	"item.minecraft.splash_potion.effect.tater": "喷溅型土豆药水",
	...
}

应当添加三条数据,分别为普通药水、喷溅型药水和滞留型药水添加中文翻译,不同类型药水的翻译键是不同的。“tater”是在Potion类的构造方法中设置的药水名称。

为药水添加酿造配方

现在,我们为自定义药水添加酿造配方,使其可以在生存模式下通过酿造台获得。


Fabric酿造配方注册构造器接口FabricFabricBrewingRecipeRegistryBuilder

FabricFabricBrewingRecipeRegistryBuilder接口是Fabric API提供的用于为指定药水添加配方并将其注册到游戏注册表中的工具。通过接口中用于处理酿造配方注册事件的BUILD对象的register()方法来完成酿造配方的注册。

register()方法中传递一个FabricFabricBrewingRecipeRegistryBuilder接口内部的函数式接口BuildCallback的函数表达式;

@FunctionalInterface
interface BuildCallback {
	void build(BrewingRecipeRegistry.Builder builder);
}

方法的参数为BrewingRecipeRegistry.Builder对象,BrewingRecipeRegistry.Builder由Minecraft API提供,同样用于构造酿造配方对象。FabricFabricBrewingRecipeRegistryBuilder接口对此内部类进行了封装,在一定程度上简化了创建药水酿造配方的代码量;

在函数式中需要调用BrewingRecipeRegistry.Builder对象的registerItemRecipe()方法来配置酿造配方的详细信息;

public void registerPotionRecipe(RegistryEntry<Potion> input, Item ingredient, RegistryEntry<Potion> output) {
	if (input.value().isEnabled(this.enabledFeatures) && ingredient.isEnabled(this.enabledFeatures) && output.value().isEnabled(this.enabledFeatures)) {
		this.potionRecipes.add(new BrewingRecipeRegistry.Recipe<>(input, Ingredient.ofItem(ingredient), output));
	}
}

其中传递了三个参数:

  • RegistryEntry<Potion> input:指定输入药水,即使用哪种药水作为初始药水,传递一个Potions类中的常量,通常为水瓶Potions.WATER或粗制的药水Potions.MUNDANE
  • Item ingredient:指定制作材料,即制作药水的原材料,传递一个Items类常量;
  • RegistryEntry<Potion> output:指定输出药水,即用以上材料制作出的目标药水,一般调用Registries.POTION.getEntry()方法返回的药水注册条目对象。传递一个药水对象;

在入口点类中的onInitialize()方法中,直接调用FabricBrewingRecipeRegistryBuilder.BUILD.register()方法,然后传递一个函数表达式;

FabricBrewingRecipeRegistryBuilder.BUILD.register(builder -> {
		builder.registerPotionRecipe(
				Potions.WATER,
				Items.POTATO,
				Registries.POTION.getEntry(TATER_POTION)
		);
});

在函数表达式中通过BrewingRecipeRegistry.Builder对象调用registerPotionRecipe()方法设置药水酿造配方的详细信息,其中的参数按照顺序分别设置了输入药水为水瓶Potions.WATER、原料为土豆Items.POTATO和输出药水的注册条目对象Registries.POTION.getEntry(TATER_POTION)getEntry()方法中传递药水对象。

启动游戏测试,使用酿造台酿造药水;
在这里插入图片描述
使用土豆(游戏称之为马铃薯)作为原料,水瓶作为输入药水;
在这里插入图片描述
也可以尝试使用改性剂,将普通药水转变为喷溅型和滞留型药水。

创建自定义药水效果

若不想使用原版游戏中的药水效果,可以为药水创建自定义效果,以此创建更加定制化的药水。在本节,我们为“土豆药水”添加一个在一段时间内给玩家增加经验值的状态效果。

想要创建自定义药水效果,需要创建一个自定义药水效果类,使其继承StatusEffect类并实现相关方法。根据官方文档中的写法,自定义药水效果类中一般重写其超类的以下方法:

  • 构造方法:其中应当直接调用其超类StatusEffect中的构造方法,其中传递两个参数;
    • StatusEffectCategory category:指定药水效果类别,代表状态效果对玩家有益、有害或者是中性,传递StatusEffectCategory枚举类中的枚举常量;
    • int color:指定药水的颜色,只能传递16进制RGB颜色码;
  • canApplyUpdateEffect():用于控制药水效果的触发频率。返回值为布尔类型,代表是否在当前游戏刻触达效果,也就是说,此方法在每游戏刻都会执行。方法一般返回true
  • applyUpdateEffect():用于定义触发药水效果的具体逻辑。返回值为布尔类型,方法应当始终返回true

1.首先在com/example/test目录中创建effect目录,然后在其中创建TaterEffect.java。使其继承StatusEffect类并重写刚刚提到的方法;

public class TaterEffect extends StatusEffect {
    public TaterEffect() {}
    
    @Override
    public boolean canApplyUpdateEffect(int duration, int amplifier) {
        return super.canApplyUpdateEffect(duration, amplifier);
    }
    
    @Override
    public boolean applyUpdateEffect(ServerWorld world, LivingEntity entity, int amplifier) {
        return super.applyUpdateEffect(world, entity, amplifier);
    }
}

2.在构造方法中使用super()调用其父类StatusEffect中的构造方法;

public TaterEffect() {
	super(StatusEffectCategory.BENEFICIAL, 0x9fff41);
}

设置药水类型为StatusEffectCategory.BENEFICIAL,代表药水对玩家有益;设置药水与生效时的粒子颜色为0x9fff41(一种与经验球颜色类似的黄绿色);

3.令canApplyUpdateEffect()方法始终返回true

@Override
public boolean canApplyUpdateEffect(int duration, int amplifier) {
    return true;
}

4.在applyUpdateEffect()方法中完成状态效果的具体逻辑,即为玩家增加经验值;

@Override
public boolean applyUpdateEffect(ServerWorld world, LivingEntity entity, int amplifier) {
    if (entity instanceof PlayerEntity) {
        ((PlayerEntity) entity).addExperience(1 << amplifier); 
    }
    return super.applyUpdateEffect(world, entity, amplifier);
}

首先确定实体为玩家,然后将LivingEntity对象强制转换为PlayerEntity并调用addExperience()方法,为玩家增加经验值,此处使用了1 << amplifier的写法,参数amplifier代表效果等级,1指的是增加的经验值数量,并不是经验等级。

每游戏刻增加的经验值为1并按照效果等级amplifier对其进行位运算,即效果等级为II时,每游戏刻增加的经验值为2;效果等级为III时,每游戏刻增加的经验值为4,以此类推。效果等级每增加一级,每游戏刻增加的经验值将会以指数级扩大一倍。

在游戏注册表中注册自定义药水效果

自定义药水效果类已经创建完毕,现在还需要将其在游戏注册表中注册。

这里使用到了Registry.registerReference()方法,与Registry.register()方法不同的是,registerReference()返回的是状态效果注册条目RegistryEntry<StatusEffect>对象,用于在注册药水时传递自定义药水效果。

1.在入口点类中声明静态常量EXP,类型为RegistryEntry<StatusEffect>,使用Registry.registerReference()方法对其初始化;

public static final RegistryEntry<StatusEffect> EXP = Registry.registerReference(Registries.STATUS_EFFECT,
		Identifier.of(FabricDocsReference.MOD_ID, "exp"),
		new TaterEffect());

参数列表与Registry.register()方法完全相同,首先确定注册键为状态效果Registries.STATUS_EFFECT,标识符为模组Id和路径“exp”组成的Identifier对象,最后传递自定义药水效果的对象。

2.将注册药水代码中的药水效果从黑暗StatusEffects.DARKNESS改为EXP

public static final Potion TATER_POTION = Registry.register(
				Registries.POTION,
				Identifier.of(FabricDocsReference.MOD_ID, "tater"),
				new Potion("tater",new StatusEffectInstance(EXP,1200,0)));

3.启动游戏,在创造模式物品栏中找到土豆药水;
在这里插入图片描述
4.可以看到颜色和中文名称已经设置完毕。然后使用土豆药水,可以看到经验值正在增加;
请添加图片描述
5.打开物品栏可以看到状态效果,但是没有状态效果的图标和状态效果的中文名称。
在这里插入图片描述

为自定义药水效果添加纹理并在语言文件添加翻译键值对

最后,我们为药水状态效果添加纹理图和中文翻译。

在这里插入图片描述
1.状态效果的纹理与物品纹理的存放位置不太相同,应当固定地添加到assets/test/textures/mob_effect目录中,且文件名与注册药水效果时使用的路径相同;
在这里插入图片描述
图片大小应为18x18;

2.打开语言文件zh-cn.js,添加一条键值对;

{
	...
	"effect.test.exp":"经验增长",
	...
}

test为模组Id,exp为注册药水效果时使用的路径;

3.再次启动游戏,查看药水效果的图标与中文名称。
在这里插入图片描述

本章小结

本章详细阐述了如何在游戏中添加自定义药水,并为其配置酿造配方和自定义药水效果。总体来讲,使用到的新APi较少,难度适中。感谢各位的阅读,有兴趣可以订阅此专栏!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值