2.1 创建方块
Part A. 实战
定义一个方块很简单,和 Item
非常类似:
先定义指定方块类,并设置基本属性:
// 继承于 net.minecraft.block.Block 类
public class ObsidianBlock extends Block {
public ObsidianBlock() {
// 从材质创建 AbstractBlock.Properties (不是之前的 Item.Properties),并且定义硬度
super(Properties.create(Material.ROCK).hardnessAndResistance(5));
}
}
注意到与创建 Item
不同的是,Block
类需要指定创建的材质。
我们可以从之前的理论分析中发现,指定材质是为了让某些
ToolItem
效果选中,例如AxeItem
作用于所有EFFECTIVE_ON_MATERIAL
材质的方块。这只是其中之一的原因,具体还有很多其他用途,遇到再作分析。Minecraft 中有许多内置的 material,你可以在
net.minecraft.block.material.Material
中看到。
和 Item
一样,接下来需要注册定义的类:
public class BlockRegistry {
public static final DeferredRegister<Block> blockDeferredRegister = DeferredRegister.create(ForgeRegistries.BLOCKS, Utils.MOD_ID);
public static final RegistryObject<Block> obsidianBlock = blockDeferredRegister.register("obsidian_block", ObsidianBlock::new);
}
别忘了,我们换了一个 DeferredRegister
,我们还需要将新的 register 注册到 Mod 总线中:
BlockRegistry.blockDeferredRegister.register(FMLJavaModLoadingContext.get().getModEventBus());
结束了吗?很可惜,还差一步。
我们知道,Minecraft 的 block 是真实出现在场景中的对象,而 item 是可以被玩家手持 / 装备 / 存放的对象,二者渲染的位置不一样。
我们现在只是定义了 ObsidianBlock
作为一个 Block 对象的信息,它还不能出现在物品栏 / 创造模式物品组,因为它没有以 item 形式存在的信息。
现在,我们需要为 block 类型定义一个 item 的呈现方式,也就是 把 block 类型同样注册到 ItemRegistry
中,并且关联 “放置 item 成为 block” 的效果。
public static final RegistryObject<Item> obsidianBlock = itemDeferredRegister.register(
"obsidian_block",
() -> new BlockItem(
BlockRegistry.obsidianBlock.get(),
// 这里本人新建了一个 ItemGroup
new Item.Properties().group(ModGroup.OBSIDIAN_BLOCK_GROUP)
)
);
这里我们直接使用内置类 BlockItem
从注册好的 Block 对象生成 Item 对象,并且把这个新对象注册到 item 的 register 中。
如此一来,方块就基本创建完毕了,现在还剩下方块的材质信息没有加入,我们在后面叙述。
Part B. 理论:Block
& Material
& LootTable
2.1.B.1 Block
& AbstractBlock
先来关注一下 Block
构造函数:

传入 block 并构造的属性还可以通过检查 AbstractBlock.Properties
类型,以及父类 AbstractBlock
得到:

我们能看到,通过定制构造 Block 的 Abstract.Properties
,至少可以指定:
- 方块材料(
material
); - 爆炸抗性(
resistance
,距爆炸中心点多远会被破坏的数值表征); - 方块是否需要随机 tick 来进行粒子效果渲染(
ticksRandomly
); - 速度限制(
speedFactor
,表征实体在方块上表面行走时的移速限制情况,默认1.0F
):例如灵魂沙可以降低玩家移速; - 光滑程度(
slipperiness
,表征实体在方块上表面行走时移动速度的维持情况,默认0.6F
):例如冰面可以在玩家停止行进时,维持更长时间保持前进速度; - 跳跃系数(
jumpFactor
,表征实体在方块上反弹的高度比例,默认1.0F
):例如玩家可以在史莱姆方块上弹跳; - 收获等级(
harvestLevel
,方块被破坏后,绝不会被收获等级低于这个等级的Item
生成掉落物,默认-1
); - 指定收获工具(
harvestTool
,规定只有指定类型的ToolItem
,并且高于harvestLevel
的工具破坏该方块后才会形成掉落物,否则即便收获等级高于限制也不会形成掉落物); - 战利品表(
lootTable
); - 发光强度(
lightLevel
)、方块音效(soundType
); - ……
现在,我们看到两个比较有趣的参数:方块材料(material
)和战利品表(lootTable
),我们一一了解。
2.1.B.2 Material
方块材料是 AbstractBlock
(父类)代为构建的,它和 AbstractBlock / Block
中的其他属性一样,共同描述了一个方块类的特性。其构造函数如下:

一个方块材料主要描述了方块的颜色、是否为流体(流体涉及的渲染和运动逻辑在后面介绍)、是否可以着火、被活塞等实体推动后的行为,等等。
Material
构造参数很多,使用 Builder
模式进行构建。如果需要自行定义一个 Material
类型,可以模仿 Material
类中已经定义好的常量。我们在定义方块时就可以传入自定义的 Material
进行使用了。
正如之前所说,Material
还有一个重要的作用就是让 ToolItem
识别一类材质的方块并作用上去。例如,前面提到的 AxeItem
对一类材质的方块破坏速度更快:

这里细心的同学可能注意到,识别一个方块的 material 使用的是 BlockState
,而不是 Block
本身,这是为什么?我们留个悬念,下一节介绍 BlockState
的时候再继续讨论。
2.1.B.3 LootTable
战利品表
我们知道敲碎一个方块 / 击败一个 mob
后可能会产生掉落物(drop),例如收获等级高于石镐的 PickaxeItem
类型的工具在破坏钻石矿(diamond ore
)后会直接掉落钻石,空手撸掉草方块后会掉落一个泥土方块,击败一个 zombie 可能会掉落一个胡萝卜,钓鱼钓出经验修补附魔书、要塞里的奖励箱的内容,等等。
注:官方定义
mob
An AI-driven game entity resembling a living creature,short for mobile entity;
游戏中的所有看起来有生命的、由 AI 驱动的实体都是
mob
,是 mobile entity 的简称。而游戏的 entity 则是指一切能移动的对象,包含其他非 entity 所没有的属性,例如:
- 位置、旋转角、速度;
- 未转动情况下三维容积长方体的几何尺寸(或称碰撞箱尺寸);
- 是否着火(表现为在 entity 周围渲染 flame);
- 是否存在效果状态(
Effects
);
这些生成掉落物 / 奖励箱内容的一切行为,全部被 lootTable
所定义。
注:像是史莱姆分裂、蠹虫从虫蚀方块(infested block)中出现的逻辑都不属于战利品表的范畴。
战利品表实际上是标准的 JSON 文件,定义了一个 Item
什么时候以掉落物的方式出现。战利品表的一些特性如下:
- 生存模式下不可破坏方块(基岩、末地传送门方块等)没有战利品表;
- 一些方块共享一份战利品表,例如墙类、地板类;
- 目前某些情况下掉落的策略在战利品表中不存在,有几种特殊情况:
- 凋零掉落下界之心的逻辑不在战利品表的管理范围内;
- 这是一个 bug:MC-94610(击杀充能 creeper 掉落生物头颅不被战利品表管理。而掉落唱片的问题已经在 18w43a 被修复);
我们开发 mod 既可以修改已存在的方块的战利品表来改变掉落逻辑,也可以新增一些方块并且为它们创建战利品表。
那么如何创建战利品表呢?详细内容请参见 Chapter EX-2;