我的世界1.20.1模组开发---9.添加作物

发布时间 2023-11-22 17:32:59作者: 小明同学404

介绍

  这次我们来添加以下作物,类似于马铃薯、小麦之类的农作物,当我们种下种子后就会慢慢生长,当长到成熟阶段后,破坏农作物我们可以获取到对应的种子和果实。这次我们来添加一个玉米作物,大致流程就是种下玉米种子后等待一定时间后就会成熟,我们破坏掉成熟的作物后,就会掉落玉米和玉米种子。玉米的状态和原版的小麦是一样的,所以我们这次就根据原版的小麦的写法来创建玉米。我们可以进到Items类(这个类里面放了所有原版的物品,我们开发中可以参考里面的物品的写法)中搜索WHEAT关键字,就能看到小麦是如何实现的了。

  由于作物涉及到多个物品,所以我们总共需要注册两个item(玉米种子、玉米果实)和一个block(玉米作物方块),这个方块就是我们把种子种到耕地后,能在耕地看到这个作物方块只是它不是一整个方块大小,总之我们添加玉米作物就要注册这三个东西,缺一不可。

  这次注册种子物品时和以前不一样的是,我们这次不能直接new一个Item类,要new一个ItemNameBlockItem类。注册玉米果实时,直接new一个Item类就行,但是因为玉米果实是可以直接吃的,我们需要设置属性时添加是food属性来设置食物的各种参数。另外在注册玉米作物方块时也和平常的方块注册有所不同,这里的不同后面再具体描述。

  下面是注册玉米的种子和果实的代码,要注意和其他的物品注册不同。

//添加玉米种子(注意这里要new一个ItemNameBlockItem类)
    public static final RegistryObject<Item>CORN_SEED=ITEMS.register("corn_seed",
            ()->new ItemNameBlockItem(ModBlocks.CORN_CROP.get(),new Item.Properties()));

    //添加玉米果实
    public static final RegistryObject<Item>CORN=ITEMS.register("corn",
            ()->new Item(new Item.Properties()
                    .food(new FoodProperties.Builder()//为这个物品添加食物属性
                            .nutrition(2)//营养值
                            .saturationMod(2F)//饱食度
                            //吃完后的效果,给玩家添加了一个再生效果,依次为 玩家获得的效果、持续时间(20=1s)、等级(从0开始),触发概率
                            .effect(new MobEffectInstance(MobEffects.REGENERATION, 400, 1), 1.0F).build())));

  我们还需要新建一个CornCrop类用来创建我们的玉米作物方块,这个类需要继承CropBlock类,这是原版的作物方块类,小麦作物方块就是用这个类创建的,但是因为我们想设置一些和原版不一样的地方,所以需要继承这个类并重写下面的这些方法来实现。

public class CornCrop extends CropBlock {
    public static final IntegerProperty AGE=IntegerProperty.create("age",0,6);
    public CornCrop(Properties pProperties) {
        super(pProperties);
    }

    @Override
    protected IntegerProperty getAgeProperty() {
        return AGE;
    }

    @Override
    public int getMaxAge() {
        return 6;
    }

    @Override
    protected ItemLike getBaseSeedId() {
        return ModItems.CORN_SEED.get();
    }

    @Override
    protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> pBuilder) {
        pBuilder.add(AGE);
    }
}

  我们需要创建一个IntegerProperty类型的变量来表示玉米作物的生长周期,上述代码中说明了玉米作物的最小阶段为0,最大阶段为6,也就是有7个阶段。因为每一个阶段的样子都不一样,所以我们也就需要七张不同的贴图来显示不同时期的作物方块。创建好这个类之后,直接在ModBlocksnew这个类注册一个作物方块即可。

  另外,因为作物方块属于一个多状态的方块,再使用方块模型生成器生成json文件时也和其他的方块有所不同。

        //添加作物方块
        this.registerCropBlockModel(ModBlocks.CORN_CROP.get());
        


        //注册作物方块
        public void registerCropBlockModel(Block block){
            //获取最大生成阶段
            int maxAge= CropBlock.MAX_AGE;
            //因为这是一个多状态方块,要用这个构造器类为每个阶段创建一个不同的模型
            VariantBlockStateBuilder builder =getVariantBuilder(block);
            //变量每个阶段,为每个阶段创建一个模型
            for(int i=0;i<maxAge;i++){
                //注意,是CornCrop.AGE,而不是CornBlock.AGE,这里传入的AGE必须是我们定义的才行
                builder.partialState().with(CornCrop.AGE,i).modelForState()//这句是在i阶段创建了一个基础模型
                      .modelFile(models().crop(name(block).split("_")[0]+"_stage"+i,
                                               cropTextureSuffix(block,"_stage"+i)).renderType("cutout"))//对模型进行设置
                        .addModel();//完成模型配置
            }
        }
        
    public ResourceLocation cropTextureSuffix(Block block,String suffix){
        ResourceLocation name=key(block);
        return new ResourceLocation(name.getNamespace(),ModelProvider.BLOCK_FOLDER+"/"+name.getPath().split("_")[0]+suffix);
    }


    public ResourceLocation key(Block block){
        return ForgeRegistries.BLOCKS.getKey(block);
    }

    public String name(Block block){
        return key(block).getPath();
    }

代码

  首先我们需要在ModItems类里注册我们的种子和果实。

    //添加玉米种子
    public static final RegistryObject<Item>CORN_SEED=ITEMS.register("corn_seed",
            ()->new ItemNameBlockItem(ModBlocks.CORN_CROP.get(),new Item.Properties()));

    //添加玉米果实
    public static final RegistryObject<Item>CORN=ITEMS.register("corn",
            ()->new Item(new Item.Properties()
                    .food(new FoodProperties.Builder()//为这个物品添加食物属性
                            .nutrition(2)//营养值
                            .saturationMod(2F)//饱食度
                            //吃完后的效果,给玩家添加了一个效果,依次为 玩家获得的效果、持续时间(20=1s)、等级(从0开始),触发概率
                            .effect(new MobEffectInstance(MobEffects.REGENERATION, 400, 1), 1.0F).build())));

  然后需要在block/custom目录下创建一个CornCrop类表示我们的作物方块,这个类要继承CropBlock类,并重写下面的这些方法。

public class CornCrop extends CropBlock {
    //创建一个作物生长阶段的属性,参数依次为 名称  最小阶段  最大阶段
    public static final IntegerProperty AGE=IntegerProperty.create("age",0,6);
    public CornCrop(Properties pProperties) {
        super(pProperties);
    }

    @Override
    protected IntegerProperty getAgeProperty() {
        return AGE;
    }
    //这里需要返回我们的最大阶段
    @Override
    public int getMaxAge() {
        return 6;
    }

    @Override
    protected ItemLike getBaseSeedId() {
        return ModItems.CORN_SEED.get();
    }
    
    //把我们的阶段属性添加到构造器
    @Override
    protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> pBuilder) {
        pBuilder.add(AGE);
    }
}

  然后再到ModBlocks类注册玉米作物方块,因为是参考原版的小麦来的,属性直接复制原版的小麦即可。

    //注册玉米作物方块
    public static  final RegistryObject<Block>CORN_CROP=BLOCKS.register("corn_crop",
            ()->new CornCrop(BlockBehaviour.Properties.copy(Blocks.WHEAT)));

  接着就需要到ModItemModelGen类中设置玉米种子和玉米果实的模型json文件。

        itemGenerateModel(ModItems.CORN.get(),resourceItem(itemName(ModItems.CORN.get())));
        itemGenerateModel(ModItems.CORN_SEED.get(),resourceItem(itemName(ModItems.CORN_SEED.get())));

  然后去ModBlockModelGen类设置作物方块的模型json文件。 

//添加作物方块
        this.registerCropBlockModel(ModBlocks.CORN_CROP.get());


    //注册作物方块
    public void registerCropBlockModel(Block block){
        int maxAge= CropBlock.MAX_AGE;
        VariantBlockStateBuilder builder =getVariantBuilder(block);
        for(int i=0;i<maxAge;i++){
            //注意,是CornCrop.AGE,而不是CornBlock.AGE,这里传入的AGE必须是我们定义的才行
            builder.partialState().with(CornCrop.AGE,i).modelForState()
                  .modelFile(models().crop(name(block).split("_")[0]+"_stage"+i,
                          cropTextureSuffix(block,"_stage"+i)).renderType("cutout"))
                    .addModel();
        }
    }


    public ResourceLocation cropTextureSuffix(Block block,String suffix){
        ResourceLocation name=key(block);
        return new ResourceLocation(name.getNamespace(),ModelProvider.BLOCK_FOLDER+"/"+name.getPath().split("_")[0]+suffix);
    }


    public ResourceLocation key(Block block){
        return ForgeRegistries.BLOCKS.getKey(block);
    }

    public String name(Block block){
        return key(block).getPath();
    }

  因为破坏成熟的作物会掉落种子和果实,所以还需要在ModLootTableGen类里面设置一下作物方块的掉落物,这里可以直接参考原版小麦的写法,修改一些参数即可。

        add(ModBlocks.CORN_CROP.get(),(block)->{
            //                           掉落的果实,        掉落的种子 ,              这个参数复制原版的改一下参数就行
            return createCropDrops(block,ModItems.CORN.get(),ModItems.CORN_SEED.get(),lootitemcondition$builder1);
        });
        //从原版复制过来,修改一下参数即可                                                                              这里改成我们的作物方块|||                       这里填写我们作物的AGE属性,以及可收获果实的阶段(一般都是最大阶段)|||
        LootItemCondition.Builder lootitemcondition$builder1 = LootItemBlockStatePropertyCondition.hasBlockStateProperties(ModBlocks.CORN_CROP.get()).setProperties(StatePropertiesPredicate.Builder.properties().hasProperty(CropBlock.AGE, 6));

  最后在ModLangGen类里面生成一些种子和果实的语言文件即可。

        add(ModItems.CORN.get(),"Corn");
        add(ModItems.CORN_SEED.get(),"Corn Seed");

  最后把贴图放到对应位置即可。