本篇教程的视频

本篇教程的源代码

GitHub地址:

自定义方块类

后面的教程我们将讲到,以及它们的世界生成

不过,在有树之前,得先有各种木头,所以这里我们先来注册各种木头

但是嘞,话又说回来了,我们还得先写一些自定义的方块类

ModRotatedPillarBlock

我们先创建这个类,它是继承自RotatedPillarBlock

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

这个类会在注册原木和木头时调用

接下来我们重写一些方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public boolean isFlammable(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return true;
}

@Override
public int getFlammability(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return 5;
}

@Override
public int getFireSpreadSpeed(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return 5;
}

这是定义我们方块的燃烧相关的属性的

  • isFlammable:是否可燃
  • getFlammability:获取易燃性
  • getFireSpreadSpeed:获取燃烧传播速度

因为原版相关的燃烧属性被硬编码在了FireBlock里面,我们自己添加的方块是没有这些属性的,不过IForge提供了额外的拓展方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void bootStrap() {
FireBlock fireblock = (FireBlock)Blocks.FIRE;

fireblock.setFlammable(Blocks.OAK_PLANKS, 5, 20);
...
fireblock.setFlammable(Blocks.OAK_LOG, 5, 5);
...
fireblock.setFlammable(Blocks.STRIPPED_OAK_LOG, 5, 5);
...
fireblock.setFlammable(Blocks.OAK_WOOD, 5, 5);
...
fireblock.setFlammable(Blocks.OAK_LEAVES, 30, 60);
...
}

当然,原版这里的方法顺序是传播速度易燃性

另外我们还需要重写一个getToolModifiedState方法

1
2
3
4
5
6
7
8
9
10
11
@Override
public @Nullable BlockState getToolModifiedState(BlockState state, UseOnContext context, ToolAction toolAction, boolean simulate) {
if (context.getItemInHand().getItem() instanceof AxeItem) {
if (state.is(ModBlocks.ICE_ETHER_LOG.get())) {
return ModBlocks.STRIPPED_ICE_ETHER_LOG.get().defaultBlockState().setValue(AXIS, state.getValue(AXIS));
} else if (state.is(ModBlocks.ICE_ETHER_WOOD.get())) {
return ModBlocks.STRIPPED_ICE_ETHER_WOOD.get().defaultBlockState().setValue(AXIS, state.getValue(AXIS));
}
}
return super.getToolModifiedState(state, context, toolAction, simulate);
}

这个方法是当我们使用斧头右键没被削皮的原木或者木头时,执行并返回相应的去皮原木或者木头

因为原版的映射也是被硬编码在了AxeItem类里面

当然,这里的方块我们还没写

ModPlankBlock

同样的,我们来创建一个木板方块类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ModPlankBlock extends Block {
public ModPlankBlock(Properties pProperties) {
super(pProperties);
}

@Override
public boolean isFlammable(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return true;
}

@Override
public int getFlammability(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return 20;
}

@Override
public int getFireSpreadSpeed(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return 5;
}
}

ModLeavesBlock

以及一个树叶方块类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ModLeavesBlock extends LeavesBlock {
public ModLeavesBlock(Properties pProperties) {
super(pProperties);
}

@Override
public boolean isFlammable(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return true;
}

@Override
public int getFlammability(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return 60;
}

@Override
public int getFireSpreadSpeed(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return 30;
}
}

注册方块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static final RegistryObject<Block> ICE_ETHER_LOG = registerBlocks("ice_ether_log",
() -> new ModRotatedPillarBlock(BlockBehaviour.Properties.copy(Blocks.OAK_LOG)));

public static final RegistryObject<Block> ICE_ETHER_WOOD = registerBlocks("ice_ether_wood",
() -> new ModRotatedPillarBlock(BlockBehaviour.Properties.copy(Blocks.OAK_LOG)));

public static final RegistryObject<Block> STRIPPED_ICE_ETHER_LOG = registerBlocks("stripped_ice_ether_log",
() -> new ModRotatedPillarBlock(BlockBehaviour.Properties.copy(Blocks.OAK_LOG)));

public static final RegistryObject<Block> STRIPPED_ICE_ETHER_WOOD = registerBlocks("stripped_ice_ether_wood",
() -> new ModRotatedPillarBlock(BlockBehaviour.Properties.copy(Blocks.OAK_LOG)));

public static final RegistryObject<Block> ICE_ETHER_LEAVES = registerBlocks("ice_ether_leaves",
() -> new ModLeavesBlock(BlockBehaviour.Properties.copy(Blocks.OAK_LEAVES)));

public static final RegistryObject<Block> ICE_ETHER_PLANKS = registerBlocks("ice_ether_planks",
() -> new ModPlankBlock(BlockBehaviour.Properties.copy(Blocks.OAK_PLANKS)));

原木和木头以及它们各自对应的去皮状态,都是实例化RotatedPillarBlock,里面的内容倒是差不多

树叶我们也一并注册了,实例化LeavesBlock

木板简单,实例化普通的方块

记得将这些方块加到物品栏里面去

1
2
3
4
5
6
pOutput.accept(ModBlocks.ICE_ETHER_LOG.get());
pOutput.accept(ModBlocks.ICE_ETHER_WOOD.get());
pOutput.accept(ModBlocks.STRIPPED_ICE_ETHER_LOG.get());
pOutput.accept(ModBlocks.STRIPPED_ICE_ETHER_WOOD.get());
pOutput.accept(ModBlocks.ICE_ETHER_LEAVES.get());
pOutput.accept(ModBlocks.ICE_ETHER_PLANKS.get());

数据文件

常规的,我们还是用数据生成来生成数据文件

战利品列表

1
2
3
4
5
6
dropSelf(ModBlocks.ICE_ETHER_LOG.get());
dropSelf(ModBlocks.STRIPPED_ICE_ETHER_LOG.get());
dropSelf(ModBlocks.ICE_ETHER_WOOD.get());
dropSelf(ModBlocks.STRIPPED_ICE_ETHER_WOOD.get());
dropSelf(ModBlocks.ICE_ETHER_LEAVES.get());
dropSelf(ModBlocks.ICE_ETHER_PLANKS.get());

树叶的我们暂时先这么写着,后面有了树苗我们再修改

语言文件

1
2
3
4
5
6
add(ModBlocks.ICE_ETHER_LOG.get(), "Ice Ether Log");
add(ModBlocks.ICE_ETHER_WOOD.get(), "Ice Ether Wood");
add(ModBlocks.STRIPPED_ICE_ETHER_LOG.get(), "Stripped Ice Ether Log");
add(ModBlocks.STRIPPED_ICE_ETHER_WOOD.get(), "Stripped Ice Ether Wood");
add(ModBlocks.ICE_ETHER_PLANKS.get(), "Ice Ether Planks");
add(ModBlocks.ICE_ETHER_LEAVES.get(), "Ice Ether Leaves");

Tag

方块

1
2
3
4
5
6
7
8
9
tag(BlockTags.LOGS_THAT_BURN)
.add(ModBlocks.ICE_ETHER_LOG.get())
.add(ModBlocks.ICE_ETHER_WOOD.get())
.add(ModBlocks.STRIPPED_ICE_ETHER_LOG.get())
.add(ModBlocks.STRIPPED_ICE_ETHER_WOOD.get());
tag(BlockTags.LEAVES)
.add(ModBlocks.ICE_ETHER_LEAVES.get());
tag(BlockTags.PLANKS)
.add(ModBlocks.ICE_ETHER_PLANKS.get());

物品

1
2
3
4
5
6
7
8
9
10
11
12
tag(ItemTags.PLANKS)
.add(ModBlocks.ICE_ETHER_PLANKS.get().asItem());
tag(ItemTags.LOGS)
.add(ModBlocks.ICE_ETHER_LOG.get().asItem())
.add(ModBlocks.STRIPPED_ICE_ETHER_LOG.get().asItem())
.add(ModBlocks.ICE_ETHER_WOOD.get().asItem())
.add(ModBlocks.STRIPPED_ICE_ETHER_WOOD.get().asItem());
tag(ItemTags.LOGS_THAT_BURN)
.add(ModBlocks.ICE_ETHER_LOG.get().asItem())
.add(ModBlocks.STRIPPED_ICE_ETHER_LOG.get().asItem())
.add(ModBlocks.ICE_ETHER_WOOD.get().asItem())
.add(ModBlocks.STRIPPED_ICE_ETHER_WOOD.get().asItem());

模型文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
logBlock(((RotatedPillarBlock) ModBlocks.ICE_ETHER_LOG.get()));
axisBlock(((RotatedPillarBlock) ModBlocks.ICE_ETHER_WOOD.get()), blockTexture(ModBlocks.ICE_ETHER_LOG.get()), blockTexture(ModBlocks.ICE_ETHER_LOG.get()));
axisBlock((RotatedPillarBlock) ModBlocks.STRIPPED_ICE_ETHER_LOG.get(), ResourceLocation.fromNamespaceAndPath(TutorialMod.MOD_ID, "block/stripped_ice_ether_log"),
ResourceLocation.fromNamespaceAndPath(TutorialMod.MOD_ID, "block/stripped_ice_ether_log_top"));
axisBlock((RotatedPillarBlock) ModBlocks.STRIPPED_ICE_ETHER_WOOD.get(), ResourceLocation.fromNamespaceAndPath(TutorialMod.MOD_ID, "block/stripped_ice_ether_log"),
ResourceLocation.fromNamespaceAndPath(TutorialMod.MOD_ID, "block/stripped_ice_ether_log"));

blockItem(ModBlocks.ICE_ETHER_LOG);
blockItem(ModBlocks.ICE_ETHER_WOOD);
blockItem(ModBlocks.STRIPPED_ICE_ETHER_LOG);
blockItem(ModBlocks.STRIPPED_ICE_ETHER_WOOD);

simpleBlockWithItem(ModBlocks.ICE_ETHER_PLANKS.get(), cubeAll(ModBlocks.ICE_ETHER_PLANKS.get()));
simpleBlockWithItem(ModBlocks.ICE_ETHER_LEAVES.get(),
models().cubeAll("ice_ether_leaves", modLoc("block/ice_ether_leaves")).renderType("cutout"));

稍微有些复杂,不过也还行

测试

那么跑完数据生成之后,放好材质文件,注意原木的材质文件分为顶(底)面和侧面,有两个

然后就可以去游戏里测试了