制作一个方块一共分几步

制作一个方块一共只比物品多一步:

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

我们发现雪可以合成雪块,那么,草可不可以合成草块呢= =本次教程将带领你一步一步地做出一个草块。

创建一个方块

创建一个方块的过程,和创建一个物品的过程非常相似。

这里我们如法炮制,新建一个包com.github.ustc_zzzz.fmltutor.block,并新建文件BlockGrassBlock.java,在其中创建一个类,使其继承方块类:

src/main/java/com/github/ustc_zzzz/fmltutor/block/BlockGrassBlock.java:

package com.github.ustc_zzzz.fmltutor.block;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;

public class BlockGrassBlock extends Block
{
    public BlockGrassBlock()
    {
        super(Material.ground);
        this.setUnlocalizedName("grassBlock");
        this.setHardness(0.5F);
        this.setStepSound(soundTypeGrass);
    }
}

一个方块初始化的时候和物品有一点不同,例如需要设定方块的材质,这里设定成和泥土一样的材质。

当然,就像上面那样,方块往往有很多需要设定的性质,现将一些常见的设定方法列举如下:

  • setBlockUnbreakable方法用于设定方块的硬度为-1,即不能损坏。
  • setHardness方法用于设定方块的硬度,如黑曜石是50,铁块5,金块3,圆石2,石头1.5,南瓜1,泥土0.5,甘蔗0,基岩-1。
  • setHarvestLevel方法用于设定方块的可挖掘等级,如钻石镐是3,铁2,石1,木金0。
  • setLightLevel方法用于设定方块的光照,其周围的光照为设定值x15,如岩浆1.0,对应15,红石火把0.5,对应7.5。
  • setLightOpacity方法用于设定方块的透光率,数值越大透光率越低,如树叶和蜘蛛网是1,水和冰3。
  • setResistance方法用于设定方块的爆炸抗性,如木头的抗性为4,石头为10,黑曜石为2000,基岩为6000000。
  • setStepSound方法用于设定走在方块上的响声。
  • setTickRandomly方法用于设定方块是否会接受随机Tick(如农作物)。

实例化并注册这个方块

同样,在CommonProxy类中添加下面的代码:

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

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

新建一个类BlockLoader,以完成对应的方块的注册:

src/main/java/com/github/ustc_zzzz/fmltutor/block/BlockLoader.java:

package com.github.ustc_zzzz.fmltutor.block;

import net.minecraft.block.Block;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.registry.GameRegistry;

public class BlockLoader
{
    public static Block grassBlock = new BlockGrassBlock();

    public BlockLoader(FMLPreInitializationEvent event)
    {
        register(grassBlock, "grass_block");
    }

    private static void register(Block block, String name)
    {
        GameRegistry.registerBlock(block.setRegistryName(name));
    }
}

有一点需要注意,从Minecraft的1.9及以上版本开始,除和物品一样,GameRegistry类中相应的方法名被修改为了register方法之外,方块对应的物品需要手动实例化一个ItemBlock去注册。关于ItemBlock的更多内容,请参阅3.2.1节。

现在不管是在服务端,还是在客户端,Forge都会在preInit阶段,运行到BlockLoader类的构造方法中的代码,实例化一个方块并注册它。

为这个方块对应的物品添加模型和材质

和物品一样,我们现在扩充一下BlockLoader类的代码:

src/main/java/com/github/ustc_zzzz/fmltutor/block/BlockLoader.java:

package com.github.ustc_zzzz.fmltutor.block;

import net.minecraft.block.Block;
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 BlockLoader
{
    public static Block grassBlock = new BlockGrassBlock();

    public BlockLoader(FMLPreInitializationEvent event)
    {
        register(grassBlock, "grass_block");
    }

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

    private static void register(Block block, String name)
    {
        GameRegistry.registerBlock(block.setRegistryName(name));
    }

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

由于注册的是方块对应的物品的模型和材质,所以就如上面的代码描述的一样,和物品唯一不一样的地方就是,我们通过Item类的静态方法getItemFromBlock获取方块对应的物品,其他的和物品相同。

接下来的事情也十分顺理成章,只不过这里有一些微小的变动。

我们这次先新建一个文件夹:src/main/resources/assets/fmltutor/models/block,并在其中新建一个文件:grass_block.json

src/main/resources/assets/fmltutor/models/block/grass_block.json:

{
    "parent": "block/cube_all",
    "textures": {
        "all": "fmltutor:blocks/grass_block"
    }
}

src/main/resources/assets/fmltutor/models/item里新建文件:grass_block.json

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

{
    "parent": "fmltutor:block/grass_block",
    "display": {
        "thirdperson": {
            "rotation": [ 10, -45, 170 ],
            "translation": [ 0, 1.5, -2.75 ],
            "scale": [ 0.375, 0.375, 0.375 ]
        }
    }
}

细心的读者可能发现,下面的文件中出现了一个名为parent的字段,表示的含义似乎是继承了上面的文件,本部分的稍后面我们会讲为何要这么做。

然后我们新建文件夹src/main/resources/assets/fmltutor/textures/blocks,在其中创建尺寸同样为16x16的图片文件grass_block.png(其实也仅仅是干草堆调了个色=_=||):

src/main/resources/assets/fmltutor/textures/blocks/grass_block.png:

grass_block

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();
        BlockLoader.registerRenders();
    }
}

现在在客户端,Forge就会在初始化Mod的时候,运行到BlockLoader类中的registerRenders方法中的代码,注册这个方块对应物品的渲染,而在服务端则不会运行。

现在运行游戏,并在其中运行命令:

/give @a fmltutor:grass_block

玩家的手上是不是多了一个新的方块呢~

为这个方块添加模型和材质

但是,当方块被放到地上的时候,我们会发现,方块并没有显示出应有的样子,而只是一个两种颜色交替的方块。这是因为刚刚我们仅仅注册了方块对应物品的模型和材质,而没有注册方块本身的模型和材质。

这里就多出来了一个问题,为什么Minecraft要分开注册方块和其对应物品的材质呢?

这是因为Minecraft往往一个方块有多种状态,如一个漏斗,就有漏斗的口向下、向北、向东、向南、向西五种状态,一个火焰甚至有三千多种状态,而这些状态,每个的模型都不一样。

当然,如何指定一个超过一个状态的方块、为一个方块指定多个物品、甚至不指定物品等,后面的部分会有讲到,这里我们不作探讨。

Minecraft会将方块的状态和模型之间的关系信息放在assets.minecraft.blockstates文件夹下,同样,Minecraft会自动寻找对应的存放方块状态的文件夹,比如这里就是assets.fmltutor.blockstates,也就是src/main/resources/assets/fmltutor/blockstates文件夹,如果没有特殊设置,再在这个文件夹下寻找文件名和<方块id>.json相同的文件。

我们新建这样一个文件夹,并在其中新建一个文件grass_block.json

src/main/resources/assets/fmltutor/blockstates/grass_block.json:

{
    "variants": {
        "normal": { "model": "fmltutor:grass_block" }
    }
}

这个文件告诉游戏,这个方块使用assets.fmltutor.models.block包下的一个名为grass_block.json的文件作为模型,这也是物品模型被拆分成两个文件的原因。

现在打开游戏,放在地上的方块,是不是成功地渲染了呢~

最后说一句,把所有物品相关的类使用Item开头,所有方块相关的类使用Block开头,等等,并把它们放到对应的包里,是一个好的习惯。

results matching ""

    No results matching ""