制作一个方块一共分几步
制作一个方块一共只比物品多一步:
- 创建一个方块
- 实例化并注册这个方块
- 为这个方块对应的物品添加模型和材质
- 为这个方块添加模型和材质
我们发现雪可以合成雪块,那么,草可不可以合成草块呢= =本次教程将带领你一步一步地做出一个草块。
创建一个方块
创建一个方块的过程,和创建一个物品的过程非常相似。
这里我们如法炮制,新建一个包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:
对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开头,等等,并把它们放到对应的包里,是一个好的习惯。