用户:MashKJo/1.12.2模组开发教程/5.第一个物品
所有物品都是net.minecraft.item.Item
类的实例。要加入一个新物品,可以直接实例化Item类,也可以先继承Item类再实例化。
实例化与注册
对于没有什么额外行为的物品(一般这种物品会被设计为合成材料或生物掉落物),一般都选择前者;反之则选择后者。Item类有许多setter和getter。限于我们目前的知识水平,getter笔者暂且不讲(后面就知道为什么了),先讲setter。
Item类包括但不限于如下的一些setter:
- setCreativeTab:用于设定物品所在的创造模式物品栏(CreativeTabs),传入一个CreativeTabs对象,原版所有的创造模式物品栏都在CreativeTabs类中以静态字段的方式存在
- setUnlocalizedName:用于设定物品在lang文件中所使用的本地化键名,传入一个字符串,如传入
"example_item"
这个字符串,那么它在lang文件中的本地化键名就是item.example_item.name
- setMaxStackSize:用于设定物品在格子中的最大堆叠数(默认为64)
- setMaxDamage:这个setter的含义有些复杂,在一定情况下,用于设定物品能被损耗的最大次数——其实就是耐久值
- setNoRepair:用于设定物品不可被修复
- setContainerItem:用于设定该物品的“容器物品”——传入一个Item对象,实际效果为在工作台中参与合成后,设定的这个“ContainerItem”会留在工作台格子中
此外,不要忘了还要调用setRegistryName这一setter——这是Item类实现IForgeRegistryEntry<Item>获得的方法。
上述setter的返回值是Item类型的,因此这代表着我们可以new完Item之后直接通过链式调用这些setter来设定该Item对象的一些属性;如果你是先继承了Item类,这些一般在构造方法中被调用:
如,笔者这里添加了一个红宝石(Ruby)物品:
src/main/java/net/tutorial_mod/item/TutorialModItems.java:
public static Item RUBY = new Item().setRegistryName(TutorialMod.MODID, "ruby") .setUnlocalizedName("ruby") .setCreativeTabs(CreativeTabs.MISC);
笔者这里新建了一个类:TutorialModItems,来统一存放模组添加的所有物品实例——这是一个好习惯,建议读者也这么做。
最后,再通过监听RegistryEvent.Register<Item>事件注册:
src/main/java/net/tutorial_mod/item/ItemRegistryHandler.java:
package net.tutorial_mod.item; import static net.tutorial_mod.item.TutorialModItems.*; import net.minecraft.item.Item; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.tutorial_mod.TutorialMod; @Mod.EventBusSubscriber(modid = TutorialMod.MODID) public class ItemRegistryHandler { @SubscribeEvent public static void registerItems(RegistryEvent.Register<Item> event){ event.getRegistry().register(RUBY); } }
这时候启动游戏,就可以在创造模式物品栏“杂项”下,看到一个材质为紫黑块、名称为“item.ruby.name”的物品了。虽然暂时没什么用,且很难看,但这毕竟是我们添加的第一个物品了。
给物品设定模型文件和材质
Minecraft中所有物品的渲染都是基于物品对应的模型,而物品的模型指定了物品的材质、旋转角度等渲染要素。
首先我们应该通过监听ModelRegistryEvent这个事件来把某个特定的物品(其实准确地说,是ItemStack,只不过仅能额外指定meta这一字段,ItemStack会在下一小节具体讲到)和某个模型文件的路径进行绑定,之前说过,渲染这种涉及到视觉效果的东西,其相关的代码应该只在物理客户端被调用,因此我们在client包下新建一个源文件ModelRegistryHandler.java,使用ModelLoader#setCustomModelResourceLocation
这一静态方法,来完成物品和模型文件的绑定:
src/main/java/net/tutorial_mod/client/model/ModelRegistryHandler.java:
package net.tutorial_mod.client.model; import static net.tutorial_mod.item.TutorialModItems.*; import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import net.tutorial_mod.TutorialMod; @Mod.EventBusSubscriber(value = Side.CLIENT, modid = TutorialMod.MODID) public class ModelRegistryHandler{ @SubscribeEvent public static void bindItemModels(ModelRegistryEvent event){ setModelResourceLocation(RUBY, 0, RUBY.getRegistryName()); } private static void setModelResourceLocation(Item item, int meta, ResourceLocation location){ ModelLoader.setCustomModelResourceLocation(item, meta, new ModelResourceLocation(location, "inventory")); } }
我们在@EventBusSubscriber
注解的参数value中指定了该类的物理端:Side.CLIENT,确保它只会存在于物理客户端。如果你选择手动注册该事件,那么请写在ClientProxy中——之前的所有事件注册则都是写在CommonProxy中。
这里笔者写了个private方法简单地把setCustomModelResourceLocation包装了一下,以节省代码量。然后我们就可以来看看这个方法的形参了:第1个参数要求传入一个Item,这自然不必多说;第2个参数是个int量,名为meta——meta到底是什么意思,这会在下一节“ItemStack”讲到,如果读者尚不清楚meta代表什么,那这一项就填0就行;第3个参数是一个ModelResourceLocation——这个类是ResourceLocation对模型的特化版,在示例代码中我们用的是它的(ResourceLocation location, String variantIn)
这个构造方法,注意传入的ResourceLocation并不要求我们填完整的模型文件路径,而是类似于这样:new ResourceLocation("modid:registry_name")
,这里我们用getRegistryName这一方法获取了这个ResourceLocation;至于那个variantIn,这个解释起来比较复杂,鉴于我们这里是要绑定物品和模型文件,因此直接填写"inventory"
即可——inventory,物品栏,也很好理解。
另外这里说一句,能存在于物品栏(包括创造模式物品栏、玩家背包、箱子中的物品栏)中的一定是物品。如果你把物品按Q键丢出去,它就不是物品了——而是实体,准确地说是EntityItem,其通用逻辑是能被玩家、僵尸等生物捡起来,并转化为物品。
上述代码成功地把红宝石这一物品的模型映射到了位于路径为assets/tutorial_mod/models/item/ruby.json
的JSON文件,这就是我们的模型文件了:
src/main/resources/assets/tutorial_mod/models/item/ruby.json:
{ "parent": "item/generated", "textures": { "layer0": "tutorial_mod:items/ruby" } }
读者照抄就行,这块属于Minecraft原版的内容,如果想了解更多,可以去Minecraft Wiki查阅相关资料。
这个模型文件将红宝石物品的唯一一层材质指定为路径为assets/tutorial_mod/textures/items/ruby.png
的PNG图片。注意材质文件只能是PNG,如果你想要实现类似动图的效果,也不能用GIF,而是要用Minecraft的纹理动画机制。且材质图片最好是正方形,边长为2的倍数,否则容易出问题——一出问题,就还是紫黑块,不跟你玩虚的。这里layer0的路径指定,用法类似于用于指定文件具体路径的ResourceLocation构造器,只是省略了"textures/"
这一层路径——实际上这个路径,在Minecraft和Forge中都是被硬编码了的。
将预先准备好的材质文件放入指定路径,进入游戏,不出意外的话,你应该能在创造模式物品栏中看到一个正常显示材质的物品——红宝石了。
给物品提供本地化支持
所有语言文件都是扩展名为.lang的文件,都存放在assets/[modid]/lang
路径下。你应该至少为你的模组添加对英文和简体中文的支持。所以:
src/main/resources/assets/tutorial_mod/lang/en_us.lang:
item.ruby.name=Ruby
src/main/resources/assets/tutorial_mod/lang/zh_cn.lang:
item.ruby.name=红宝石
大功告成!现在进入游戏,你应该能看到:红宝石这一物品,已经能根据当前的游戏语言显示正确的名称了。