本篇教程的视频

本篇教程的源代码

GitHub地址:TutorialMod-Light-1.20.1

本篇教程目标

  • 为方块添加LIT属性,让方块发光
  • 写一些方法实现开关灯

查看源代码

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

1
public static final BooleanProperty LIT = Properties.LIT;

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

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

1
2
3
4
5
6
7
public static final Block TORCH = register(
"torch",
new TorchBlock(
AbstractBlock.Settings.create().noCollision().breakInstantly().luminance(state -> 14).sounds(BlockSoundGroup.WOOD).pistonBehavior(PistonBehavior.DESTROY),
ParticleTypes.FLAME
)
);

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

1
2
3
4
5
6
public static final Block REDSTONE_LAMP = register(
"redstone_lamp",
new RedstoneLampBlock(
AbstractBlock.Settings.create().luminance(createLightLevelFromLitBlockState(15)).strength(0.3F).sounds(BlockSoundGroup.GLASS).allowsSpawning(Blocks::always)
)
);

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

1
2
3
public static ToIntFunction<BlockState> createLightLevelFromLitBlockState(int litLevel) {
return state -> state.get(Properties.LIT) ? litLevel : 0;
}

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

添加属性

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

常规发光方块

新建LampBlock,继承自Block

1
2
3
4
5
6
public class LampBlock extends Block {

public LampBlock(Settings settings) {
super(settings);
}
}

随后我们引入LIT这个属性

1
public static final BooleanProperty LIT = Properties.LIT;

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

1
this.setDefaultState(this.getStateManager().getDefaultState().with(LIT, true));

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

另外不要忘记添加属性

1
2
3
4
@Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
builder.add(LIT);
}

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

1
super(settings.luminance(state -> 15));

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

开关发光方块

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

1
super(settings.luminance(state -> state.get(LIT) ? 15 : 0));

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

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

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

1
2
3
4
5
6
7
8
9
10
11
@Override
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
if (!world.isClient()) {
if (state.get(LIT)) {
world.setBlockState(pos, state.with(LIT, false));
} else {
world.setBlockState(pos, state.with(LIT, true));
}
}
return ActionResult.SUCCESS;
}

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

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

方块注册

注册

1
2
public static final Block LAMP_BLOCK = register("lamp_block",
new LampBlock(AbstractBlock.Settings.create().strength(2.0f, 6.0f).nonOpaque()));

实例化LampBlock,因为我们在前面的settings中写了luminance方法吗,这里就不用写了

物品栏

添加到物品栏

1
entries.add(ModBlocks.LAMP_BLOCK);

数据文件

语言文件

1
translationBuilder.add(ModBlocks.LAMP_BLOCK, "Lamp Block");

模型文件

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

1
blockStateModelGenerator.registerSimpleState(ModBlocks.LAMP_BLOCK);

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

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

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

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

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

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

测试

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