教程:制作附加包/方块

来自Minecraft基岩版开发Wiki
方块
系列教程
所属系列
难度
中级
前置知识
适用版本
国际版
≥ 1.12.0
实践设备
Windows
所需软件

欢迎你来阅读本篇自定义方块教程!Minecraft是由无穷无尽的方块所组成的,因此在模组以及地图制作中,将难免遇到各种各样新的方块需求。本篇教程将带你入门基岩版自定义方块,了解如何在基岩版添加一个富有特色的方块。

在阅读本篇教程之前,请确保你已经能够创建一个行为包和资源包,若还不能,请先阅读开始之前;包的构建;运行、调试与导出页面以学习行为包的基础制作。此外,为简化本篇的篇幅,请先提前阅读Tutorial:制作附加包/物品以熟悉自定义内容的一些必要工具和思路。本教程将假设你已经了解了自定义物品的制作方法。

引言[编辑]

不同版本之间的差异[编辑]

自定义方块亦有三个分水岭版本存在:

  • 1.10,加入了对自定义方块的支持;
  • 1.16.100,加入了非常多全新的方块组件,然而它们都是实验性的;
  • 1.19.X,令一些实用的方块走出了实验性玩法,并加入了一些新特性。

请按照自己的需求选择需要的版本。我们推荐你使用稳定的版本和稳定的方块组件,1.19.70之后的组件已趋于稳定。

1.10至1.16.100的自定义方块编写[编辑]

你需要首先创建一个行为包和资源包,创建方法不过多赘述。

行为包部分[编辑]

在行为包目录下,创建一个名为blocks的文件夹,并在该文件夹下创建一个文件my_custom_block.block.json。你可以看到,这步骤和自定义物品是大同小异的。

  • 行为包名称或其内部ID
    • blocks
      • my_custom_block.block.json
    • manifest.json
    • pack_icon.png

我们也可以照葫芦画瓢地给出一个最基础的自定义方块的定义:

{
  "format_version": "1.16.0",
  "minecraft:block": {
    "description": {
      "identifier": "test:my_custom_block"
    }
  }
}

相信如果你已经学会了自定义物品的话,理解这段代码对你来说应该不是什么难事。这里需要指出的一点是,Mojang在1.15时曾对方块组件做出过更新并修改了方块组件所能接受的值。本教程基于1.16.0。如果你需要1.15以前的写法可以参考以下内容:

现在我们不妨直入主题来为我们的方块加入自定义组件吧!当然,旧版本的自定义方块的组件也非常的少,但你已经可以用它们来实现最基础的效果了。旧版本的方块组件有以下几个可用:

例如,如果我们希望自定义方块的光照等级是15,并且在被挖掉之后掉落钓鱼的战利品,我们可以写成:

{
  "format_version": "1.16.0",
  "minecraft:block": {
    "description": {
      "identifier": "test:my_custom_block"
    },
    "components": {
      "minecraft:block_light_emission": 1.0, // 旧版本下该值的范围为0.0-1.0
      "minecraft:loot": "loot_tables/gameplay/fishing.json"
    }
  }
}

以下是这段代码的解释:

  • minecraft:block_light_emission方块光照强度,它支持一个0.0-1.0的浮点数,值越大则光照越强。
  • minecraft:loot战利品表,当该方块被挖掘后,调用其指定的战利品表。

资源包部分[编辑]

自定义方块的资源包部分比较复杂。你可能需要以下文件(即粗体部分),请先提前创建:

  • 资源包名称或其内部ID
    • texts
      • en_US.lang
      • zh_CN.lang
    • textures
      • blocks
        • (方块贴图1).png
        • (方块贴图2).png
        • ...
      • terrain_texture.json(链接短ID和贴图)
      • flipbook_textures.json(当你需要一个要涉及到动态贴图的方块时创建,例如海晶灯)
    • blocks.json(链接ID和短ID)
    • manifest.json
    • pack_icon.png

block.json[编辑]

我们先从blocks.json入手。需要注意一点,自定义方块有三种显示模式:六面全同分顶面底面和侧面分顶底东西南北。举两个简单的例子,我们知道泥土六个面是完全一样的,这是利用了最简单的六面全同模式;草方块的顶面是绿色的草贴图,底面是泥土贴图,而侧面是覆盖了一层草的贴图,这就是分顶底侧面。在入手之前请先想好自己的方块应该是什么样的,再动手。下面是blocks.json的基本格式和三个模式的方块指定方法:

{
  "方块ID": { "textures": "短ID", "sound": "音效" }, // 六面全同
  "方块ID": { "textures": { "down": "短ID1", "side": "短ID2", "up": "短ID3" }, "sound": "音效" }, // 分顶底侧面
  "方块ID": { "textures": { "down": "短ID1", "up": "短ID2", "north": "短ID3", "south": "短ID4", "west": "短ID5", "east": "短ID6" }, "sound": "音效" } // 分顶底东西南北
}

其中音效可以是原版的方块音效,在被放置、被踩踏以及被破坏后将播放对应方块的音效,你可以查看原版的blocks.json来查看有哪些内容是能够允许的。以下是几种比较常用的音效:

  • stone:石头质音效(例如石头、混凝土);
  • glass:玻璃质音效(例如玻璃、荧石);
  • gravel:泥质音效(例如泥土、沙砾);
  • wood:木质音效(例如木板、木头);
  • cloth:布质音效(例如羊毛、地毯);
  • grass:草质音效(例如草方块、树叶);
  • metal:金属质音效(例如铁块、金块)。

举个例子,如果我希望加入一种新的木板,它应该是六面全同,使用木质音效的,因此可以写为:

{
  "test:my_custom_block": { "textures": "my_custom_block", "sound": "wood" }
}

terrain_texture.json[编辑]

接着我们来看terrain_texture.json。我们在blocks.json中指定了短ID,该文件就是将短ID和实际的贴图文件链接起来的。假设我们已经在textures/blocks文件夹里面放入了一个my_custom_planks.png的文件,我们便可以如此指代:

{
  "resource_pack_name": "vanilla",
  "texture_name": "atlas.terrain",
  "padding": 8,
  "num_mip_levels": 4,
  "texture_data": {
    "my_custom_block": { "textures": [ "textures/blocks/my_custom_planks" ] },
    "短ID": { "textures": [ "贴图路径" ] },
    ...
  }
}

其中前4行是什么你并不需要关心,你需要关心的只是其中的texture_data。它的一般格式也在上面的代码中提出,你可以看到短ID就是如此链接到实际贴图的。

动态贴图[编辑]

如果你的方块需要用到动态贴图,你可能需要用到flipbook_texture.json。动态贴图的用法可自行参考原版写法。

翻译文本[编辑]

和自定义物品类似,你也需要一个翻译文件来指定它们显示出的名字。打开en_US.lang,输入以下内容:

tile.test:my_custom_block.name=My Custom Block

如你所见,方块的翻译文本格式为tile.方块ID.name。同理地,在zh_CN.lang输入以下内容:

tile.test:my_custom_block.name=我的自定义方块

至此,你的方块编写就大功告成啦!当然了,本教程也会介绍新版本组件的简单应用,详见下文。

1.19.60及更高版本的自定义方块编写[编辑]

行为包部分[编辑]

1.19.60版本后又进一步的开放了部分组件。和高版本物品组件是几乎全新不同,高版本的方块组件是基于低版本组件的。1.19.60之后有下列组件可以不开启实验性玩法使用:

同时,旧版组件大多数都经过了重命名,这里不再详述。

资源包部分[编辑]

高版本方块的流程和低版本方块的流程可以说是几乎完全相同的。但特别地,当你指定了minecraft:material_instancetexture参数时,写法可能会有一些小变化。在下面的范例中你就可以知道了。

方块状态的设定[编辑]

方块状态(Block States)是指定方块所处状态的一种重要手段,例如半砖是上半砖还是下半砖、羊毛的颜色、按钮的朝向等等,这些方块都有相同的ID,但是它们所处的状态不一样。在自定义方块中你可以利用description中的states指定方块所处的方块状态,并利用permutations来另行指代不同方块状态下采用的不同组件。以下是微软文档中给出的一个方块状态与置换的范例:

{
  "format_version": "1.19.40",
  "minecraft:block": {
    "description": {
      "identifier": "custom:lamp_block",
      "states": {
        "custom:is_lit": [ true, false ]
      }
    },
    "permutations": [
      {
        "condition": "query.block_state('custom:is_lit') == true",
        "components": {
          "minecraft:light_emission": 15
        }
      },
      {
        "condition": "query.block_state('custom:is_lit') == false",
        "components": {
          "minecraft:light_emission": 0
        }
      }
    ],
    "components": {
      "minecraft:friction": 0.6,
      "minecraft:map_color": "#00ff00" 
    }
  }
}

对这段代码做一些必要的解释:

  • states方块状态,指定方块可能具有的状态。在这里,该方块被指定了具有custom:is_lit的方块状态,并支持两个值,分别为truefalse
  • permutations方块置换,指定在满足特定的条件(condition)下该方块所具有的组件。我们可以看到,condition的检测条件为query.block_state('custom:is_lit') == true,这是用于检测该方块所处状态的Molang,当custom:is_lit方块状态为true时将使用组件"minecraft:light_emission": 15,即光照亮度为15级。下面的条目也是同理的。
  • components方块组件,指定方块所具有的通用特性。

你可以使用命令/setblock/fill来放置这些具有自定义特性的方块。

关于方块状态和置换,你可以查看更加详细的微软文档

方块性状的设定[编辑]

一些范例[编辑]

无法被破坏和炸毁的泥土[编辑]

如果你希望泥土不再能被破坏,何不以假乱真来做一个新方块呢?请记住,原版物品和方块都是不能更改的,因此如果你希望更改原版方块,请立即放弃这种想法,自己做个新方块才是更好的选择。

要实现这点很简单,我们的核心要素在于“无法破坏”和“无法炸毁”两点,这分别可以用minecraft:destructible_by_miningminecraft:destructible_by_explosion来解决。因此可以用下面的行为包代码:

行为包/blocks/dirt.block.json
{
    "format_version": "1.19.40",
    "minecraft:block": {
        "description": {
            "identifier": "wiki:dirt"
        },
        "components": {
            "minecraft:destructible_by_explosion": false,
            "minecraft:destructible_by_mining": false
        }
    }
}

资源包方面,我们可以偷个懒,直接调用原版的方块路径:

资源包/blocks.json
{
  "wiki:dirt": { "textures": "dirt", "sound": "gravel" }
}

可以调用原版的贴图有一个条件,就是原版的这个对应短ID不能链接到多个纹理,一旦链接到有多个纹理的短ID,就会出现紫黑块贴图错误。如果不能直接偷懒用原版的短ID,就需要再用terrain_texture.json来链接到贴图上(当然这个贴图也是可以直接链接原版的)。最后搞定翻译即可:

资源包/texts/en_US.lang
tile.wiki:dirt.name=Dirt
资源包/texts/zh_CN.lang
tile.wiki:dirt.name=泥土

然后,你就可以获得一个以假乱真,但是怎么炸也炸不坏的泥土了!

会发光的玻璃[编辑]

想不想要一种可以自发光的玻璃?我们当然可以实现!想想玻璃的一些需求要素:

因此,行为包代码也就呼之欲出了。

行为包/blocks/glass.block.json
{
    "format_version": "1.19.40",
    "minecraft:block": {
        "description": {
            "identifier": "wiki:scene_block_glass"
        },
        "components": {
            "minecraft:material_instances": { "*": { "render_method": "blend" } },
            "minecraft:destructible_by_explosion": { "explosion_resistance": 0.3 },
            "minecraft:destructible_by_mining": { "seconds_to_destroy": 0.3 },
            "minecraft:light_dampening": 0,
            "minecraft:light_emission": 15,
            "minecraft:loot": "loot_tables/empty.json"
        }
    }
}

一些基本解释:

  • minecraft:material_instance:令方块为透明渲染。*代表所有面都按照透明的方式渲染。
  • minecraft:light_dampening:对于透明渲染的方块而言,如果不设置这个值,它本质上是不透明方块,一是会导致草方块的变化,二是会导致方块与方块之间在底面出现很重的阴影,对于“发光玻璃”而言,这并不是我们希望的结果。

资源包不做过多解释,这是很简单的。

能穿透又摸不到的假方块[编辑]

假方块!在很久以前,基岩版的按钮漏洞导致其在某个特殊值下会显示为整个方块,而其又没有碰撞箱,是可以穿过的,因此称之为假方块。虽然这是一个漏洞,但今天我们却能实打实的做一个真正的假方块出来了!要想实现假方块,我们只需要考虑碰撞箱和击中箱的问题。这可以利用minecraft:collision_boxminecraft:selection_box来解决。我们只需要完全取消掉它的碰撞箱,就可以让它是可被穿过的:

行为包/blocks/fake_oak_planks.block.json
{
    "format_version": "1.19.60",
    "minecraft:block": {
        "description": {
            "identifier": "wiki:fake_oak_planks"
        },
        "components": {
            "minecraft:collision_box": false
        }
    }
}

这将禁用它的碰撞箱,成为可穿过的方块;而如果再引入一个击中箱:

行为包/blocks/fake_oak_planks.block.json
{
    "format_version": "1.19.60",
    "minecraft:block": {
        "description": {
            "identifier": "wiki:fake_oak_planks"
        },
        "components": {
            "minecraft:collision_box": false,
            "minecraft:selection_box": false
        }
    }
}

这甚至会让玩家无法选中这个方块(包括创造模式玩家)!如果放到了错误的地方,你就需要用/setblock来解决啦。

自定义台阶[编辑]

假设我们在抗爆泥土上再进一步,要实现不可破坏的台阶,显然这是一种不完整方块。对于台阶,我们需要考虑以下几点:

  • 方块不是完整方块,必须使用特定的方块模型。方块模型需要在Blockbench里自行绘制,假设我们现在已经拥有了geometry.slab_upgeometry.slab_down两个模型。指定模型可以由minecraft:geometry来承担。
  • 其碰撞箱和击中箱都必须是普通方块的一半;
  • 因为调用了自定义模型,这个方块的面的表达已经不再能用普通的三种情况来代替,必须使用minecraft:material_instance来选择性地指定面的贴图。

基于这样的考虑,我们给出以下参考代码:

行为包/blocks/cobblestone_slab_up.block.json
{
    "format_version": "1.19.60",
    "minecraft:block": {
        "description": {
            "identifier": "wiki:cobblestone_slab_up"
        },
        "components": {
            "minecraft:destructible_by_explosion": false,
            "minecraft:destructible_by_mining": false,
            "minecraft:collision_box": { "origin": [ -8, 8, -8 ], "size": [ 16, 8, 16 ] },
            "minecraft:selection_box": { "origin": [ -8, 8, -8 ], "size": [ 16, 8, 16 ] },
            "minecraft:geometry": { "identifier": "geometry.slab_up" },
            "minecraft:material_instances": { "*": { "texture": "cobblestone" } }
        }
    }
}

关于碰撞箱和选择箱的写法,见对应条目。如果我们需要把两种台阶合在一起写,就可以利用前面的方块状态的设定的内容来合并:

行为包/blocks/cobblestone_slab.block.json
{
    "format_version": "1.19.70",
    "minecraft:block": {
        "description": {
            "identifier": "wiki:cobblestone_slab",
            "states": { "vertical_half": [ "top", "bottom" ] }
        },
        "components": {
            "minecraft:destructible_by_explosion": false,
            "minecraft:destructible_by_mining": false,
            "minecraft:material_instances": { "*": { "texture": "cobblestone" } }
        },
        "permutations": [
            {
                "condition": "query.block_state('vertical_half') == 'top'",
                "components": {
                    "minecraft:collision_box": { "origin": [ -8, 8, -8 ], "size": [ 16, 8, 16 ] },
                    "minecraft:selection_box": { "origin": [ -8, 8, -8 ], "size": [ 16, 8, 16 ] },
                    "minecraft:geometry": { "identifier": "geometry.slab_up" }
                }
            },
            {
                "condition": "query.block_state('vertical_half') == 'bottom'",
                "components": {
                    "minecraft:collision_box": { "origin": [ -8, 0, -8 ], "size": [ 16, 8, 16 ] },
                    "minecraft:selection_box": { "origin": [ -8, 0, -8 ], "size": [ 16, 8, 16 ] },
                    "minecraft:geometry": { "identifier": "geometry.slab_down" }
                }
            }
        ]
    }
}

最后利用/setblock等命令对方块状态进行控制。是不是很有意思?

关于资源包的问题,事实上你看到了minecraft:material_instances这个组件指定了texture,这其实就是blocks.json中的那个短ID,在方块中也是存在短ID迁移到行为包中的现象的。因此,blocks.json就可以进行简化:

资源包/blocks.json
{
  "wiki:cobblestone_slab": { "sound": "stone" }
}

即忽略掉texture参数。至于terrain_texture.json,其实行为包代码也偷了个懒,直接调用了原版的cobblestone纹理,因此根本无需再次更改!

这就是自定义方块,自定义方块要稍微比自定义物品复杂一些,但本教程已经尽可能将这些内容讲的完整了。期待这些能对你有所帮助。如果需要更详细的文档,请查阅微软文档的自定义方块文档

本教程默认读者已掌握附加包的基本构架。教程为自定义方块的基础教程,关于自定义方块的更多内容请查看进阶教程页面。

概述[编辑]

自定义方块是在基岩版beta 1.12.0.2中的新增内容。在基岩版1.16.100.56及之后的部分版本更新中, Mojang 为自定义方块提供了大量的接口,这使得自定义方块的功能大大增加,不过现在仍有绝大多数的接口未被开放。

通过自定义方块,创作者可以在游戏中创造出属于您的全新方块,并通过添加属性、组件和事件等内容赋予它许多有趣的特性。

添加方块[编辑]

添加自定义方块首先需要了解一下自定义方块行为部分的基本结构。

自定义方块配置文件存储在行为包中的 blocks文件夹下,其数据结构如下:

{
  "format_version": "1.16.100",
  "minecraft:block": {
    "description": {
    }, //描述
    "components": {
    }, //组件
    "events": {
    }, //事件
    "permutations": [
    ] //置换
  }
}

如上,方块配置文件由描述、组件、事件与置换四部分内容构成。下面对上述四种基本内容进行了简要阐述:

描述[编辑]

描述 (description) 对象储存了用于描述该方块的基础信息,其数据结构如下:

属性名称 数据类型 描述
identifier 字符串 设置此方块的标识符。须包含命名空间但不得使用minecraft:作为命名空间。(除非所编辑的方块为原版方块)
is_experimental 布尔值 (可选)决定了该方块是否为实验性方块。默认值为 false 。若此属性值为 true ,则该方块需开启实验性玩法才可获得。
properties 对象 设置此方块所具有的一个或多个属性。例如:"test:block_property": [ 0, 1, 2, 3 ],其中test:block_property为属性名称,数组中的参数为该方块此属性可能拥有的值(游戏默认该方块初始属性为所有属性数组中的第一个参数)。数组的参数类型可以为整数、小数、布尔值或字符串。
register_to_creative_menu 布尔值 设置此方块是否出现在创造模式物品栏。(基岩版1.15.0至今由于不明原因导致此API失效,待修复)

组件[编辑]

组件(components)对象决定了该方块的功能属性,您可选择并添加您需要的组件属性。

组件分为一般组件和触发器。一般组件用于定义该方块的属性,触发器用于在特定条件下使方块触发事件。

事件[编辑]

事件(events)对象储存了该方块可能用到的所有事件。

通过在一个事件下直接添加多个事件或使用序列间接添加多个事件可以使一个触发器同时触发多个事件:

示例:

"events": {
  "test_event": { //事件名称
    "set_block_property": { //第一个事件
      "minecraft:direction": 1
    },
    "run_command": { //第二个事件
      "command": "say Hello world"
    }
  }
}

置换[编辑]

置换(permutations)数组储存了该方块在对应条件下会置换或新增的对应所有组件。一般使用 query.block_property[注 1] 来获取方块属性并以此作为置换条件。

示例[编辑]

现在仿照下面的示例,通过创建一个方块的JSON行为文件来向游戏中添加一个简单的自定义方块:

{
  "format_version": "1.16.100",
  "minecraft:block": {
    "description": {
      "identifier": "example:test_block"
    },
    "components": {
      "minecraft:destroy_time": 1.0,
      "minecraft:explosion_resistance": 2.5,
      "minecraft:friction": 0.6,
      "minecraft:map_color": "#FFFFFF",
      "minecraft:block_light_absorption": 0,
      "minecraft:block_light_emission": 0
      }
  }
}

资源定义[编辑]

主条目:资源定义
创建完自定义方块后,还需要对其增添纹理、音效等内容来改变其外观表现。首先需要对添加的纹理进行定义。

定义纹理[编辑]

准备好两张PNG格式的图片,这里以自定义类似原版原木的方块作为示例:

Tutorial Block Texture
custom_log_end.png —— “原木”顶部和底部的图片
Tutorial Block Texture
custom_log_side.png —— “原木”侧面的图片

将这两张图片分别命名并放到资源包的<RP>/textures/blocks/路径下,这里分别命名为“custom_log_end.png”和“custom_log_side.png”。

现在准备好了图片,还需要对这两张图片进行定义。创建一个名为“terrain_texture.json”的文件到<RP>/textures/路径下,然后向其中添加如下内容:

{
  "resource_pack_name": "tutorial_pack", //这里填写任意名称
  "num_mip_levels": 4,
  "padding": 8,
  "texture_name": "atlas.terrain",
  "texture_data": {
    "log_end": { //定义后的名称
      "textures": "textures/blocks/custom_log_end"  //图片文件的路径
    },
    "log_side": {
      "textures": "textures/blocks/custom_log_side"
    }
  }
}

这样就将刚刚的custom_log_end.pngcustom_log_side.png两张图片分别定义为了“log_end”和“log_side”这两个名称。

每添加一张新的图片都需要在terrain_texture.json中定义一次,定义后的名称将用于在以后给各种文件或组件调用。

blocks.json[编辑]

定义完了图片,现在需要将这两张图片应用到刚刚的自定义方块上,并且为它添加音效。

首先创建一个名为“blocks.json”的文件到资源包根目录下,然后向其中添加如下内容:

{
  "format_version": [ 1, 1, 0 ],
  "example:test_block": { //刚刚创建的自定义方块的标识符
    "sound" : "wood", //使用木头的音效
    "textures" : {
      "down" : "log_end", //刚刚定义的图片名称,下同
      "side" : "log_side", 
      "up" : "log_end"
    }
  }
}

现在保存文件并进入游戏,将附加包添加进一个世界并进入世界,输入如下命令: /give @s example:test_block 就可以获取到刚刚添加的自定义方块了。

Tutorial Test Customer Block
自定义“原木”被成功添加到了游戏

  1. query.block_property 是Molang中的一项查询功能。

< 物品 | 配方 >