MC Forge 1.20.1 项目 开发 (2)方块和物品 接下来为方便讲解我将基于我自己正在开发的一个项目来进行讲解。本项目有些内容需要一定java基础例如方块里批量注册炸弹运用了数组不要忘记将模组主类的名称和里面的modid等修改一下保持跟gradle.properties里的modid相同新建两个包block和item在block中创建类BlockReg.javapackage craftedegg.rbw.block; import java.util.ArrayList; import java.util.List; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockBehaviour.Properties; import net.minecraft.world.level.material.MapColor; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegistryObject; public class BlockReg { //定义炸弹的注册名这些是我瞎取的 public static final String[] BOMB_NAMES new String[]{mini, division, h37, c29, b23, a77, a34, m86, k8v, m63, p22, jk4}; public static final int[] BOMB_RANGES new int[]{9, 13, 18, 25, 33, 40, 48, 54, 64, 68, 72, 75};//这些是炸弹的爆炸范围 public static ListRegistryObjectBlock bombs new ArrayList(); public static final DeferredRegisterBlock BLOCKS DeferredRegister.create(ForgeRegistries.BLOCKS, rbw); public static final RegistryObjectBlock BOMB_BENCH BLOCKS.register(bombbench, () - { return new BombBench(Properties.of()); });; public static void registerBombBlocks() { int ele 0; String[] var1 BOMB_NAMES; int var2 var1.length; //用for循环遍历直接批量注册 for(int var3 0; var3 var2; var3) { String name var1[var3]; int finalEle ele; RegistryObjectBlock bomb BLOCKS.register(name, () - { return new ModBomb(Properties.of().mapColor(MapColor.STONE), (float)BOMB_RANGES[finalEle]); }); bombs.add(bomb); ele; } } }再新建一个BombBench.java这个方块是以后给卖炸弹的村民用的。package craftedegg.rbw.block; import net.minecraft.world.level.block.Block; public class BombBench extends Block { public BombBench(Properties p_49795_) { //简单写个构造方法 //以后我也许会加入复杂的逻辑例如允许玩家打开GUI来制造炸弹 super(p_49795_); } }新建ModBomb.java它是我们的主角炸弹方块。package craftedegg.rbw.block; import craftedegg.rbw.entity.BombEntity; import craftedegg.rbw.entity.EntityReg; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Explosion; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.TntBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockBehaviour.Properties; import net.minecraft.world.level.gameevent.GameEvent; import org.jetbrains.annotations.Nullable; public class ModBomb extends TntBlock { public float range 10.0F; public ModBomb(Properties p_57422_, float range) { super(p_57422_); this.range range; } public void onCaughtFire(BlockState state, Level world, BlockPos pos, Nullable Direction face, Nullable LivingEntity igniter) { this.explode(world, pos, igniter); } public void explode(Level p_57437_, BlockPos p_57438_, javax.annotation.Nullable LivingEntity p_57439_) { if (!p_57437_.isClientSide) {//实体只应该在服务端创建所以判断一下 BombEntity primedtnt new BombEntity((EntityType)EntityReg.BOMB_ENTITY.get(), p_57437_);//炸弹实体将会在下一章讲解 primedtnt.setRange(this.range); primedtnt.setPos((double)p_57438_.getX(), (double)p_57438_.getY(), (double)p_57438_.getZ()); p_57437_.addFreshEntity(primedtnt); p_57437_.playSound((Player)null, primedtnt.getX(), primedtnt.getY(), primedtnt.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0F, 1.0F); p_57437_.gameEvent(p_57439_, GameEvent.PRIME_FUSE, p_57438_);//这里直接照搬TNT的逻辑 } } Override public void wasExploded(Level p_57441_, BlockPos p_57442_, Explosion p_57443_) { if (!p_57441_.isClientSide) { BombEntity primedtnt new BombEntity((EntityType)EntityReg.BOMB_ENTITY.get(), p_57441_); primedtnt.setFuse(0); primedtnt.setPos((double)p_57442_.getX(), primedtnt.getY(), primedtnt.getZ()); p_57441_.addFreshEntity(primedtnt); } } Override public void neighborChanged(BlockState p_57457_, Level p_57458_, BlockPos p_57459_, Block p_57460_, BlockPos p_57461_, boolean p_57462_) { if (p_57458_.hasNeighborSignal(p_57459_)) { this.explode(p_57458_, p_57459_, (LivingEntity)null); } } }炸弹实体BombEntity将会在下一章讲解。所以你的代码暂时还不能直接编译...接下来在item包里新建ItemReg.javapackage craftedegg.rbw.item; import craftedegg.rbw.block.BlockReg; import craftedegg.rbw.item.ammo.AmmoItem; import craftedegg.rbw.item.attachment.AttachmentEnum; import craftedegg.rbw.item.attachment.AttachmentItem; import craftedegg.rbw.item.gun.GunItem; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import craftedegg.rbw.util.Tools; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.Item.Properties; import net.minecraft.world.level.block.Block; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegistryObject; public class ItemReg { public static ListRegistryObjectItem rbwItems new ArrayList(); public static final DeferredRegisterItem ITEMSDeferredRegister.create(ForgeRegistries.ITEMS, rbw); public static final RegistryObjectItem GUARANTEE ITEMS.register(guarantee, () - new Guarantee(new Properties().stacksTo(1))); public static final RegistryObjectItem BOMB_BENCH_ITEM ITEMS.register(bombbench, () - new BlockItem(BlockReg.BOMB_BENCH.get(), new Properties())); public static void registerBombBlockItems() { int ele 0; for(Iterator var1 BlockReg.bombs.iterator(); var1.hasNext(); ele) { RegistryObjectBlock bomb (RegistryObject)var1.next(); int finalEle ele; RegistryObjectItem bomb_item ITEMS.register(BlockReg.BOMB_NAMES[ele], () - (new BombBlockItem((Block)bomb.get(), new Properties())).setRange((float)BlockReg.BOMB_RANGES[finalEle])); rbwItems.add(bomb_item); } } }在这里为我们的炸弹方块注册对应物品说起来Item类默认要传入的Item.Properties其实非常有用。支持链式调用给物品设置属性。其常用方法如下stacksTo:需传入一个整数代表物品堆叠上限默认64rarity需传入一个Rarity类的实例它是一个枚举类代表物品的稀有程度这会反映在物品的名称颜色上补充Rarity类似乎还支持用create方法自定义一个稀有程度然后可以用ChatFormmatting枚举类来指定颜色感兴趣者可自行查阅原版代码food指定该物品为食物Forge之前提供的默认物品应该使用了这个方法durability指定耐久度就像原版的那些工具一样。需传入一个int作为初始最大耐久然后每次使用都会扣1。开启后强制堆叠数为1defaultDurability指定物品刚被创建时扣多少耐久必须跟durability搭配否则无效例如僵尸掉的武器就会这样fireResistant无参指定物品是否能免疫岩浆和火焰例如像下界合金盔甲setNoRepair无参指定物品是否能被铁砧等修复耐久度craftRemainer需传入一个Item类的实例指定物品在被使用或消耗后返回的东西例如岩浆桶被熔炉使用后返还一个空桶还有很多方法此处暂不讲解。再新建一个Guarantee.java (这个是向村民的保证书你在炸弹售卖村民那里想买炸弹必须先花钱买保证书才能升级而且之后买炸弹这个是第二个消耗品package craftedegg.rbw.item; import java.util.List; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.Item.Properties; import net.minecraft.world.level.Level; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import org.jetbrains.annotations.Nullable; public class Guarantee extends Item { public Guarantee(Properties p_41383_) { super(p_41383_); } public void appendHoverText(ItemStack p_41421_, Nullable Level p_41422_, ListComponent p_41423_, TooltipFlag p_41424_) { p_41423_.add(Component.translatable(item.rbw.guarantee).withStyle(ChatFormatting.GRAY)); super.appendHoverText(p_41421_, p_41422_, p_41423_, p_41424_);//在这个方法里我们可以修改物品在物品栏里下面显示出来的附属信息item.rbw.guarantee直接对应语言文件 } OnlyIn(Dist.CLIENT) public InteractionResultHolderItemStack use(Level p_41432_, Player p_41433_, InteractionHand p_41434_) { if (p_41432_.isClientSide) { String var10001 p_41433_.getDisplayName().getString(); p_41433_.sendSystemMessage(Component.literal(var10001 Component.translatable(text.rbw.guarantee_info).getString()).withStyle(ChatFormatting.GRAY)); }//这里实现玩家拿着保证书右键后会在消息栏发出一条消息“我保证不用村民那里买的炸弹攻击村庄...” return super.use(p_41432_, p_41433_, p_41434_); } }最后来到Main.java模组主类的主方法Mainpublic Main() { IEventBus modEventBus FMLJavaModLoadingContext.get().getModEventBus(); modEventBus.addListener(this::commonSetup); BlockReg.registerBombBlocks();注册炸弹方块 BlockReg.BLOCKS.register(modEventBus); ItemReg.registerBombBlockItems();直接注册炸弹 ItemReg.ITEMS.register(modEventBus); // TabReg.CREATIVE_MODE_TAB.register(modEventBus);创造物品栏。下一章讲解 // EntityReg.ENTITY_TYPES.register(modEventBus);实体注册 // GeckoLib.initialize();这里是GeckoLib依赖的初始化 MinecraftForge.EVENT_BUS.register(this); ModLoadingContext.get().registerConfig(Type.COMMON, Config.SPEC); }我们必须向FML的事件总线要求注册我们的模组以及模组里定义的这些东西。最后若你实在想先看效果先取消掉炸弹物品的注释然后运行runClient尝试用give指令获取保证书并右键尝试。