User Tools

Site Tools


Sidebar

安装

基础

高级

物品

方块和方块实体

流体

实体

世界生成

配方类型

其他

事件

Mixin

动态数据生成

Minecraft 1.15 的教程

Minecraft 1.14 的教程

贡献 Fabric

神秘人优选

zh_cn:tutorial:blocks

添加一个方块

将方块添加到你的模组过程与添加物品类似。你可以创建Block或自定义类的实例,然后将其注册到Registry.BLOCK注册表。你还需要提供纹理和方块状态或模型文件以提供方块外观。如需了解方块模型格式的更多信息,请参考Minecraft Wiki模型页面

创建一个方块

首先创建Block的实例。该实例可以存储在任何地方,但是我们会在ModInitializer的顶部开始。Block构造器函数需要一个AbstractBlock.Settings实例,也就是用于配置方块属性的构造器。Fabric提供一个FabricBlockSettings构造器类以及更多可用的选项。

  1. public class ExampleMod implements ModInitializer {
  2.  
  3. /* 声明和初始化我们的自定义方块实例。
  4.   我们将方块材质(material)设置为METAL(金属),需要镐来高效挖掘。
  5.  
  6.   `strength`会将方块的硬度和抗性设为同一个值。
  7.   硬度决定了方块需要多久挖掘,抗性决定了方块抵御爆破伤害(如爆炸)的能力。
  8.   石头的硬度为1.5f,抗性为6.0f,黑曜石的硬度为50.0f,抗性为1200.0f。
  9.  
  10.   可以在`Blocks`类中查找所有原版方块的统计。
  11.   */
  12. public static final Block EXAMPLE_BLOCK = new Block(FabricBlockSettings.of(Material.METAL).hardness(4.0f));
  13.  
  14. @Override
  15. public void onInitialize() {
  16.  
  17. }
  18. }

注册方块

方块应该注册在Block.REGISTRY的注册表下。调用Registry.register并传递适当的参数。

  1. public class ExampleMod implements ModInitializer {
  2.  
  3. public static final Block EXAMPLE_BLOCK = new Block(FabricBlockSettings.of(Material.METAL).hardness(4.0f));
  4.  
  5. @Override
  6. public void onInitialize()
  7. {
  8. Registry.register(Registry.BLOCK, new Identifier("tutorial", "example_block"), EXAMPLE_BLOCK);
  9. }
  10. }

您的方块不能作为物品存入背包,但可以通过使用/setblock tutorial:example_block在游戏中看到。

为方块注册物品

在大多数情况下,您希望能够拿着物品放置方块。为此,您需要在物品注册表中注册一个相应的BlockItem。您可以通过在Registry.ITEM下注册BlockItem的实例来执行此操作。该物品的注册表名称通常应与该方块的注册表名称相同。

  1. public class ExampleMod implements ModInitializer {
  2.  
  3. /* Declare and initialize our custom block instance.
  4.   We set out block material to METAL, which requires a pickaxe to efficiently break.
  5.   Hardness represents how long the break takes to break. Stone has a hardness of 1.5f, while Obsidian has a hardness of 50.0f.
  6.   */
  7. public static final Block EXAMPLE_BLOCK = new Block(FabricBlockSettings.of(Material.METAL));
  8.  
  9. @Override
  10. public void onInitialize() {
  11. Registry.register(Registry.BLOCK, new Identifier("tutorial", "example_block"), EXAMPLE_BLOCK);
  12. Registry.register(Registry.ITEM, new Identifier("tutorial", "example_block"), new BlockItem(EXAMPLE_BLOCK, new Item.Settings().group(ItemGroup.MISC)));
  13. }
  14. }

给您的方块一个外观

您可能已经注意到,新的方块只是游戏中紫色和黑色棋盘格图案。这表明Minecraft加载方块资源或外观时出错。运行客户端时,完整的问题列表会输出在你的日志中。你需要以下文件来给予方块外观:

  • 方块状态文件
  • 方块模型文件
  • 纹理
  • 物品模型文件(如果方块有与之关联的物品)

这些文件位于:

方块状态:src/main/resources/assets/tutorial/blockstates/example_block.json
方块模型:src/main/resources/assets/tutorial/models/block/example_block.json
物品模型:src/main/resources/assets/tutorial/models/item/example_block.json
方块纹理:src/main/resources/assets/tutorial/textures/block/example_block.png

方块状态文件根据其方块装填确定该方块应使用的模型。由于我们的方块没有所谓状态,所以我们用空字符串表示所有:

src/main/resources/assets/tutorial/blockstates/example_block.json
{
  "variants": {
    "": { "model": "tutorial:block/example_block" }
  }
}

方块模型文件定义了方块的形状和纹理。我们将使用block/cube_all作为父模型,这将使我们能够轻松地在方块的所有面上设置相同的纹理。

src/main/resources/assets/tutorial/models/block/example_block.json
{
  "parent": "block/cube_all",
  "textures": {
    "all": "tutorial:block/example_block"
  }
}

在大多数情况下,您想让方块作为物品时外观还是这个方块。为此,您可以制作一个从方块模型文件继承的项目文件,这会使得该物品外观和方块相同:

src/main/resources/assets/tutorial/models/item/example_block.json
{
  "parent": "tutorial:block/example_block"
}

加载Minecraft,您的方块最终应该具有外观!

配置方块掉落物

该方块必须有一个战利品表,以便在该方块被破坏时掉落物品。以下文件会使方块被破坏时掉落其本身。

src/main/resources/data/tutorial/loot_tables/blocks/example_block.json
{
  "type": "minecraft:block",
  "pools": [
    {
      "rolls": 1,
      "entries": [
        {
          "type": "minecraft:item",
          "name": "tutorial:example_block"
        }
      ],
      "conditions": [
        {
          "condition": "minecraft:survives_explosion"
        }
      ]
    }
  ]
}

在1.17,破坏方块有所改变,定义采集工具和采集等级需要使用标签,请参考标签教程。我们需要将方块添加到以下标签:

采集工具:src/main/resources/data/minecraft/tags/blocks/mineable/<tooltype>.json,其中'tooltype'可以是'axe'、'pickaxe'、'shovel'、'hoe'
采集等级:src/main/resources/data/minecraft/tags/blocks/needs_<tier>_tool.json,其中'tier'可以是:'stone'、'iron'、'diamond'
src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json
{
  "replace": false,
  "values": [
    "example:example_block"
  ]
}
src/main/resources/data/minecraft/tags/blocks/needs_stone_tool.json
{
  "replace": false,
  "values": [
    "example:example_block"
  ]
}

对于采集等级标签(needs_stone_tool、needs_iron_tool和needs_diamond_tool)生效,在方块定义中将requiresTool()到FabricToolSettings:

  1. public static final Block EXAMPLE_BLOCK = new ExampleBlock(FabricBlockSettings.of(Material.METAL).strength(4.0f).requiresTool());

创建自定义方块类

当创建一个简单的方块时,上述方法效果很好,但是有时您想要一个具有独一无二机制的方块。我们将创建一个单独的扩展Block的类来执行此操作。该类需要一个带有AbstractBlock.Settings参数的构造器:

  1. public class ExampleBlock extends Block {
  2.  
  3. public ExampleBlock(Settings settings) {
  4. super(settings);
  5. }
  6. }

你可以在方块类中覆盖方法以实现特殊功能。这里是onUse方法的实现,右键单击方块时会调用此方法。我们检查交互是否在服务器进行,并向玩家发送消息,“Hello, world!”

  1. public class ExampleBlock extends Block {
  2.  
  3. public ExampleBlock(Settings settings) {
  4. super(settings);
  5. }
  6.  
  7. @Override
  8. public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
  9. if (!world.isClient) {
  10. player.sendMessage(new LiteralText("Hello, world!"), false);
  11. }
  12.  
  13. return ActionResult.SUCCESS;
  14. }
  15. }

要使用自定义方块类,请在注册时将new Block替换为new ExampleBlock

  1. public class ExampleMod implements ModInitializer {
  2.  
  3. public static final ExampleBlock EXAMPLE_BLOCK = new ExampleBlock(Block.Settings.of(Material.STONE).hardness(4.0f));
  4.  
  5. @Override
  6. public void onInitialize() {
  7. Registry.register(Registry.BLOCK, new Identifier("tutorial", "example_block"), EXAMPLE_BLOCK);
  8. Registry.register(Registry.ITEM, new Identifier("tutorial", "example_block"), new BlockItem(EXAMPLE_BLOCK, new Item.Settings().group(ItemGroup.MISC)));
  9. }
  10. }

自定义VoxelShape

当使用不能完整填充一个方块的方块模型(例如铁砧、台阶、楼梯)时,邻近的方块会隐藏面:

要解决这个问题,我们需要定义方块的VoxelShape

 @Override
 public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, ShapeContext context) {
     return VoxelShapes.cuboid(0f, 0f, 0f, 1f, 1.0f, 0.5f);
 }

注意方块的collision shape默认为其描边形状,如果未被指定。

下一步

zh_cn/tutorial/blocks.txt · Last modified: 2021/12/03 15:40 by solidblock