树 26.1 Fabric
本篇教程的视频
本篇教程的源代码
GitHub地址:
本篇教程目标
- 搞清「树是一种地物」,以及它由哪几块拼成
- 学会用
TreeConfiguration描述一棵树 - 学会用
TreeGrower让树苗长成树 - 学会把地物挂进 26.1 的数据生成
介绍
树整个结构在游戏里不是方块,而是一种地物(Feature)
除了树,还有矿脉、湖泊、随机斑块,都是地物
这期我们先来写一棵树,后面再来写树的世界生成
查看源代码
TreeFeatures
原版所有的树都在 TreeFeatures 这个类里,我们看橡树
1 | private static TreeConfiguration.TreeConfigurationBuilder createStraightBlobTree( |
这个 TreeConfigurationBuilder 有五个参数:
BlockStateProvider.simple(oakLog):树干用什么方块StraightTrunkPlacer(4, 2, 0):树干生成器,「笔直树干」;基础高度、随机高度 A、随机高度 B,最终高度是「基础 + 0 到 A + 0 到 B」这个范围里随机BlockStateProvider.simple(oakLeaves):树叶用什么方块BlobFoliagePlacer(ConstantInt.of(2), ConstantInt.of(0), 3):树叶生成器,「一团球」,三个参数是半径、偏移、从树顶往下第几层开始长TwoLayersFeatureSize(1, 0, 1):树的「尺寸」,管的是碰撞检测那套,一般照抄原版ignoreVines()是「不挂藤蔓」,我们的树没有藤蔓,加上也无所谓
注册
1 | FeatureUtils.register(context, OAK, Feature.TREE, createOak().build()); |
FeatureUtils.register 三件事:注册上下文、注册键、地物类型(Feature.TREE),最后是配置
TreeGrower
树苗长大靠这个类
1 | public static final TreeGrower OAK = new TreeGrower("oak", 0.1F, Optional.empty(), Optional.empty(), |
TreeGrower 有两个构造
四个参数的:名字、大型树、普通树、带花树,适合只有一种形态的树
带 0.1F 那个是六个以上参数的,多了一个概率,用来在几种形态之间随机
橡树有四种形态(普通、珍异、带蜂巢的),所以用长的那套
我们只有一种树,用四个参数的就行
26.1 的树叶类
打开 LeavesBlock 你会发现它现在是抽象类
1 | public abstract class LeavesBlock extends Block implements SimpleWaterloggedBlock { |
抽象的原因是「落叶粒子」有两个实现,得挑一个
TintedParticleLeavesBlock:随生物群系给树叶染色,原版橡树、白桦都是这个,贴图本身是灰的
UntintedParticleLeavesBlock:不染色,用你贴图本来的颜色,另外要指定掉什么粒子
我们的树叶贴图是自己画的固定颜色,不能再被染色,所以用后者
动手写
树叶
1 | public static final Block ICE_ETHER_LEAVES = register("ice_ether_leaves", |
三个参数:落叶粒子的概率、粒子类型、方块属性
概率给0.02F,粒子类型可以大家自己挑一个,不一定要用落叶的粒子,后面也可以自己去搓一个
属性抄橡木树叶,distance、persistent、waterlogged 这些状态就都有了
树的配置
新建 ModConfiguredFeatures
1 | public class ModConfiguredFeatures { |
这里的createKey是原版FeatureUtils.createKey直接copy过来的,当然要加上我们自己的命名空间
树本身
1 | private static TreeConfiguration.TreeConfigurationBuilder createIceEtherTree() { |
原木和树叶都换成我们自己的,其余照抄橡树
树叶半径给 3(橡树是 2),这样一棵树的叶子会大一圈,看着更厚实
TreeGrower
1 | public class ModTreeGrower { |
四个参数:名字(随便取,只是调试用)、大型树、普通树、带花树
我们只有「普通树」,所以第二个和第四个都是 Optional.empty()
树苗
1 | public static final Block ICE_ETHER_TREE_SAPLING = register("ice_ether_tree_sapling", |
SaplingBlock 两个参数:生成器、方块属性
属性抄橡木树苗,这样它会有 stage 状态,也会随机刻生长、也要摆在土上
记得加物品栏
1 | output.accept(ModBlocks.ICE_ETHER_TREE_SAPLING); |
数据生成
挂上动态注册表
ConfiguredFeature是数据包注册表,不是普通的游戏注册表
所以它走的同样是「动态注册」那条路,和我们之前做村民交易、唱片是一样的
首先我们要在 TutorialModDataGenerator 的 buildRegistry 里加一行
1 | registryBuilder.add(Registries.CONFIGURED_FEATURE, ModConfiguredFeatures::bootstrap); |
随后在 ModDynamicRegistryProvider 的 configure 里加一行
1 | entries.addAll(registries.lookupOrThrow(Registries.CONFIGURED_FEATURE)); |
这两步少一个,跑完数据生成,worldgen 目录就是空的
生成出来在
1 | data/tutorial/worldgen/configured_feature/ice_ether_tree.json |
里面能看到 type: minecraft:tree,树干、树叶分别指向我们的方块
模型
树叶
1 | blockModelGenerators.createTrivialBlock(ModBlocks.ICE_ETHER_LEAVES, TexturedModel.LEAVES); |
TexturedModel.LEAVES 对应的父模型是 minecraft:block/leaves,那个模型的面没有 cullface,所以从外面看不会有剔除问题
树苗
1 | blockModelGenerators.createCrossBlockWithDefaultItem(ModBlocks.ICE_ETHER_TREE_SAPLING, |
树苗是十字模型,用 createCrossBlockWithDefaultItem 一行搞定方块状态 + 方块模型 + 物品模型
PlantType 有三个值:TINTED(染色的,比如草)、NOT_TINTED(不染色)、EMISSIVE_NOT_TINTED(自发光)
战利品
树叶要改成「掉树苗」
1 | add(ModBlocks.ICE_ETHER_LEAVES, |
createLeavesDrops 会帮你写出「剪刀掉树叶、时运掉更多树苗」那一整套,NORMAL_LEAVES_SAPLING_CHANCES 是原版给的那组概率
树苗就直接掉自己
标签
1 | valueLookupBuilder(BlockTags.LEAVES) |
物品标签里也要加树苗
1 | valueLookupBuilder(ItemTags.SAPLINGS) |
树叶进 #leaves 之后,树叶才会被当成树叶(比如树叶的衰减、剪刀判定这些)
贴图
树叶放 textures/block/ice_ether_leaves.png
树苗也放 textures/block/ice_ether_tree_sapling.png
这里容易踩坑:树苗虽然是个「物品」,但贴图得放 block 下面
因为树的十字模型和物品模型,都是按 block/方块名 去找贴图的
放 item 目录里,方块世界里会变成紫黑,物品栏也许正常,看着特别迷惑
测试
跑完数据生成,进游戏进行测试
常见问题(大肥鱼总结版)
- 树叶是实心黑块:贴图透明度丢了,或者模型没用
TexturedModel.LEAVES - 树叶颜色不对、发灰:用了
TintedParticleLeavesBlock,它会被生物群系染色,换成UntintedParticleLeavesBlock - 树叶一直不掉:
distance和persistent状态没继承下来,属性抄错方块了 - 树苗放不下去:
SaplingBlock只能种在#dirt这类方块上,普通石头不行 - 用骨粉催没反应,或者树苗直接把骨粉吃了:
TreeGrower里的Optional给空了,或者注册键拼错 - 数据生成后
worldgen目录是空的:buildRegistry或DataDynamicRegistryProvider里少写了一步 - 游戏启动报找不到
ice_ether_tree:configure里没addAll(CONFIGURED_FEATURE),数据没写进 jar - 树长出来是原版的橡树:
BlockStateProvider.simple里传的还是Blocks.OAK_LOG - 树苗是紫黑方块:贴图放到了
textures/item/下面,应该放textures/block/ - 树苗模型是歪的/只有一半:
PlantType用了TINTED,换成NOT_TINTED







