本篇教程的视频
(待发布)
本篇教程的源代码
本篇教程目标
- 理解原版各类木头相关方块注册
- 学会编写原木、木头,以及绑定与它们各自对应的削皮原木、削皮木头
查看源代码
后面的教程我们将讲到树
,以及它们的世界生成
不过,在有树之前,得先有各种木头,和往常一样,我们来看看源代码
方块注册
我们到Blocks类中找到LOG
、WOOD
相关的内容,这里我们就以橡木
为例
1 2 3 4 5 6 7 8 9 10 11 12 13
| public static final Block OAK_LOG = register("oak_log", createLogBlock(MapColor.OAK_TAN, MapColor.SPRUCE_BROWN));
public static final Block STRIPPED_OAK_LOG = register("stripped_oak_log", createLogBlock(MapColor.OAK_TAN, MapColor.OAK_TAN));
public static final Block OAK_WOOD = register( "oak_wood", new PillarBlock(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).instrument(Instrument.BASS).strength(2.0F).sounds(BlockSoundGroup.WOOD).burnable()) );
public static final Block STRIPPED_DARK_OAK_WOOD = register( "stripped_dark_oak_wood", new PillarBlock(AbstractBlock.Settings.create().mapColor(MapColor.BROWN).instrument(Instrument.BASS).strength(2.0F).sounds(BlockSoundGroup.WOOD).burnable()) );
|
原木的注册虽然是有一个createLogBlock
方法,但实际上它也是实例化PillarBlock
的
1 2 3 4 5 6 7 8 9 10
| public static PillarBlock createLogBlock(MapColor topMapColor, MapColor sideMapColor) { return new PillarBlock( AbstractBlock.Settings.create() .mapColor(state -> state.get(PillarBlock.AXIS) == Direction.Axis.Y ? topMapColor : sideMapColor) .instrument(Instrument.BASS) .strength(2.0F) .sounds(BlockSoundGroup.WOOD) .burnable() ); }
|
可以看到,原木的注册方法与木头类似,只不过原木的材质颜色是会根据方向来改变的
因为原木它的侧面
和它的年轮面
(顶面和底面)并不是一样的,所以显示在地图上的颜色会不一样
而木头的话就没有这个特性,所以mapColor()
方法中直接返回一个颜色即可
其他的方块设置我们也基本上见过了,burnable()
方法就是让这个方块可以燃烧,当然具体的燃烧速度、几率我们后面再说,它们由其他类定义
另外我们也顺便看看木板
和树叶
的注册,我们在这期教程中也一起加入了,后面就直接讲树了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public static final Block OAK_PLANKS = register( "oak_planks", new Block(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).instrument(Instrument.BASS).strength(2.0F, 3.0F).sounds(BlockSoundGroup.WOOD).burnable()) );
public static final Block OAK_LEAVES = register("oak_leaves", createLeavesBlock(BlockSoundGroup.GRASS));
public static LeavesBlock createLeavesBlock(BlockSoundGroup soundGroup) { return new LeavesBlock( AbstractBlock.Settings.create() .mapColor(MapColor.DARK_GREEN) .strength(0.2F) .ticksRandomly() .sounds(soundGroup) .nonOpaque() .allowsSpawning(Blocks::canSpawnOnLeaves) .suffocates(Blocks::never) .blockVision(Blocks::never) .burnable() .pistonBehavior(PistonBehavior.DESTROY) .solidBlock(Blocks::never) ); }
|
木板简单,实例化普通的方块
而树叶也有一个方法来注册,实例化LeavesBlock
,我们也可以来看看它的一些方块设置
ticksRandomly()
方法就是让树叶有随机刻
,因为要检测这个树叶能否存在,当我们砍完树之后,树上的树叶会一点点消失
nonOpaque()
方法指定方块是非实心的,因为树叶是有透明通道
的
allowsSpawning()
方法指定方块上能否生成生物,这里指定的是能够生成在树叶上的生物
suffocates()
和blockVision()
方法指定方块是否阻挡生物的视线和移动,这里指定的是不阻挡
pistonBehavior()
方法指定方块在活塞推动时的行为,这里指定的是破坏方块
solidBlock()
方法指定方块是否是实心的,这里指定的是不是实心的
当然我们后面也可以来研究研究树叶方块的具体实现
燃烧属性
上面我们也都看到了burnable()
方法,这个方法就是让方块可以燃烧,但没有涉及燃烧速度和几率
这里我们就得到FireBlock
中找到相关内容了
不过先说一下,FireBlock
其实是火焰方块,也就是打火石生成出来的火,在这个方块类中定义了方块燃烧的属性
1 2 3 4 5 6 7 8 9 10 11 12
| public static void registerDefaultFlammables() { FireBlock fireBlock = (FireBlock)Blocks.FIRE; fireBlock.registerFlammableBlock(Blocks.OAK_PLANKS, 5, 20); fireBlock.registerFlammableBlock(Blocks.OAK_SLAB, 5, 20); fireBlock.registerFlammableBlock(Blocks.OAK_FENCE_GATE, 5, 20); ... fireBlock.registerFlammableBlock(Blocks.OAK_LOG, 5, 5); fireBlock.registerFlammableBlock(Blocks.STRIPPED_OAK_LOG, 5, 5); fireBlock.registerFlammableBlock(Blocks.OAK_WOOD, 5, 5); fireBlock.registerFlammableBlock(Blocks.OAK_LEAVES, 30, 60); ... }
|
我们可以在这个类中找到一个registerDefaultFlammables
方法,在这其中就定义了可以燃烧的方块它们的燃烧属性
registerFlammableBlock
方法就是注册一个方块的燃烧属性,它接受三个参数,第一个参数是方块
,第二个参数是几率
(有火源在边上时,自身着火的概率),第三个参数是燃烧传播几率
(引燃其他可燃方块的概率)
相当而言,原木
类的几率会小一点,原木加工后的产物
,比如木板、台阶这种,传播概率会高一点,而树叶要比它们更加易燃,概率更高
另外也说一下,要作为燃料还是要写Tag
的,原版熔炉中定义的燃料是用Tag
指定的
去皮与不去皮对应关系
原木与去皮原木的话,如果你留意过的话,就能在AxeItem
中发现它们
1 2 3 4 5
| protected static final Map<Block, Block> STRIPPED_BLOCKS = new Builder<Block, Block>() .put(Blocks.OAK_WOOD, Blocks.STRIPPED_OAK_WOOD) .put(Blocks.OAK_LOG, Blocks.STRIPPED_OAK_LOG) ... .build();
|
在AxeItem
中有一个Map
,里面定义了原木与去皮原木的对应关系,我们可以通过Mixin
来注入我们自己的木头,不过Fabric也提供给我们了API
注册
注册方块
这里我们就来注册我们自己的各种木头
1 2 3 4 5 6 7 8
| public static final Block ICE_ETHER_LOG = register("ice_ether_log", new PillarBlock(AbstractBlock.Settings.copy(Blocks.OAK_LOG))); public static final Block ICE_ETHER_WOOD = register("ice_ether_wood", new PillarBlock(AbstractBlock.Settings.copy(Blocks.OAK_LOG))); public static final Block STRIPPED_ICE_ETHER_LOG = register("stripped_ice_ether_log", new PillarBlock(AbstractBlock.Settings.copy(Blocks.OAK_LOG))); public static final Block STRIPPED_ICE_ETHER_WOOD = register("stripped_ice_ether_wood", new PillarBlock(AbstractBlock.Settings.copy(Blocks.OAK_LOG)));
|
这里我们就注册了原木
、木头
、去皮原木
和去皮木头
,方便起见,我们就直接用原版对应木头的设置了
它们都是实例化PillarBlock
,也就是柱体方块,不过注意一下,我们之前的教程也搞了个柱类方块,不要和之前那个搞混了
另外顺便把木板和树叶也注册了
1 2 3 4
| public static final Block ICE_ETHER_LEAVES = register("ice_ether_leaves", new LeavesBlock(AbstractBlock.Settings.copy(Blocks.OAK_LEAVES))); public static final Block ICE_ETHER_PLANKS = register("ice_ether_planks", new Block(AbstractBlock.Settings.copy(Blocks.OAK_PLANKS)));
|
同样也是复制了原版方块的属性
注册去皮对应内容
前面我们在AxeItem
中看到的内容,我们也得写一下,不然用斧头右键方块时不会转化
前面我也说了,可以用Mixin
,也可以用Fabric
提供的API
来写,这里我们采用后者
到模组主类的初始化方法中写上
1 2
| StrippableBlockRegistry.register(ModBlocks.ICE_ETHER_LOG, ModBlocks.STRIPPED_ICE_ETHER_LOG); StrippableBlockRegistry.register(ModBlocks.ICE_ETHER_WOOD, ModBlocks.STRIPPED_ICE_ETHER_WOOD);
|
StrippableBlockRegistry.register方法就是注册原木与去皮原木的对应关系
它接受两个参数,第一个参数是原木
,第二个参数是去皮原木
原木和木头都是这样操作
不过,除了去皮原木这种,其他用斧头右键方块会转化的,也可以用这个方法来写
注册燃烧属性
同样,我们也在主类中来注册这些方块的燃烧属性
1 2 3 4 5 6
| FlammableBlockRegistry.getDefaultInstance().add(ModBlocks.ICE_ETHER_LOG, 5, 5); FlammableBlockRegistry.getDefaultInstance().add(ModBlocks.ICE_ETHER_WOOD, 5, 5); FlammableBlockRegistry.getDefaultInstance().add(ModBlocks.STRIPPED_ICE_ETHER_LOG, 5, 5); FlammableBlockRegistry.getDefaultInstance().add(ModBlocks.STRIPPED_ICE_ETHER_WOOD, 5, 5); FlammableBlockRegistry.getDefaultInstance().add(ModBlocks.ICE_ETHER_LEAVES, 30, 60); FlammableBlockRegistry.getDefaultInstance().add(ModBlocks.ICE_ETHER_PLANKS, 5, 20);
|
同样,我们也是用Fabric
的API
来写
FlammableBlockRegistry.getDefaultInstance().add
方法就是注册一个方块的燃烧属性
它接受三个参数,和FireBlock
中registerFlammableBlock
方法一样,第一个参数是方块,第二个参数是几率,第三个参数是燃烧传播几率
加入物品栏
最后,我们还要把我们的方块加入物品栏,不然我们看不到它们
1 2 3 4 5 6
| entries.add(ModBlocks.ICE_ETHER_LOG); entries.add(ModBlocks.ICE_ETHER_WOOD); entries.add(ModBlocks.STRIPPED_ICE_ETHER_LOG); entries.add(ModBlocks.STRIPPED_ICE_ETHER_WOOD); entries.add(ModBlocks.ICE_ETHER_LEAVES); entries.add(ModBlocks.ICE_ETHER_PLANKS);
|
数据文件
常规的,我们还是用数据生成来生成数据文件
语言文件
1 2 3 4 5 6
| translationBuilder.add(ModBlocks.ICE_ETHER_LOG, "Ice Ether Log"); translationBuilder.add(ModBlocks.ICE_ETHER_WOOD, "Ice Ether Wood"); translationBuilder.add(ModBlocks.STRIPPED_ICE_ETHER_LOG, "Stripped Ice Ether Log"); translationBuilder.add(ModBlocks.STRIPPED_ICE_ETHER_WOOD, "Stripped Ice Ether Wood"); translationBuilder.add(ModBlocks.ICE_ETHER_PLANKS, "Ice Ether Planks"); translationBuilder.add(ModBlocks.ICE_ETHER_LEAVES, "Ice Ether Leaves");
|
Tag
方块
1 2 3 4 5
| getOrCreateTagBuilder(BlockTags.LOGS_THAT_BURN) .add(ModBlocks.ICE_ETHER_LOG) .add(ModBlocks.ICE_ETHER_WOOD) .add(ModBlocks.STRIPPED_ICE_ETHER_LOG) .add(ModBlocks.STRIPPED_ICE_ETHER_WOOD);
|
物品
1 2 3 4 5 6 7 8 9 10 11 12
| getOrCreateTagBuilder(ItemTags.PLANKS) .add(ModBlocks.ICE_ETHER_PLANKS.asItem()); getOrCreateTagBuilder(ItemTags.LOGS) .add(ModBlocks.ICE_ETHER_LOG.asItem()) .add(ModBlocks.STRIPPED_ICE_ETHER_LOG.asItem()) .add(ModBlocks.ICE_ETHER_WOOD.asItem()) .add(ModBlocks.STRIPPED_ICE_ETHER_WOOD.asItem()); getOrCreateTagBuilder(ItemTags.LOGS_THAT_BURN) .add(ModBlocks.ICE_ETHER_LOG.asItem()) .add(ModBlocks.STRIPPED_ICE_ETHER_LOG.asItem()) .add(ModBlocks.ICE_ETHER_WOOD.asItem()) .add(ModBlocks.STRIPPED_ICE_ETHER_WOOD.asItem());
|
主要还是物品
的标签,方块的加到LOGS_THAT_BURN
标签中即可
木板加到物品标签中的PLANKS
标签中,用于合成木棍之类的
另外标签是加入到燃料中
模型文件
1 2 3 4
| blockStateModelGenerator.registerLog(ModBlocks.ICE_ETHER_LOG).log(ModBlocks.ICE_ETHER_LOG).wood(ModBlocks.ICE_ETHER_WOOD); blockStateModelGenerator.registerLog(ModBlocks.STRIPPED_ICE_ETHER_LOG).log(ModBlocks.STRIPPED_ICE_ETHER_LOG).wood(ModBlocks.STRIPPED_ICE_ETHER_WOOD); blockStateModelGenerator.registerSimpleCubeAll(ModBlocks.ICE_ETHER_PLANKS); blockStateModelGenerator.registerSimpleCubeAll(ModBlocks.ICE_ETHER_LEAVES);
|
原木和木头的特殊一点,用registerLog
来注册它们,然后用log
和wood
方法分别传入原木和木头
木板和树叶就很简单了,用registerSimpleCubeAll
方法来注册,它们是六面相同的
测试
那么跑完数据生成之后,放好材质文件,注意原木的材质文件分为顶(底)面和侧面,有两个
然后就可以去游戏里测试了