教程/制作数据包/实例:消除视线

来自Minecraft Wiki
跳转至: 导航搜索
Information icon.svg
此特性为Java版独有。

此教程介绍一个数据包制作的实例,阅读此教程前请先确保自己掌握教程/制作数据包教程/制作资源包的知识。了解命令记分板原始JSON文本等页面也会有所帮助。

目标[编辑 | 编辑源代码]

动手制作一个数据包前,你应该有一个明确的目标。也许你已经阅读过很多命令教程,但是却不知道如何有机地整合这些知识。在本实例中,我们会解析如何制作一个数据包,使得玩家视线所指的地方发生爆炸。

由于教程/制作数据包/实例:蜜蜂助手中已经包含了这篇实例的一部分内容,所以本实例讲述的会较为含糊,甚至有一段全部是命令。这就需要你自己静下心来思考这些文件的关系了。

本实例的GitHub地址:点击这里

开始[编辑 | 编辑源代码]

视线所指[编辑 | 编辑源代码]

在实例:蜜蜂助手中我们已经较为清楚的描述了“视线所指”如何实现,这里仅再一次给出局部坐标的解释图。

图中三色羊毛所组成的坐标轴是世界坐标系,蓝绿红对应ZYX三个坐标轴的正半轴;粒子所组成的坐标轴是玩家坐标系(摄像机坐标系),蓝绿红对应左上前三个坐标轴的正半轴。

爆炸[编辑 | 编辑源代码]

嗯,爆炸。还能多简单呢?

为了达到爆炸的目的,我们可以在所指的地方召唤一个瞬间爆炸的TNT或者苦力怕。

但是,我们也可以做的更有趣一些,比如……一个小小的世界橡皮擦,又或是加一些粒子特效。这就看你怎么发挥了。

编写与实现[编辑 | 编辑源代码]

初始化[编辑 | 编辑源代码]

以下#<命名空间>:<名字>表示<命名空间>下的<名字>标签,<命名空间>:<名字>表示<命名空间>下的<名字>对象(可以是函数、模型等)。

新建一个文件夹,填写好pack.mcmeta,建立data文件夹。在data文件夹下建立nuke(本实例以此为主要的命名空间)和minecraft/tags/functions(一些函数需要被每刻执行和在地图加载时执行)文件夹。

本实例中不使用队伍来侦测正在使用该功能的玩家(因为使用队伍可能会影响其他数据包的运作),而是使用记分项。本实例的记分项前缀为nuke

建立data/nuke/functions,建立load.mcfunction函数,内容如下:

 scoreboard objectives add nukePerson dummy
 scoreboard objectives add nukeUseCSt minecraft.used:minecraft.carrot_on_a_stick

第一条命令初始化了一个nukePerson记分项,用来记录玩家是否正在使用爆炸功能,类型为dummy,也就是只能被命令修改。

第二条命令初始化了一个nukeUseCSt记分项,类型是……

好,你可能会问,“为什么这一次不用dummy了”,对吧?

在原版中,胡萝卜钓竿应该算是最方便检测右键功能的物品,原因就是有这么一个准则minecraft.used:minecraft.carrot_on_a_stick,它可以自动记录玩家使用胡萝卜钓竿的次数。

没错,我们这次会使用胡萝卜钓竿作为本功能的开关(的本体)。nukeUseCSt记分项中的“CSt”也就是“Carrot on a Stick”(胡萝卜钓竿)的缩写。我们需要这个记分项来制作这个开关。

这一次胡萝卜钓竿的检测会参照更多的合成的某个版本编写,如果目录结构过于分散可以尝试自己简化。

建立data/minecraft/tags/functions/load.json,内容如下:

{
    "replace": false,
    "values": [
        "nuke:load"
    ]
}

这样,将nuke:load函数设定为地图载入时执行。

下文提及到将函数加入标签时请参照这里。

视线投射[编辑 | 编辑源代码]

现在,我们要获取玩家所指的位置来生成我们的TNT。

nuke命名空间下,建立tick.mcfunctionray.mcfunction函数。

tick.mcfunction
 execute as @a run function nuke:entities/player
 execute as @a[scores={nukePerson=1..}] at @s anchored eyes run function nuke:ray

第一条命令用于后面的胡萝卜钓竿检测。

第二条命令将执行位置对齐到头部,然后开始执行视线投射。

nuke:tick函数也加入#minecraft:tick,使得其每刻执行。

ray.mcfunction
 execute unless entity @s[distance=..20] positioned ^ ^ ^2 run function nuke:nuke
 execute if entity @s[distance=..20] unless block ~ ~ ~ #nuke:get_through run function nuke:nuke
 execute if entity @s[distance=..20] if block ~ ~ ~ #nuke:get_through positioned ^ ^ ^0.005 run function nuke:ray

好,一上来出现了很多东西,但是基本和实例:蜜蜂助手中的差不多。

#nuke:get_through标签内储存的是视线追踪会忽略的方块,毕竟我们获取“视线所指”的方块并不想包含空气、草、花这些东西,但同时我们需要获取的也不仅仅是一类方块(不同于蜜蜂助手中我们只获取蜂巢类方块)。这个标签是自创的,也就是你需要自己整理一份/抄实例的标签列表,然后把列表放到data/nuke/tags/blocks/get_through.json里面。

nuke:nuke是实际执行爆炸的函数。

你会发现,这次出现了三个命令。其中两条和实例:蜜蜂助手差不多,这里不再赘述。

第一条是因为,我们并不希望我们看着天空就不会发生爆炸(也就是并没有看着任何方块的时候),所以如果视线追踪往前20格都没有碰到任何方块,那就直接再前进两格然后执行爆炸。“再前进两格”并不是必须的。

爆炸和消除[编辑 | 编辑源代码]

nuke命名空间下,建立nuke:nuke函数。

 summon minecraft:tnt ~ ~ ~

没错,生成一个TNT,就这么简单。或者,如果你想做世界橡皮擦:

 setblock ~ ~ ~ minecraft:air

到此,基本功能的逻辑就实现(但还未实装)完毕了。

你也可以生成一个会瞬间爆炸的苦力怕,甚至可以调节它的爆炸威力,但是不要尝试用隐身状态效果隐藏它——苦力怕爆炸时会生成所带的状态效果的区域效果云,这可能会导致异常的卡顿。

胡萝卜钓竿开关[编辑 | 编辑源代码]

还记得上面提到的函数nuke:entities/player吗?

下面我会给出所有和这个胡萝卜钓竿开关相关的函数,接好了:

nuke:entities/player
 execute as @s[scores={nukeUseCSt=1..}] at @s run function nuke:use_carrot_on_a_stick/type
nuke:use_carrot_on_a_stick/type
 execute as @s[nbt={SelectedItem:{id:"minecraft:carrot_on_a_stick"}}] run function nuke:use_carrot_on_a_stick/mainhand
 execute as @s[nbt=!{SelectedItem:{id:"minecraft:carrot_on_a_stick"}}] run function nuke:use_carrot_on_a_stick/offhand
 scoreboard players reset @s nukeUseCSt
nuke:use_carrot_on_a_stick/mainhand
 execute as @s[nbt={SelectedItem:{tag:{id:"nuke:remote"}}}] run function nuke:use_carrot_on_a_stick/items/remote
 execute as @s[tag=!nuke_used,nbt={SelectedItem:{tag:{id:"nuke:remote_off"}}}] run function nuke:use_carrot_on_a_stick/items/remote_off
 tag @s remove nuke_used
nuke:use_carrot_on_a_stick/items/remote_off
 loot replace entity @s[nbt=!{SelectedItem:{id:"minecraft:carrot_on_a_stick"}}] weapon.offhand 1 loot nuke:remote
 loot replace entity @s[nbt={SelectedItem:{id:"minecraft:carrot_on_a_stick"}}] weapon.mainhand 1 loot nuke:remote
 function nuke:start
nuke:use_carrot_on_a_stick/items/remote
 loot replace entity @s[nbt=!{SelectedItem:{id:"minecraft:carrot_on_a_stick"}}] weapon.offhand 1 loot nuke:remote_off
 loot replace entity @s[nbt={SelectedItem:{id:"minecraft:carrot_on_a_stick"}}] weapon.mainhand 1 loot nuke:remote_off
 function nuke:stop
 tag @s add nuke_used
nuke:start
 scoreboard players set @s nukePerson 1
nuke:stop
 scoreboard players set @s nukePerson 0
“随便做”牌遥控器
“随便做”牌遥控器,打开状态

让我们解析一下为什么会这么写。

首先,我们得构想我们的这个胡萝卜钓竿开关——就叫遥控器好了,到底是怎么样的。

为了和普通的胡萝卜钓竿区别开来,我们会在物品的tag中嵌入自己的id标签(如果你不希望这个标签被其他的数据包占用,你也可以命名为类似nuke_id),并把关闭状态的遥控器的id的值设定为nuke:remote_off,开启的设定为nuke:remote

检测玩家的SelectedItem标签就可以检测主手上的物品了。此处我们检测tag,就是检测玩家手上有没有遥控器。

同时,因为遥控器肯定长得不像胡萝卜钓竿,所以我们需要通过CustomModelData来重新指定遥控器的材质。

段落内会有两个遥控器的图片(随便画的)。

新建一个资源包,填写好pack.mcmeta,在assets/minecraft/models/item/carrot_on_a_stick.json写入以下内容:

{
    "parent": "item/handheld_rod",
    "textures": {
        "layer0": "item/carrot_on_a_stick"
    },
    "overrides": [
        { "predicate": { "custom_model_data": 13400000 }, "model": "nuke:item/remote"},
        { "predicate": { "custom_model_data": 13400001 }, "model": "nuke:item/remote_off"}
    ]
}

其中的overrides就是来指定CustomModelData的。我们指定了两个物品标签谓词,分别指定了一个CustomModelData和它对应的模型:13400000(对应nuke:item/remote)和13400001(对应nuke:item/remote_off)。

assets/nuke/models/item/remote.json
{
    "parent": "item/handheld",
    "textures": {
        "layer0": "nuke:item/remote"
    }
}

其中nuke:item/remote对应材质assets/nuke/textures/item/remote.png,也就是开启的状态的材质。

另一个模型文件同理。

为了获取物品的方便,我们使用战利品表来预定义物品。此处以关闭的遥控器为例。

nuke:remote_off.json
{
    "pools": [
        {
            "rolls": 1,
            "entries": [
                {
                    "type": "minecraft:item",
                    "name": "minecraft:carrot_on_a_stick",
                    "functions": [
                        {
                            "function": "minecraft:set_nbt",
                            "tag": "{id:'nuke:remote_off',display:{Name:'{\"translate\":\"item.nuke.remote_off\"}'},CustomModelData:13400001}"
                        }
                    ]
                }
            ]
        }
    ]
}

掉落一份该战利品表就会获得关闭状态的遥控器。除了定义tag中的id,我们也自定义了物品的CustomModelData和显示名称。显示名称和实例:蜜蜂助手的多语言一样去写就行。此处在简体中文中显示的名称为“遥控器 (关闭)”。

同理,定义一份开启的。

现在请您再次回顾一遍上面的代码。现在能明白了吗?

基本思路是,循环检测钓鱼竿,如果有人用了遥控器就切换遥控器的状态,并且根据遥控器的状态决定是开始爆炸还是停止爆炸。

切换遥控器的状态,可以直接替换玩家对应的栏位,比如像上方一样使用/loot replace,然后调用定义好的战利品表,十分方便。

上方还预留了一个“offhand”,用于副手。除了使用和主手一样的使用目标选择器的nbt参数以外(但是由于副手没有提供SelectedItem这么方便的标签,我们需要读取玩家背包并且指定栏位),我们也可以使用1.15加入的(也就是实例:蜜蜂助手所使用的)谓词文件去判断。这个谓词的编写就让你自己尝试写吧,绝对不是因为这玩意是在1.14写的所以我懒得写谓词。

至此,编写完毕。

另见[编辑 | 编辑源代码]