Minecraft mod制作简易教程(三)——创建一个物品

一、模块化管理你的程序

一个mod可能包含数百个物品,还有block、Recipe、WorldGenerator等很多东西,如果不进行模块化管理,到后期将会难以进行调试和bug处理。
所以从一开始就要好好管理你的代码
我们现在com.hexatomic_ring.realmining下新建一个包item
这里的模块化管理当然不是简单地把所有关于Item的代码都扔到这个包里。如果翻一下Minecraft源代码,就会发现对item的调用都是以这样的格式:

Items.AIR

但是mc所有的物品都是在Item.java里实例化的,这里的Items类相当于一个封装
所以我们也照样在item下建两个类ModItems和ItemLoader

二、简易物品

在较新版的mc中不是每一个物品都有一个专门的类来实例化,例如在1.12.2中一共只有80个与item相关的类。这是如何做到的呢?
我们来看一种最基础的item,它的属性只有名称、创造模式物品栏、耐久、挖掘等级、最大堆叠数量等,你就不需要用一个特殊的类来构建这些性质。这一点在官方教程中写得很清楚:https://mcforge.readthedocs.io/en/latest/items/items/
其实现方法是用setUnlocalizedName()之类的方法,其返回值为this,即可以把各种设置写成一条链,只占用一行的空间,于是没有必要单独创建一个类。
关于item的具体结构可以自由发挥,这里仅代表个人见解。
现在我要做一个物品叫做rubble
我们在ItemLoader.java中类的声明前一行加一个注解:

@Mod.EventBusSubscriber(modid = “realmining”)

设置物品参数

这样Forge就能注意到这个类会注册一些东西。
我们先建一个类型为Item的数组

private static Item[] items = {
new Item().setUnlocalizedName(“rubble”).setRegistryName(“rubble”).setCreativeTab(CreativeTabs.MATERIALS)
};

这里的setUnlocalizedName是设置非本地化名称,建议使用小写驼峰写法,由于rubble只有一个单词,换个例子:realMining
setRegistryName是设置注册名,建议使用下划线写法,如real_mining
setCreativeTab是设置创在模式物品栏,这样我的物品就能在“杂项”一栏中找到。你可以翻看net.minecraft.creativetab.CreativeTabs并选择合适的物品栏
你应该注意到了这个数组被声明为private,那我们就需要一个拆封的方法,比如按照非本地化名称找到对应的item。
如果翻看Item.java就会找到这样一条方法:

public String getUnlocalizedName()
{
return “item.” + this.unlocalizedName;
}

我们就利用这条方法查找:

public static Item getByName(String name){
for(Item item:items)
if(item.getUnlocalizedName().equals(name))
return item;
return Items.AIR;
}

注册这个物品

下面注册这个item:

@SubscribeEvent
public static void registerItems(RegistryEvent.Register< Item> event) {
for(Item item : items){
event.getRegistry().register(item);
}
}
}

虽然forge提供了registerAll方法,但由于我是用一个数组来管理所有物品的,所以仍然多次使用register。

访问这个物品

在ModItems.java中写入:

public static final Item RUBBLE;
static{
RUBBLE = ItemLoader.getByName(“item.rubble”);
}

这里注意一下final表示这个变量的值一经定义不能再修改,也就是常量,一般用全大写加下划线表示,如REAL_MINING。
这样就可以用ModItems.RUBBLE来调取这个物品啦

给物品添加材质

一个物品再简单,也不能没有材质
我们把前面注册物品的部分改成这样:

public static void registerItems(RegistryEvent.Register< Item> event) {
for(Item item : items){
ModelLoader.setCustomModelResourceLocation(item,0,new ModelResourceLocation(item.getRegistryName(), “inventory”));
event.getRegistry().register(item);
}
}

也就是加了一行,这一行制定了这个物品材质模型文件的路径,即src/resources/assets//models/item/.json,我们需要New一些包和这个文件。注意文件名是用register name注册的,所以也要按小写字母下划线的格式。我们把这下写进.json,我这里是rubble.json:

{
“parent”: “builtin/generated”,
“textures”: {
“layer0”: “realmining:items/rubble”
},
“display”: {
“thirdperson”: {
“rotation”: [ -90, 0, 0 ],
“translation”: [ 0, 1, -2 ],
“scale”: [ 0.55, 0.55, 0.55 ]
},
“firstperson”: {
“rotation”: [ 0, -135, 25 ],
“translation”: [ 0, 4, 2 ],
“scale”: [ 1.7, 1.7, 1.7 ]
}
}
}

realmining:items/rubble定义了它的材质文件的位置,我们需要把一个材质文件放到src\main\resources\assets\realmining\textures\rubble.png。它的分辨率要求是nn,n必须是二的指数,一般用1616。
后面的一堆代码定义了这个物品拿在手里时的状态。
现在可以打开游戏,在指令中输入/give @p reaalmining:rubble试试看了

三、更复杂的物品

上面的方法只适合制作最简单的物品
现在,我需要做几个共享一些共性的物品
我还需要让它们有一些特殊的功能
解决方法就是——创建一个物品类

创建一个物品类

我现在要做三种不同形状的石块,它们右击硬度大于等于石头的方块时会都碎成两块小石块
在item包下New一个ItemRock类,并把类的声明改成这样:

public class ItemRock extends Item {
}

也就是它继承了Item,我们创建实例的时候也符合Item类型
随后修改ItemLoader:

private static Item[] items = {
new Item().setUnlocalizedName(“rubble”).setRegistryName(“rubble”).setCreativeTab(CreativeTabs.MATERIALS),
new ItemRock().setUnlocalizedName(“rockStrip”).setRegistryName(“rock_strip”).setCreativeTab(CreativeTabs.MATERIALS),
new ItemRock().setUnlocalizedName(“rockPlate”).setRegistryName(“rock_plate”).setCreativeTab(CreativeTabs.MATERIALS),
new ItemRock().setUnlocalizedName(“rockDiscoid”).setRegistryName(“rock_discoid”).setCreativeTab(CreativeTabs.MATERIALS),
new Item().setUnlocalizedName(“rocklet”).setRegistryName(“rocklet”).setCreativeTab(CreativeTabs.MATERIALS)
};

修改ModItems:

public static final Item RUBBLE;
public static final Item ROCK_STRIP;
public static final Item ROCK_PLATE;
public static final Item ROCK_DISCOID;
public static final Item ROCKLET;
static{
RUBBLE = ItemLoader.getByName(“item.rubble”);
ROCK_STRIP = ItemLoader.getByName(“item.rockStrip”);
ROCK_PLATE = ItemLoader.getByName(“item.rockPlate”);
ROCK_DISCOID = ItemLoader.getByName(“item.rockDiscoid”);
ROCKLET = ItemLoader.getByName(“item.rocklet”);
}

当然还要给新物品添加对应的材质,这里就不加赘述了。

实现鼠标右键事件

像这种简单的事件并不需要Event类,如果翻看过ItemBucket或者ItemBoat的话就会发现一个叫onItemRightClick的方法,输入值为World worldIn, EntityPlayer playerIn, EnumHand handIn,返回值为ActionResult
虽然一眼还不是很清楚ActionResult是什么,但我们可以游戏效果来倒推一下,也可以通过Ctrl+Click追踪源代码。
更重要的是我们要直到如何清除手里的物品,获取对准的方块的信息以及在该位置生成掉落物品的方法。
首先看这一句

ItemStack itemstack = playerIn.getHeldItem(handIn);

很显然获得了手中的物品

return new ActionResult(EnumActionResult.FAIL, itemstack);

表示动作失败,还有PASS和SUCCESSFUL,其中只有返回SUCCESSFUL时才会有使用物品的动画效果。

itemstack.shrink(1);

表示移除了手上的一个物品

worldIn.rayTraceBlocks(vec3d, vec3d1, true)

会返回一个RayTraceResult,与玩家看着的方块有关
通过解读源代码,我们可以写出自己的方法:

public ActionResult< ItemStack> onItemRightClick(World worldIn, EntityPlayer playerIn, EnumHand handIn)
{
ItemStack itemstack = playerIn.getHeldItem(handIn);
float f = 1.0F;
float f1 = playerIn.prevRotationPitch + (playerIn.rotationPitch - playerIn.prevRotationPitch) * 1.0F;
float f2 = playerIn.prevRotationYaw + (playerIn.rotationYaw - playerIn.prevRotationYaw) * 1.0F;
double d0 = playerIn.prevPosX + (playerIn.posX - playerIn.prevPosX) * 1.0D;
double d1 = playerIn.prevPosY + (playerIn.posY - playerIn.prevPosY) * 1.0D + (double)playerIn.getEyeHeight();
double d2 = playerIn.prevPosZ + (playerIn.posZ - playerIn.prevPosZ) * 1.0D;
Vec3d vec3d = new Vec3d(d0, d1, d2);
float f3 = MathHelper.cos(-f2 * 0.017453292F - (float)Math.PI);
float f4 = MathHelper.sin(-f2 * 0.017453292F - (float)Math.PI);
float f5 = -MathHelper.cos(-f1 * 0.017453292F);
float f6 = MathHelper.sin(-f1 * 0.017453292F);
float f7 = f4 * f5;
float f8 = f3 * f5;
double d3 = 5.0D;
Vec3d vec3d1 = vec3d.addVector((double)f7 * d3, (double)f6 * d3, (double)f8 * d3);
RayTraceResult raytraceresult = worldIn.rayTraceBlocks(vec3d, vec3d1, true);
if (raytraceresult == null){
return new ActionResult< ItemStack>(EnumActionResult.PASS, itemstack);
}else if(raytraceresult.typeOfHit == RayTraceResult.Type.BLOCK && !worldIn.isRemote){
BlockPos pos = raytraceresult.getBlockPos();
if(worldIn.getBlockState(pos).getBlockHardness(worldIn,pos) >= 1.5F){
itemstack.shrink(1);
worldIn.spawnEntity(new EntityItem(worldIn,2*(pos.getX()+0.5)-vec3d1.x,2*(pos.getY()+0.5)-vec3d1.y,2*(pos.getZ()+0.5)-vec3d1.z,new ItemStack(ModItems.ROCKLET,2)));
}
return new ActionResult< ItemStack>(EnumActionResult.SUCCESS, itemstack);
}else{
return new ActionResult(EnumActionResult.FAIL, itemstack);
}
}

这里Vec3d是一个坐标,它与BlockPos的区别在于它的坐标是double类型的
创建一个RayTraceResult 需要一个起点和一个终点,它会返回玩家视线是对着方块、实体还是空的。World.spawnEntity方法用来创建一个实体。
虽然一开始一段代码确定了视线的终点,但从游戏效果看,这个点通常在目标方块内部远离玩家的位置,所以我采用了一种不是很规范的方式来取得一个相对准确的坐标。

上一篇:Minecraft mod制作简易教程(二)——Mod配置
https://blog.csdn.net/lyh20000420/article/details/83659163
下一篇:Minecraft mod制作简易教程(四)——创建一个方块
https://blog.csdn.net/lyh20000420/article/details/83660874
回到目录:https://blog.csdn.net/lyh20000420/article/details/83659423

  • 11
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
制作一个 Minecraft Mod 需要一些基本的编程知识和一些工具。以下是制作 Minecraft Mod 的基本步骤: 1. 下载并安装 Java 开发工具包(JDK):在你的计算机上安装 JDK,确保使用的是适合你操作系统的版本。 2. 下载并安装 Minecraft Forge:Minecraft Forge 是一个用于创建和加载 Mod 的工具。在官方网站(https://files.minecraftforge.net/)上下载适合你 Minecraft 版本的 Forge 安装程序,并按照其指南进行安装。 3. 创建一个新的 Mod 项目:使用 IDE(集成开发环境)如 Eclipse 或 IntelliJ IDEA 创建一个新的 Java 项目。 4. 添加 Minecraft Forge 到项目:将下载的 Minecraft Forge 的库文件添加到项目的构建路径中。 5. 编写 Mod 代码:使用 Java 编写你的 Mod 代码。你可以使用 Minecraft Forge 提供的 API 来添加新的方块、物品、生物、合成配方等。 6. 编译和导出 Mod:将你的代码编译为可执行的 Mod 文件。这通常是一个 JAR 文件。 7. 将 Mod 安装到 Minecraft:将生成的 Mod 文件复制到你的 Minecraft 安装目录下的 "mods" 文件夹中。 8. 启动 Minecraft 并测试 Mod:启动 Minecraft 游戏,确保你的 Mod 能够正常加载和运行。 请注意,这只是制作 Minecraft Mod 的基本步骤。具体的细节和功能取决于你想要创建的 Mod 的复杂程度和要实现的特定功能。你可能需要进一步学习 Minecraft Forge 的文档和其他教程来深入了解如何开发特定类型的 Mod
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值