方块状态是附加到 Minecraft 世界中的单个方块上的一段数据,包含属性形式的方块块信息——原版存储在方块状态中的属性的一些示例:
- Rotation:主要用于原木方块和其他自然方块中。
- Activated:主要用于红石装置方块和类似于熔炉、烟熏炉的方块中。
- Age:用于农作物、植物、树苗、海带等方块中。
你可能会明白为什么方块状态有用——它们避免了在方块实体中存储 NBT 数据的需要——这既减小了世界大小,也防止产生 TPS 问题!
方块状态的定义能在 assets/example-mod/blockstates 文件夹中找到。
示例:柱方块
Minecraft 已经有些自定义的类,允许你快速创建特定类型的方块——这个例子会通过创建“Condensed Oak Log”方块来带你创建带有 axis 属性的方块。
原版的 RotatedPillarBlock 允许方块按 X、Y 或 Z 轴放置。
java
public static final Block CONDENSED_OAK_LOG = register(
"condensed_oak_log",
RotatedPillarBlock::new,
BlockBehaviour.Properties.of().sound(SoundType.WOOD),
true
);1
2
3
4
5
6
7
2
3
4
5
6
7
柱方块有两个纹理,顶部(top)和侧面(side),使用 block/cube_column 模型。
同样,纹理文件可以在 assets/example-mod/textures/block 中找到
由于柱方块有两个位置,水平和垂直,我们需要创建两个单独的模型文件:
condensed_oak_log_horizontal.json,继承block/cube_column_horizontal模型。condensed_oak_log.json,继承block/cube_column模型。
condensed_oak_log_horizontal.json 文件的示例:
json
{
"parent": "minecraft:block/cube_column_horizontal",
"textures": {
"end": "example-mod:block/condensed_oak_log_top",
"side": "example-mod:block/condensed_oak_log"
}
}1
2
3
4
5
6
7
2
3
4
5
6
7
INFO
请记住,方块状态文件可以在 assets/example-mod/blockstates 中找到,方块状态文件的名称应当匹配你在 ModBlocks 类中注册的方块的 ID。 例如,如果方块 ID 为 condensed_oak_log,这个文件就应当叫做 condensed_oak_log.json。
如需更加深入了解方块状态文件中可用的所有修饰符,可查看中文 Minecraft Wiki - 教程:制作资源包/模型(方块状态)页面。
接下来,我们需要创建一个方块状态文件,这正是见证奇迹的地方。 柱型方块有三个轴,因此我们将针对以下情况使用特定模型:
axis=x- 方块沿 X 轴放置时,旋转模型以朝向正 X 方向。axis=y- 方块沿 Y 轴旋转时,使用正常的垂直模型。axis=z- 方块沿 Z 轴放置时,旋转模型以朝向正 Z 方向。
json
{
"variants": {
"axis=x": {
"model": "example-mod:block/condensed_oak_log_horizontal",
"x": 90,
"y": 90
},
"axis=y": {
"model": "example-mod:block/condensed_oak_log"
},
"axis=z": {
"model": "example-mod:block/condensed_oak_log_horizontal",
"x": 90
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
同样,你需要为该方块创建本地化条目,并创建一个物品模型,将其父模型指定为前述两种模型之一。

自定义方块状态
如果你的方块有独特的属性,那么自定义方块状态会非常不错——有时你会发现你的方块可以复用原版的属性。
这个例子会创建一个叫做 activated 的独特属性——玩家右键单击方块时,方块会由 activated=false 变成 activated=true 并相应改变纹理。
创建属性
首先,需要创建属性本身——因为是个布尔值,所以使用 BooleanProperty.create 方法。
java
public class PrismarineLampBlock extends Block {
public static final BooleanProperty ACTIVATED = BooleanProperty.create("activated");
}1
2
3
4
2
3
4
接下来,需要在 createBlockStateDefinition 方法中将该属性添加到方块状态管理器。 需要重写此方法以访问构建器:
java
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(ACTIVATED);
}1
2
3
4
5
2
3
4
5
你还需要在你的自定义方块的构造函数中,设置 activated 属性的默认状态。
java
public PrismarineLampBlock(Properties settings) {
super(settings);
// Set the default state of the block to be deactivated.
registerDefaultState(defaultBlockState().setValue(ACTIVATED, false));
}1
2
3
4
5
6
7
2
3
4
5
6
7
使用属性
这个例子会在玩家与方块交互时,翻转 activated 属性的布尔值。 我们可以重写 useWithoutItem 方法来实现:
java
@Override
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
if (!player.getAbilities().mayBuild) {
// Skip if the player isn't allowed to modify the level.
return InteractionResult.PASS;
} else {
// Get the current value of the "activated" property
boolean activated = state.getValue(ACTIVATED);
// Flip the value of activated and save the new blockstate.
level.setBlockAndUpdate(pos, state.setValue(ACTIVATED, !activated));
// Play a click sound to emphasise the interaction.
level.playSound(player, pos, SoundEvents.COMPARATOR_CLICK, SoundSource.BLOCKS, 1.0F, 1.0F);
return InteractionResult.SUCCESS;
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
视觉呈现属性
创建方块状态前,我们需要为方块的激活的和未激活的状态都提供纹理,以及方块模型。
利用你对方块模型的了解,为该方块创建两个模型:一个用于激活状态,另一个用于未激活状态。 完成后,就可以开始创建方块状态文件了。
既然创建了新的属性,就需要更新该方块的方块状态文件以适配这个属性。
如果方块有多个属性,那么会需要包含所有可能的组合。 例如,activated 和 axis 可能就会导致 6 个组合(activated 有两个可能的值,axis 有三个可能的值)。
由于该方块只有一个属性(activated),因此仅有两种可能的变体,其方块状态 JSON 应如下所示:
json
{
"variants": {
"activated=false": {
"model": "example-mod:block/prismarine_lamp"
},
"activated=true": {
"model": "example-mod:block/prismarine_lamp_on"
}
}
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
TIP
不要忘记为方块添加客户端物品,以便它在物品栏中显示!
由于这个示例方块是灯,我们还需要让它在 activated 属性为 true 时发光。 此操作可通过在注册方块时传递给构造函数的方块设置来实现。
可以使用 lightLevel 方法设置方块发出的光照等级,我们可以在 PrismarineLampBlock 类中创建一个静态方法,根据 activated 属性返回光照等级,并将其作为方法引用传递给 lightLevel 方法:
java
public static int getLuminance(BlockState currentBlockState) {
// Get the value of the "activated" property.
boolean activated = currentBlockState.getValue(PrismarineLampBlock.ACTIVATED);
// Return a light level if activated = true
return activated ? 15 : 0;
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
java
public static final Block PRISMARINE_LAMP = register(
"prismarine_lamp",
PrismarineLampBlock::new,
BlockBehaviour.Properties.of()
.sound(SoundType.LANTERN)
.lightLevel(PrismarineLampBlock::getLuminance),
true
);1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
完成所有步骤后,最终结果应大致如下所示:



