制作一个物品一共分几步

制作一个物品一共分三步:

  1. 创建一个物品
  2. 实例化并注册这个物品
  3. 为这个物品添加模型和材质

Minecraft中,使用八个金锭和一个苹果可以创造一个金苹果,那我们是不是可以创造一个金蛋呢,这一次教程会一步一步地带着你完成制作新物品的全过程。

创建一个物品

如果读者翻看了net.minecraft.item包,想必就会发现你在Minecraft中遇到的各种物品,都继承了Item类,那很明显,我们制作的物品也要继承这个类。

新建一个包com.github.ustc_zzzz.fmltutor.item,在其中创建一个类ItemGoldenEgg

src/main/java/com/github/ustc_zzzz/fmltutor/item/ItemGoldenEgg.java:

package com.github.ustc_zzzz.fmltutor.item;

import net.minecraft.item.Item;

public class ItemGoldenEgg extends Item
{
    public ItemGoldenEgg()
    {
        super();
        this.setUnlocalizedName("goldenEgg");
    }
}

这里的setUnlocalizedName方法为该物品添加了一个非本地化的名称,该名称为“item.”+设置的名称,比如这里就是item.goldenEgg,这个非本地化名称,与本地化和国际化有关,在后面的部分我们会讲到。非本地化名称尽量使用小写驼峰式写法,即第一个词以小写字母开始,第二个词开始首字母大写,中间不使用任何符号分隔

实例化并注册这个物品

CommonProxy类中添加下面的代码:

src/main/java/com/github/ustc_zzzz/fmltutor/common/CommonProxy.java(部分):

    public void preInit(FMLPreInitializationEvent event)
    {
        new ItemLoader(event);
    }

新建一个类ItemLoader

src/main/java/com/github/ustc_zzzz/fmltutor/item/ItemLoader.java:

package com.github.ustc_zzzz.fmltutor.item;

import net.minecraft.item.Item;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.registry.GameRegistry;

public class ItemLoader
{
    public static Item goldenEgg = new ItemGoldenEgg();

    public ItemLoader(FMLPreInitializationEvent event)
    {
        register(goldenEgg, "golden_egg");
    }

    private static void register(Item item, String name)
    {
        GameRegistry.registerItem(item.setRegistryName(name));
    }
}

新建一个类进行初始化的原因是当你的物品越来越多,如果所有的注册过程都直接在CommonProxy类中进行,随着注册的对象越来越多,这些注册的对象会越来越难以管理。换句话说,这体现了代码模块化的原则。

首先,我们要实例化这个物品:

src/main/java/com/github/ustc_zzzz/fmltutor/item/ItemLoader.java(部分):

    public static Item goldenEgg = new ItemGoldenEgg();

然后,我们来到了这块的重点,注册这个物品:

src/main/java/com/github/ustc_zzzz/fmltutor/item/ItemLoader.java(部分):

        GameRegistry.registerItem(item.setRegistryName(name));

GameRegistry是Forge提供的一个用来注册物品、方块、合成表、烧炼规则等各种常见内容的类,比如下面的用于注册的方法我们在后面都会遇到并加以讲解:

  • registerBlock方法用于注册方块
  • registerFuelHandler方法用于注册燃料
  • registerItem方法用于注册物品
  • registerTileEntity方法用于注册TileEntity(后面会讲到什么是TileEntity)
  • registerWorldGenerator方法用于注册世界生成器以生成不同的世界
  • addRecipe方法和addShapedRecipe方法用于注册合成表
  • addSmelting方法用于注册物品烧炼规则

这个方法需要传入一个Item类的实例用于注册物品,那么如何指定这个物品的id呢?在示例中,我们通过调用物品的setRegistryName方法指定了物品的id,这也是从1.8.9开始指定物品id的通用做法。

有一点需要注意,从Minecraft的1.9及以上版本开始,GameRegistry类中相应的方法名被修改为了register方法,因此注册物品时需要用到的代码会有一点微小的变动。

我们这里通过参数提供物品的id。id请尽量使用小写字母加下划线,并且同一个Mod下的物品id不能相同,有的Mod会使用驼峰式,这样的好处是把物品的非本地化名称和物品id设置成相同的,但是我们不推荐这样的做法

现在不管是在服务端,还是在客户端,Forge都会在preInit阶段,运行到ItemLoader类中的构造函数,也就是实例化一个物品,并注册它。

现在运行客户端,运行命令:

/give @a fmltutor:golden_egg

玩家的手上便多了一个新的物品。

为这个物品添加模型和材质

可以看到,你手上的物品,现在还什么都没有,只是一个两种颜色交替的方块,这是因为你没有添加模型和材质。模型的作用是保证你手里的物品是一个扁平的长方体,而材质的作用,就是给这个长方体上色。

首先,新建一个文件夹:src/main/resources/assets/fmltutor/models/item,并在其中新建一个文件:golden_egg.json

src/main/resources/assets/fmltutor/models/item/golden_egg.json:

{
    "parent": "builtin/generated",
    "textures": {
        "layer0": "fmltutor:items/golden_egg"
    },
    "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 ]
        }
    }
}

当然,这里的fmltutor就是Mod id,golden_egg就是你的物品id。

这个json的文件,就是这个物品的模型,这个文件的内容解释起来极其复杂,这也不是教程负责的介绍内容,直接抄下来就好了,但是有的地方是显而易见的:

src/main/resources/assets/fmltutor/models/item/golden_egg.json(部分):

    "textures": {
        "layer0": "fmltutor:items/golden_egg"
    },

这一部分告诉我们的是这个物品材质的位置,也就是fmltutor:items/golden_egg,很明显,我们需要建立一个材质文件。这里使用的是16x16的材质文件(当然Minecraft也支持尺寸更大如32x32的材质文件,不过建议还是使用16x16的),新建文件夹src/main/resources/assets/fmltutor/textures/items,把制作完成的goldenegg.png放入(其实是我照着鸡蛋的原图嗐改的==||):

src/main/resources/assets/fmltutor/textures/items/golden_egg.png:

golden_egg

所有模型和材质都准备好了,现在需要做的,就是让Minecraft知道你准备的模型和材质了。

修改ItemLoader类的内容:

src/main/java/com/github/ustc_zzzz/fmltutor/item/ItemLoader.java:

package com.github.ustc_zzzz.fmltutor.item;

import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.item.Item;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

public class ItemLoader
{
    public static Item goldenEgg = new ItemGoldenEgg();

    public ItemLoader(FMLPreInitializationEvent event)
    {
        register(goldenEgg, "golden_egg");
    }

    @SideOnly(Side.CLIENT)
    public static void registerRenders()
    {
        registerRender(goldenEgg);
    }

    private static void register(Item item, String name)
    {
        GameRegistry.registerItem(item.setRegistryName(name));
    }

    @SideOnly(Side.CLIENT)
    private static void registerRender(Item item)
    {
        ModelResourceLocation model = new ModelResourceLocation(item.getRegistryName(), "inventory");
        ModelLoader.setCustomModelResourceLocation(item, 0, model);
    }
}

我们来看这一段:

src/main/java/com/github/ustc_zzzz/fmltutor/item/ItemLoader.java(部分):

    @SideOnly(Side.CLIENT)
    private static void registerRender(Item item)
    {
        ModelResourceLocation model = new ModelResourceLocation(item.getRegistryName(), "inventory");
        ModelLoader.setCustomModelResourceLocation(item, 0, model);
    }

Forge提供了ModelLoader类用于加载和处理模型,其setCustomModelResourceLocation方法有三个参数:

  • 第一个参数是要被注册的物品。
  • 第二个参数是这个物品的Metadata。Metadata是一个用于区分同一个物品或方块的不同状态的数据,比如钟表的十六种状态、羊毛的十六种颜色,在3.2.1节会讲到Metadata,默认为零就好了。
  • 第三个参数就是这个物品模型的资源位置了,资源位置是类ModelResourceLocation的一个实例,它用于描述一个模型,在后面我们还会比较常用到这个类的。

ModelResourceLocation被用于标注模型的位置,通常为由冒号(:)和井号(#)分隔的三个字符串组成,对于我们这里构造的ModelResourceLocation,它的一部分通过调用物品的getRegistryName方法得到,第二部分由我们指定,为inventory,是一个固定的字符串,代表作为一个物品的渲染模型。

在这里,第一部分为fmltutor:golden_egg,第二部分为inventory,组合后的ModelResourceLocation就是fmltutor:golden_egg#inventory。Minecraft便会去相应的目录下寻找相应的资源:

  • fmltutor指示游戏应该在assets.fmltutor包下找到这个资源
  • inventory指示游戏应该在assets.fmltutor.models.item包下找到这个资源
  • golden_egg指示这个资源就是assets.fmltutor.models.item.golden_egg.json,对应到源代码,就是src/main/resources/assets/fmltutor/models/item/golden_egg.json这一文件

当然,上面已经提到了,golden_egg.json模型文件里已经包含了材质的信息。

@SideOnly注解的作用是注解这一方法、类等只作用于客户端或服务端。很明显,对于模型和材质的操作只会在客户端执行(实际上如果在服务端执行会出错),所以我们同时要在ClientProxypreInit阶段中初始化:

src/main/java/com/github/ustc_zzzz/fmltutor/client/ClientProxy.java:

package com.github.ustc_zzzz.fmltutor.client;

import com.github.ustc_zzzz.fmltutor.common.CommonProxy;

import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;

public class ClientProxy extends CommonProxy
{
    @Override
    public void preInit(FMLPreInitializationEvent event)
    {
        super.preInit(event);
        new ItemRenderLoader();
    }

    @Override
    public void init(FMLInitializationEvent event)
    {
        super.init(event);
    }

    @Override
    public void postInit(FMLPostInitializationEvent event)
    {
        super.postInit(event);
    }
}

com.github.ustc_zzzz.fmltutor.client下新建ItemRenderLoader类:

src/main/java/com/github/ustc_zzzz/fmltutor/client/ItemRenderLoader.java:

package com.github.ustc_zzzz.fmltutor.client;

import com.github.ustc_zzzz.fmltutor.item.ItemLoader;

public class ItemRenderLoader
{
    public ItemRenderLoader()
    {
        ItemLoader.registerRenders();
    }
}

现在在客户端,Forge会在preInit阶段,运行到ItemRenderLoader类的构造函数,进而运行到ItemLoader类中的registerRenders方法中的代码,也就是注册这个物品的渲染,而在服务端则不会运行。

现在运行游戏,你的手上是不是有了一个金色的蛋啦~

最后说一句,把所有只在客户端执行的代码放到同一个client文件夹下是一个好的习惯。

results matching ""

    No results matching ""