添加自定义作物
本教程将教会您如何添加像小麦和胡萝卜那样的作物。创建自定义的作物时,需要做以下这些事情:
- 自定义的种子物品
- 作物方块和种子物品的注册表
- 作物方块类
- 为你的作物设计的方块状态和模型
创建作物类
为创建自定义作物,我们需要先创建一个方块类。你需要用你的作物名称命名你的类,并且继承 CropBlock
。你还需要添加 AbstractBlock.Settings
并为作物创建形状。
public class CustomCropBlock extends CropBlock { public CustomCropBlock(AbstractBlock.Settings settings) { super(settings); } }
配置完成后,你需要定义你的种子物品并添加外观形状。每个 Block.createCubiodShape
都为作物生长的各个阶段定义了碰撞箱的大小。你可以根据自己的喜好进行配置,或者什么也不做,而是直接使用原版继承自 CropBlock
的,会直接使用和小麦一样的形状。
我们还没有添加种子物品,因此暂时先使用其他的。下面的代码,使用长方体形状、种子物品和外观形状应该是这样子:
public class CustomCropBlock extends CropBlock { private static final VoxelShape[] AGE_TO_SHAPE = new VoxelShape[]{Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 2.0D, 16.0D), Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 3.0D, 16.0D), Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 4.0D, 16.0D), Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 5.0D, 16.0D), Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 6.0D, 16.0D), Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 7.0D, 16.0D), Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 8.0D, 16.0D), Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 9.0D, 16.0D) }; public CustomCropBlock(AbstractBlock.Settings settings) { super(settings); } @Override protected ItemConvertible getSeedsItem() { return TutorialItems.CUSTOM_SEEDS; } @Override protected VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { return AGE_TO_SHAPE[getAge(state)]; } }
注册你的作物和种子物品
现在需要注册作物和用作种子的物品。种子模型和类(包括为方便而用的静态 static
方法)本页不作介绍,请参考 items 和 blocks 页面。需要注意的是,种子虽然是作物对应的方块物品,但是其名称不是直接使用作物的名称,而是有单独的名称,因此对于 1.21.2 之前的版本使用 AliasedBlockItem
而非 BlockItem
,对于 1.21.2 及之后的版本需要调用 useItemPrefixedTranslationKey()
。
- TutorialBlocks.java
- // 对于 1.21.2 之前的版本:
- public static final CropBlock CUSTOM_CROP = register("custom_crop", new CustomCropBlock(AbstractBlock.Settings.create().nonOpaque().noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)));
- // 对于 1.21.2 及之后的版本:
- public static final Block CUSTOM_CROP = register("custom_crop", CustomCropBlock::new, AbstractBlock.Settings.create().nonOpaque().noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP));
- TutorialItems.java
- // 对于 1.21.2 之前的版本:
- public static final Item CUSTOM_SEEDS = register("custom_seeds", new AliasedBlockItem(TutorialBlocks.CUSTOM_CROP, new Item.Settings()));
- // 对于 1.21.2 及之后的版本:
- public static final Item CUSTOM_SEEDS = register("custom_seeds", settings -> new BlockItem(TutorialBlocks.CUSTOM_CROP, settings), new Item.Settings().useItemPrefixedTranslationKey());
在添加方块教程中,我们写的register
方法默认会为每个方块创建一个对应的物品。因此这里会在创建的custom_seeds
的同时,还注册了名为custom_crop
的物品。如果不需要创建这个物品,可以像这样创建个不注册物品的registerBlockOnly
方法,或者给register
方法添加个参数以决定是否注册物品。
- TutorialBlocks.java
// ... public static final Block CUSTOM_CROP = registerBlockOnly("custom_crop", CustomCropBlock::new, AbstractBlock.Settings.create().nonOpaque().noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)); // ... private static Block registerBlockOnly(String path, Function<AbstractBlock.Settings, Block> factory, AbstractBlock.Settings settings) { final Identifier identifier = Identifier.of("tutorial", path); final RegistryKey<Block> registryKey = RegistryKey.of(RegistryKeys.BLOCK, identifier); return Blocks.register(registryKey, factory, settings); }
你很可能还需要 BlockRenderMapLayer
,这样你的作物才会显示为透明裁切的格式(参见 blockappearance)。在客户端初始化器中:
- TutorialModClient.class
- public class ExampleModClient implements ClientModInitializer {
- // ...
- @Override
- public void onInitializeClient() {
- // ...
- BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getCutout(), TutorialBlocks.CUSTOM_CROP);
- }
- }
创建方块状态和模型
我们已经完成了注册和代码,现在需要添加模型。下面的例子展示了使用 minecraft:block/crop
格式的简单生长阶段模型。你也可以使用 minecraft:block/cross
以使用交叉形的模型。您必须为拥有的每个生长阶段创建一个单独的模型。这个例子只呈现了单一的阶段,你可以将“0”替换成对应的生长阶段的数字。
- src/main/resources/assets/tutorial/models/block/custom_crop_stage0.json
{ "parent": "minecraft:block/crop", "textures": { "crop": "tutorial:block/custom_crop_stage0" } }
最后,您还需要为您的作物创建方块状态映射,以给作物的每个生长阶段都分配单独的模型。
- src/main/resources/assets/tutorial/blockstates/custom_crop.json
{ "variants": { "age=0": { "model": "tutorial:block/custom_crop_stage0" }, "age=1": { "model": "tutorial:block/custom_crop_stage0" }, "age=2": { "model": "tutorial:block/custom_crop_stage1" }, "age=3": { "model": "tutorial:block/custom_crop_stage1" }, "age=4": { "model": "tutorial:block/custom_crop_stage2" }, "age=5": { "model": "tutorial:block/custom_crop_stage2" }, "age=6": { "model": "tutorial:block/custom_crop_stage3" }, "age=7": { "model": "tutorial:block/custom_crop_stage3" } } }
种子物品也需要对应的物品模型和物品模型映射(对于 1.21.4 及之后的版本),具体做法参见 items,这里不作详细描述。
战利品表
方块还需要战利品表,否则被破坏后什么也不会掉落。不过,你可以直接模仿原版的。例如,复制原版的 data/minecraft/loot_table/blocks/wheat.json
到你模组的 src/main/resources/data/tutorial/loot_table/blocks/custom_crop.json
并替换相关的 ID。也可以使用数据生成器生成战利品表。
大功告成!
如果你正确完成了本教程的所有部分,那么你现在就应该有一个生效的作物了!这个作物可以用骨粉催熟,并且只能用种子物品放置在耕地上。