本篇教程的视频

本篇教程的源代码

GitHub地址:

相关源代码

前面我们看熔炉类的时候,已经看见过一个名为LIT的方块属性

1
public static final BooleanProperty LIT = BlockStateProperties.LIT;

这个属性是布尔属性,也就是只有truefalse两种状态,我们只需要在方块类中添加这个属性,就可以让方块发光了

我们在查看其他光源方块的时候,可能你找不到LIT这个东西,但会在它们注册的时候看到一个lightLevel的方法

1
2
3
4
5
6
7
8
9
public static final Block TORCH = register("torch", new TorchBlock(
BlockBehaviour.Properties.of()
.noCollission()
.instabreak()
.lightLevel((p_50755_) -> {
return 14;
})
.sound(SoundType.WOOD)
.pushReaction(PushReaction.DESTROY), ParticleTypes.FLAME));

这个方法用于设置方块的发光级别,比如这里的TORCH火把,它的发光属性就是14,当然最高的是15

1
2
3
4
5
6
static final Block REDSTONE_LAMP = register("redstone_lamp", 
new RedstoneLampBlock(BlockBehaviour.Properties.of()
.lightLevel(litBlockEmission(15))
.strength(0.3F)
.sound(SoundType.GLASS)
.isValidSpawn(Blocks::always)));

另外还有像红石灯,它是有开关两个状态的,litBlockEmission方法是根据LIT属性来判断给方块哪个给光照等级

1
2
3
4
5
private static ToIntFunction<BlockState> litBlockEmission(int pLightValue) {
return (p_50763_) -> {
return p_50763_.getValue(BlockStateProperties.LIT) ? pLightValue : 0;
};
}

根据这个方法,当LIT属性为true时,发光级别为litLevel(对应上面写的就是15),否则为0

添加属性

现在我们来新建一个方块,来实现发光的效果

常规发光方块

新建LampBlock,继承自Block

1
2
3
4
5
public class LampBlock extends Block {
public LampBlock(Properties pProperties) {
super(pProperties);
}
}

随后我们引入LIT这个属性

1
public static final BooleanProperty LIT = BlockStateProperties.LIT;

在构造方法中我们要初始化这个属性

1
2
3
4
public LampBlock(Properties pProperties) {
super(pProperties);
this.registerDefaultState(this.defaultBlockState().setValue(LIT, true));
}

那么默认我们让这个方块发光,设置为true

另外不要忘记添加属性

1
2
3
4
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> pBuilder) {
pBuilder.add(LIT);
}

构造函数的pProperties我们可以接着写lightLevel,构造函数的pProperties和方块注册中的是一样的

1
super(pProperties.lightLevel(state -> 15));

那么常规的发光方块就是这样编写,后面就直接去注册方块就好了

开关发光方块

那么要再现实一点,实现开关灯的效果,我们在lightLevel中写的就要改一下了

1
super(pProperties.lightLevel(state -> state.getValue(LIT) ? 15 : 0));

用上三元运算符,当LIT属性为true时,发光级别为15,否则为0

另外,我们也得重写方法,让方块能在LIT的两个属性之间切换

这里我们要重写use,当玩家右键方块时,会调用这个方法

1
2
3
4
5
6
7
8
9
10
11
@Override
public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, BlockHitResult pHit) {
if (!pLevel.isClientSide()) {
if (pState.getValue(LIT)) {
pLevel.setBlock(pPos, pState.setValue(LIT, false), 3);
} else {
pLevel.setBlock(pPos, pState.setValue(LIT, true), 3);
}
}
return InteractionResult.SUCCESS;
}

逻辑其实很简单,右键一下就改一下LIT的值,然后调用setBlock方法,将方块状态设置为新的状态

配合上面的lightLevel方法,就能实现开关灯的效果了

方块注册

注册

1
2
3
public static final RegistryObject<Block> LAMP_BLOCK =
registerBlocks("lamp_block",
() -> new LampBlock(BlockBehaviour.Properties.of().strength(2.0f, 2.0f).noOcclusion()));

实例化LampBlock

物品栏

添加到物品栏

1
pOutput.accept(ModBlocks.LAMP_BLOCK.get());

数据文件

战利品列表

1
dropSelf(ModBlocks.LAMP_BLOCK.get());

语言文件

1
add(ModBlocks.LAMP_BLOCK.get(), "Lamp");

模型文件

这里我们没有为方块加入别的属性,所以就直接写最简单的方块状态文件即可

1
simpleBlockWithoutBlockModel(ModBlocks.LAMP_BLOCK);

哎,可能就要有人问了,这不是有个LIT吗?为什么不写在方块状态中?

这个时候,你就得知道一件事,写在方块状态文件中的属性,是会引起方块发生改变的

比如我们之前写的FACING,方块旋转了吧?

对于这里的LIT,除了发光之外,方块的模型是否有变化?当然没有吧

除非你的方块发光前和发光后的形态不一样,那么就得把LIT写入方块状态中

至于方块的模型文件,我们还是拿Blockbench制作的

测试

那么最后我们就可以进入游戏进行测试了