跳转至

自定义组件与方块事件

基岩版通过自定义组件机制,让脚本API可以响应方块上发生的各种事件,例如玩家交互、踩踏、随机刻等。

注册自定义组件

自定义组件必须在世界加载之前注册,要使用 system.beforeEvents.startup 事件:

BP/scripts/my_block.js
import { system } from "@minecraft/server";

/** @type {import("@minecraft/server").BlockCustomComponent} */
const MyBlockComponent = {
    onPlayerInteract({ block, player }) {
        player?.sendMessage(`你点击了 ${block.typeId}!`);
    },
    onTick({ block }) {
        // 每次刻触发
    }
};

system.beforeEvents.startup.subscribe(({ blockComponentRegistry }) => {
    blockComponentRegistry.registerCustomComponent("wiki:my_component", MyBlockComponent);
});

注册之后,在方块JSON中声明使用这个组件:

BP/blocks/my_block.json > components
"wiki:my_component": {}

参数化自定义组件

自定义组件可以接受参数,让同一套逻辑适配不同方块:

BP/blocks/my_block.json > components
"wiki:reward_on_break": {
    "item": "minecraft:diamond",
    "count": 3
}

在脚本中通过事件对象的 params 字段读取参数:

const RewardOnBreakComponent = {
    onPlayerBreak({ block, dimension }, { params }) {
        const { item, count } = params;
        dimension.spawnItem(
            new ItemStack(item, count),
            block.center()
        );
    }
};

事件钩子一览

以下是 BlockCustomComponent 支持的所有事件钩子:

beforeOnPlayerPlace
玩家将要放置该方块之前触发。可通过 event.cancel = true 取消放置。
onBreak
方块以任何方式被破坏时触发(玩家、爆炸、命令等)。
onEntityFallOn
实体跌落到该方块上时触发。需配合 minecraft:entity_fall_on 组件,可设置触发所需的最小跌落高度。
onPlace
方块以任何方式被放置后触发。
onPlayerBreak
玩家破坏该方块时触发(不含爆炸、命令等方式)。
onPlayerInteract
玩家右键交互该方块时触发。
onRandomTick
随机刻触发时调用。需配合 minecraft:tick 组件并设置 interval_rangelooping: true
onRedstoneUpdate
该方块接收到的红石信号发生变化时触发。
onStepOff
实体走出该方块时触发。
onStepOn
实体走上该方块时触发。
onTick
minecraft:tick 组件设定的固定间隔触发。

完整示例:交互开关灯

这个例子展示了一个可以交互切换开关状态的灯:

BP/blocks/toggle_lamp.json
{
    "format_version": "1.26.10",
    "minecraft:block": {
        "description": {
            "identifier": "wiki:toggle_lamp",
            "states": {
                "wiki:is_on": [false, true]
            }
        },
        "components": {
            "wiki:toggle": {
                "state": "wiki:is_on",
                "on_sound": "random.click",
                "off_sound": "random.click"
            },
            "minecraft:material_instances": {
                "*": { "texture": "wiki:lamp_off" }
            }
        },
        "permutations": [
            {
                "condition": "q.block_state('wiki:is_on')",
                "components": {
                    "minecraft:light_emission": 15,
                    "minecraft:material_instances": {
                        "*": { "texture": "wiki:lamp_on" }
                    }
                }
            }
        ]
    }
}
BP/scripts/toggle_lamp.js
import { system } from "@minecraft/server";

const ToggleComponent = {
    onPlayerInteract({ block }, { params }) {
        const currentState = block.permutation.getState(params.state);
        block.setPermutation(
            block.permutation.withState(params.state, !currentState)
        );
        block.dimension.playSound(
            currentState ? params.off_sound : params.on_sound,
            block.center()
        );
    }
};

system.beforeEvents.startup.subscribe(({ blockComponentRegistry }) => {
    blockComponentRegistry.registerCustomComponent("wiki:toggle", ToggleComponent);
});

定时触发:minecraft:tick

minecraft:tick 组件配合 onTick 钩子,可以实现按固定间隔执行逻辑:

components
"minecraft:tick": {
    "interval_range": [20, 20],
    "looping": true,
    "looping_deadline": 0
}
  • interval_range:触发间隔的随机范围(单位:刻)。设为 [20, 20] 表示每1秒触发一次。
  • looping:是否循环触发。
  • looping_deadline:循环最大触发次数,0表示无限。

onRandomTick 类似,但依赖游戏的随机刻机制(需要 interval_rangelooping: true)。

旧版JSON事件迁移

在格式版本1.20.0之前,自定义方块事件使用JSON响应定义。这种旧式事件已被废弃,不应在新方块中使用。以下是几个常见旧式响应的Script API等效写法:

旧式:add_mob_effect

onStepOn({ entity }) {
    entity?.addEffect("regeneration", 30, { amplifier: 10, showParticles: false });
}

旧式:damage

import { EntityDamageCause } from "@minecraft/server";

// ...
onStepOn({ entity }) {
    entity?.applyDamage(2, { cause: EntityDamageCause.drowning });
}

旧式:run_command

onPlayerInteract({ block }) {
    block.dimension.runCommand(`say 命令在此运行!`);
}