本篇教程的视频

本篇教程的源代码

GitHub地址:

本篇教程目标

  • 学会用 FlowerBlock 做一朵花,包括它的谜之炖菜效果
  • 学会用 FlowerPotBlock 做盆栽
  • 知道 26.1 的盆栽为什么不用再手动登记
  • 学会用数据生成一次性写出花 + 盆栽的全部模型

介绍

这一期做小植物:一格大小的花,以及它的盆栽

像玫瑰丛那种两格高的高花,这期先不讲,等你熟悉了一格的花,高花就是把两个方块拼起来而已

花和盆栽的关系

花是一个方块,单独长在地上

盆栽(花盆)是另一个方块,它的「内容」嵌在模型里,看起来是一盆花

所以严格来说,盆栽不是「花放在花盆上」,而是一个独立的方块,长得像花盆里插了朵花

这两者之间有一张映射表:给游戏一个「花」,游戏得知道它对应的「盆栽」是哪个方块

查看源代码

蒲公英

原版的花都是 FlowerBlock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static final Block DANDELION = register(
"dandelion",
new FlowerBlock(
MobEffects.SATURATION,
0.35F,
BlockBehaviour.Properties.of()
.mapColor(MapColor.PLANT)
.noCollission()
.instabreak()
.sound(SoundType.GRASS)
.offsetType(BlockBehaviour.OffsetType.XZ)
.pushReaction(PushReaction.DESTROY)
)
);

FlowerBlock 要两个额外参数:效果、持续秒数

这个效果不会直接给你,它是用来做谜之炖菜的

你拿花去合成谜之炖菜,吃下去就会获得这朵花带的效果,蒲公英给的是饱和

第二个参数是秒数,原版花基本都在 0.35F 上下

属性里有一项值得单独说:offsetType(BlockBehaviour.OffsetType.XZ)

花很小,如果每朵都插在方块正中央,一片花海看起来会特别死板

offsetType 就是让它随机偏一点,XZ 是水平方向随机,Y 是竖直方向随机(比如草丛)

花盆

1
2
3
4
5
public FlowerPotBlock(final Block potted, final BlockBehaviour.Properties properties) {
super(properties);
this.potted = potted;
POTTED_BY_CONTENT.put(potted, this);
}

26.1 的花盆只要把「盆里装什么」传进去就行

注意构造函数最后那句 POTTED_BY_CONTENT.put(potted, this)

它就是在填那张映射表,所以不需要你再去主类里手动登记(前面的教程)

动手写

花

1
2
3
public static final Block SIMPLE_FLOWER = register("simple_flower",
p -> new FlowerBlock(MobEffects.NIGHT_VISION, 4.0F, p),
BlockBehaviour.Properties.ofFullCopy(Blocks.DANDELION), true);

效果我给的是夜视,持续 4 秒

属性直接抄蒲公英,noCollission、instabreak、offsetType 这些全都有了,比一个个写省事

盆栽

1
2
3
public static final Block POTTED_SIMPLE_FLOWER = register("potted_simple_flower",
p -> new FlowerPotBlock(SIMPLE_FLOWER, p),
BlockBehaviour.Properties.ofFullCopy(Blocks.POTTED_DANDELION), false);

注意最后一个参数是 false

盆栽方块没有对应的方块物品,你手里拿不到它,只能通过花盆放花得到

物品栏

只有花需要进物品栏

1
output.accept(ModBlocks.SIMPLE_FLOWER);

贴图

只要一张:textures/block/simple_flower.png

盆栽不用单独的画,它的模型是「花盆 + 花的贴图」拼出来的

数据生成

模型

1
2
blockModelGenerators.createPlantWithDefaultItem(ModBlocks.SIMPLE_FLOWER, ModBlocks.POTTED_SIMPLE_FLOWER,
BlockModelGenerators.PlantType.NOT_TINTED);

PlantType 选 NOT_TINTED:花不需要被生物群系染色

不要盆栽怎么写

有时候花只是个装饰,不想要花盆版(比如你打算做两格高的花丛)

那就别注册 POTTED_XXX,模型换成这个

1
2
blockModelGenerators.createCrossBlockWithDefaultItem(ModBlocks.SIMPLE_FLOWER,
BlockModelGenerators.PlantType.NOT_TINTED);

和树苗那行一模一样

它只写花的十字模型(连方块状态一起)和物品模型,不碰盆栽

所以两个方法的分工是

  • createCrossBlockWithDefaultItem(花, 类型):只要花
  • createPlantWithDefaultItem(花, 盆栽, 类型):花加盆栽

少了盆栽,数据生成里还有三处要跟着简化

战利品只留 dropSelf,把 dropPottedContents 去掉

语言只写花那一行

贴图也只放花那一张,盆栽的模型是拿花的贴图当 plant 槽用的,没有花盆就没人读它

战利品

花的很简单,掉自己

1
dropSelf(ModBlocks.SIMPLE_FLOWER);

盆栽要特殊处理

1
dropPottedContents(ModBlocks.POTTED_SIMPLE_FLOWER);

这个方法是原版给的现成方法,它会写出「掉一个空花盆 + 掉一朵花」

标签

1
2
valueLookupBuilder(BlockTags.SMALL_FLOWERS)
.add(ModBlocks.SIMPLE_FLOWER);

物品标签也来一份

1
2
valueLookupBuilder(ItemTags.SMALL_FLOWERS)
.add(ModBlocks.SIMPLE_FLOWER.asItem());

进 #small_flowers 之后,蜜蜂会来采蜜,一些配方的判定也认这个标签

语言

1
2
translationBuilder.add(ModBlocks.SIMPLE_FLOWER, "Simple Flower");
translationBuilder.add(ModBlocks.POTTED_SIMPLE_FLOWER, "Potted Simple Flower");

中文

1
2
translationBuilder.add(ModBlocks.SIMPLE_FLOWER, "简易花");
translationBuilder.add(ModBlocks.POTTED_SIMPLE_FLOWER, "简易花盆栽");

测试

跑完数据生成,进游戏进行测试

常见问题(大肥鱼总结版)

  • 盆栽放不进去花:FlowerPotBlock 的第一个参数传错,或者花是在盆栽之后注册的(必须先有花)
  • 打掉盆栽变成白送花:战利品用了 dropSelf,要换成 dropPottedContents
  • 盆栽在物品栏里能拿出来:注册时最后一个参数给了 true,盆栽不该有方块物品
  • 花是紫黑方块:贴图路径不对,应该在 textures/block/ 下,名字和方块注册名一致
  • 花颜色发灰:PlantType 用了 TINTED,花不会染色,应该用 NOT_TINTED
  • 盆栽模型是空的:没写 potted_xxx 的模型,或者 createPlantWithDefaultItem 的第二个参数写成了花自己
  • 花全都长得一样整齐:属性里没有 offsetType(XZ),抄原版属性的时候漏了
  • 谜之炖菜没有效果:FlowerBlock 的第一个参数传的不是 Holder<MobEffect>,或者改完后没重新进游戏
  • 蜜蜂不来:#small_flowers 标签没加