本帖最后由 Dahesor 于 2022-4-21 12:13 编辑
命令教程“真”从零开始 (五) 记分板与/scoreboard
声明:
1. 本教程默认所有读者看过本系列的前四帖。作者不对可能冒出来的术语或方言负责。以前帖的链接在最后。
2. 本系列教程默认读者拥有关于Minecraft游戏的基础了解。
3. 本系列全部教程均适用于当前Java最新版(1.18)。
4. 本系列教程致力于基础原理而非使用方法,因为某些原因,这是本声明里最重要的一条。
Minecraft命令是一种自洽的编程语言么?
有一些人在讨论这个问题。
但我们今天要研究的并不是这个。
——编程语言嘛,有一个要素是必须的,那就是变量(Variables)。
今天,我们要看的,就是变量的问题——记分板,/scoreboard。
注意,/scoreboard在Java1.13之后与1.12之前相差很大。其标签与队伍的功能被分化为两条独立的指令。 注意,基岩版并没有将标签与队伍的功能分化为两条独立的指令。对于这两个较Java多出的功能与其他的细微差异,
管理计分板
想要研究计分板,首先让我们创建一个看看:
/scoreboard这条指令分为了两个子指令:/scoreboard objectives,与/scoreboard players。
其中,/scoreboard objectives主要是用于管理计分板本身,而/scoreboard players则用于管理玩家在计分板上的分数。
添加一个计分板,我们使用的是管理计分板的/scoreboard objectives add:
格式:
- /scoreboard objectives add <计分板ID> <计分准则> [显示名称]
复制代码
add就是“添加”的意思,<计分板ID>(学名:计分项)为一串英文字符(可以使用下划线)。理论上你用什么都行,只要保证不重复而且自己记得住分得清就好了。
接下来,就是复杂一点的东西了:也就是上方出现的元素“<计分准则>”
计分准则
什么是计分准则(criterion)?
简单来讲就是,根据什么加分?
足球是进一门加一分,羽毛球是谁接不住对手加一分,这里也一样——如何加分?
好,现在找到游戏暂停页面中的"统计"这一项。
这一个功能记录了玩家非常多的数据:你走了几米,跳了几下,破坏一个特定的方块几次,杀死几只僵尸,又或者触发了几次袭击事件。
这里记录的所有项目,都可以成为准则。
而且不止,除了这些项目,还有更多可用的计分准则。
你的计分板可以让玩家“每丢出一颗钻石加一分”,又或者“有多少生命值就设定为几分”,也可以是“每杀一名玩家”加一分,甚至“每杀死一名属于特定队伍的玩家加一分”或“被特定队伍的玩家杀死加一分”等等等等。
在这里我不会列出所有准则列表——学会自己找资料看wiki吧。
你可以点这里在WIKI中寻找所有可用的计分准则。
填入准则,你就有一个计分板啦。
比如:
- /scoreboard objectives add 123 deathCount
复制代码
这会创建一个ID为“123”的计分板,记分方式为“deathCount”,也就是“死亡次数”——玩家每死一次就加一分。
但在这些准则中,有两项是特殊的——
一个是"dummy",另一个是"trigger"。
dummy的学名是“虚拟型”,听起来可能很唬人,但翻译过来就是“假的”,或者“货币”。
如果你使用dummy作为准则,这个计分板不会因为任何原因增加分数,只能用指令调整。所以dummy普遍地被使用在游戏的货币,计算,或者分数系统上。
至于trigger嘛,我们还涉及不到。虽然不难,但涉及到了JSON相关,现在有个印象就好。
显示名称
最后,就是显示名称。这不同于ID,是玩家在游戏中可以看到的名称。你可以使用任何字符,任何语言。
[显示名称] 完全是使用JSON格式表达的,将在系列教程第17帖讲到。不过在了解JSON之前,用双引号将你想要的文字引起来就好了:
- /scoreboard objectives add abc dummy "金钱"
复制代码 这条指令会创建一个ID为“abc”,显示名称为金钱,计分方式为只能指令更改的记分板。如何使用指令更改分数,会在下面讨论。
注意!这是英文的双引号""而不是中文的“”别搞错了!(所有人打代码都会出现切错中英文引号,括号,等于号,连字符等等问题。)
其他管理
接下来,是几条没啥可讲,不讲又不完整的指令:
1. 列出
如果你忘记了自己计分板的ID,怎么办?
你要使用的是
- /scoreboard objectives list
复制代码 这会列出所有计分板的ID,显示名称,与积分准则。
2. 修改
如果你突然对一个计分板的显示名称不满意,可以使用以下指令修改它:
- /scoreboard objectives modify <计分板ID> displayname <显示名称>
复制代码 ......我是不知道为什么Wiki上选择计分板的方式是“<准则>”啦,这显然是错的,额,发完这帖我就去改过来。(日常Wiki挑错)
- /scoreboard objectives modify abc displayname "分数"
复制代码 这会将abc计分板的显示名称更改为分数
除了显示名称,你还可以修改渲染类型。简单来说就是,怎么表示你的得分数?
我们目前只有两种选择:使用爱心或是数字:
- /scoreboard objectives modify <记分板ID> rendertype (hearts|integer)
复制代码
比如:
- /scoreboard objectives modify hp rendertype hearts
复制代码
这条指令会使用爱心来显示abc的分数:
我的分数会以“心”的方式被显示:每一分是半颗心。但由于这个计分板的计分方式就是“生命值”,有多少血就是几分,所以上方显示的就是我的生命值。(这段有点绕口哈)
除了正常生命值,它同样可以显示伤害吸收的金心。
3. 删除
你可以使用/scoreboard objectives remove 来移除一个计分板:
- /scoreboard objectives remove <计分板ID>
复制代码 例:
- /scoreboard objectives remove abc
复制代码 本指令会把刚才创建的计分板abc移除。
显示
各位看到这里可能有个疑问:我们在地图里看到的计分板里明明是被显示在一边的啊,如何显示一个记分板?
你要使用的子指令名叫“setdisplay”,翻译过来就是“设置显示”:
- /scoreboard objectives setdisplay <槽位> [记分板ID]
复制代码 什么是“<槽位>”?这是说,你要把分数显示在哪里?
你有3个基本选项:sidebar,list,与belowname。
sidebar就是最常见的“显示在屏幕右侧”:
- /scoreboard objectives setdisplay sidebar abc
复制代码 这会将计分板abc的分数显示在屏幕右侧,效果是这样的:
在上一帖中,我把自己加入了蓝队,所以你可以注意到我的ID是蓝色的。计分板总会把玩家ID更改为他队伍的颜色。
除了sidebar以外,你还可以使用list,即“显示在tab键里”。
- /scoreboard objectives setdisplay list hp
复制代码 将一个ID为“hp”的计分板显示在list槽位。
按下tab就可以看到:
(本图片来自Minecraft Wiki 关于/scoreboard的条目)
最后是belowName,也就是显示在姓名下方:
除了这些,sidebar还有“只为特定队伍显示”的选项:
- /scoreboard objectives setdisplay sidebar.team.<color> abc
复制代码 (如果你忘了什么是/team,回去看第四帖)
将“<color>”替换为一种颜色,就只会向拥有特定颜色的队伍中的玩家显示本计分板——因为虽然可以创建无数个队伍,但颜色只有十六种,所以从某种角度来讲,我们最多只能创建16支队伍。
例:
- /scoreboard objectives setdisplay sidebar.team.red abc
复制代码 红队(red)玩家可以在屏幕右侧看到abc计分板。
注意,一个位置上只能有一个计分板,且sidebar与sidebar.team.<color>冲突。
同样注意,基岩版没有设定特定队伍显示的选项,只有基础的三种选择。
现在,回去看我们有关显示设定的指令格式,你会发现[记分板ID]是一个可选元素。如果你不填写这个元素,指令将会清空这个位置:
- /scoreboard objectives setdisplay sidebar
复制代码 将槽位sidebar清空。
那好,现在,你创立了一个计分板,并输入了让其显示在屏幕右侧的指令——但你会发现,该计分板没有出现在右侧。
为什么呢?
因为上面没分。你的计分板是空的。接下来要讲的,就是如何对分数修改,运算。
管理分数
现在,假设我们有一个"dummy"(虚拟型)记分板ID为test(即"测试")
这个计分板的准则是"dummy",是不会因为任何原因自动加分的。
想要修改它的分数,只能使用指令。
这里,我们就涉及到/scoreboard的另一个子指令“/scoreboard players”。这个子指令专门用于管理分数。
当你创建一个计分板时,上面是没有分数的。注意这不是说分数为零,而是说分数是“空”,连0都没有。这种空的计分板,即使使用了刚才讲过的设置显示的指令,在他拥有分数之前是不会显示的。
那么现在,你有三种直接更改分数的方法:加分(add),减分(remove),与设置(set):
- /scoreboard players (add|remove|set) <目标> <计分板ID> <值>
复制代码 该指令会将<目标>在计分板:“<计分板ID>” 上的分数增加/减少/设置为<值>。
不难理解:
- /scoreboard players remove Dahesor test 10
复制代码 这条指令会把我(Dahesor)在计分板"test"上的分数减少10。
- /scoreboard players add @a abc 3
复制代码 这条指令会把所有玩家(@a)在计分板'abc"上的分数增加3。
注意,如果在运行这条指令前<目标>的分数为空,也就是最开始的情况,那么当你使用:"add"或者"remove"时,将从零开始算。
注意,即使有一个运作的准则,比如“每扔出一根木棍加一分”而不是"dummy",你仍可以使用指令修改分数。但对于“是否获得某个进度”这种要么是1要么是0(要么是真要么是假)的计分板,虽然可以更改分数,但一旦该进度被更新(玩家完成或使用指令剥夺/给予进度),分数就会回到1或0。
注意,会实时更新的准则,比如“生命值”之类,是不能修改的。因为个计分板的分数每时每刻都会更改为你目前的生命值,所以更改也没用。同样,这些计分板一旦创建就会在下一次更新时获得玩家的分数,也不存在分数为“空”的状况。(在本情况下,“下一次更新”是指你受伤或回血导致生命值更改的时候。)
而:
- /scoreboard players set @e test 5
复制代码 会把所有实体(@e)在计分板"test"上的分数设为5。
是的,实体也是可以在计分板上拥有分数的。
本指令会把所有玩家,村民,僵尸,其他生物,抑或是飞行中的火球,掉落的经验球这些实体在计分板abc上的分数均设为5分。
啊啊,不止可以设置实体的分数哦,你还可以使用“虚拟目标”。就是在计分板上添加一个不存在的目标的分数:
- /scoreboard players set tp test 5
复制代码 我这是单人游戏,名叫“tp”的玩家并不存在,但我还是可以添加它到计分板上。
这说明了什么?
你可以将一个数字保存在计分板,你可以使用变量啦!
有啥用?
呼,自己想。这里只教指令本身。
我相信,也不得不相信,MInecraft与Minecraft玩家的可能性。(这毕竟是我写教程的目的。)
如果你想要将某人的分数恢复成一开始的“啥都没有”的状态,请执行:
- /scoreboard players reset <目标> [计分板ID]
复制代码 这会清除<目标>在 特定计分板<计分板ID>上的分数。
注意“[计分板ID]”是一个可选元素——如果你不指定计分板ID,<目标>在任何(能被更改的)计分板上的分数都会被清除。
获取分数
还记得记分板显示的“槽位”吗?
槽位并不多,不算队伍类,就只有3个而已,你也只能直接获取3个计分板的分数罢了
那么,如何得到其他记分板的分数呢?
你可以使用:
- /scoreboard players get <目标> <记分板ID>
复制代码 这条指令会给出<目标>在特定计分板“<记分板ID>”上的分数。
那现在好了,如果你连“谁在哪里有没有分”这种问题都不知道了,你可以使用list:
- /scoreboard players list [目标]
复制代码 本指令会显示<目标>在所有计分板上的分数。
你可以发现[目标]是一个可选元素。所以如果你省略“目标”:
本指令会列出所有在任意记分板上有分数的实体。
你也可以在“<目标>”中填“*”。
这和不填的效果是一样的,都会列出所有在任意记分板上有分数的实体:
- /scoreboard players list *
复制代码
运算
最后,让我们看向今天最后一项内容,也是任何编程语言的核心之一:运算。
/scoreboard players operation命令允许你对两个数字作数学或逻辑运算。你可以将一个分数加到另一个分数上,也可以做“取最小值”这样的逻辑运算,是以后数据包等高端内容的核心之一。
格式:
- /scoreboard players operation <目标> <目标计分板ID> <操作> <来源> <来源计分板ID>
复制代码
解析:
/soreboard players opertaion 指令头>子指令>更下级子指令:计分板,分数操作,运算
<目标> <目标计分板ID> 被运算的分数,也就是数学说的“被减数”或“被除数”,比如“Dahesor abc” 即为我(Dahesor)在记分板abc上的分数。
<操作> 你要干嘛?要加要减要乘要除?
<来源> <来源计分板ID> 这是来源分数,也就是数学说的“减数”或“除数”,和目标分数是一个写法。
有哪些操作?
目前,你一共有9种不同的选择器:
运算符 | 运算名称 | 描述 | = | 赋值 | 把目标的分数设为来源的分数。 | +=
| 加法 | 把来源的分数加到目标分数上。 | -= | 减法 | 在目标分数上减去来源的分数。 | *= | 乘法 | 将目标分数设为目标分数与来源分数的乘积。 | /= | 除法 | 将目标分数设为被来源的分数除后的结果。 | %= | 求余 | 将目标分数设为被来源的分数除后得到的余数。 | < | 取较小值 | 如果来源分数比目标分数小,则把目标分数设为来源分数。 | > | 取较大值 | 取较大值:如果来源分数比目标分数大,则把目标分数设为来源分数。 | >< | 交换 | 将来源分数与目标分数交换。 |
注意,在所有的9种运算中,只有最后一种交换会改变来源分数。
记分板无法存储小数,当使用除法出现小数是会向下取整。
例:
- /scoreboard players operation Dahesor a *= MysticNebula70 b
复制代码
将Dahesor在a计分板上的分数设定与MysticNebula70在b记分板上的乘积。
若原值:Dahesor a = 3,MysticNebula70 b = 10,
那么结束后:Dahesor a = 30,MysticNebula70 b = 10。
- /scoreboard players operation Dahesor money += @a money
复制代码
将Dahesor在money计分板上的分数增加所有玩家在money记分板上的分数。
若原值:Dahesor money = 10,玩家1 money = 5,玩家2 money = 15
结果为:Dahesor money = 10+5+15+10=40(Dahesor也是玩家之一,玩家也包含我,所以还要加上自己的分数),玩家1 money = 5,玩家2 money = 15
- /scoreboard players operation @r x >< Dianliang233 y
复制代码
将一名随机玩家在x计分板上的分数与Dianliang233在y计分板上的分数交换。
若原值:随机玩家 x = 0,Dianliang233 y = 10,
结果为:随机玩家 x = 10,Dianliang233 y = 0。
(Dianliang233是MCWiki“最年轻的编辑者”(那是段很有趣的故事))
再次提醒,“><”是唯一一个会改变来源分数的运算。
还有一件有趣的事是,这里,你可以使用"*"填在<目标> 或 <来源>(但不能同时)中用以代表在任意计分板上有分数的实体(包括虚拟分数)。
下面的内容可能有些复杂,你可以跳过,几乎不会有影响,下面的东西也很少用到。
让我们举几个带“*”的例子。
比如说:
- /scoreboard players operation * x = Dahesor y
复制代码 将所有在任意计分板上有分数的实体(包括虚拟目标)在x计分板上的分数设为Dahesor在y计分板上的分数。
若原值:
x计分板:a有4分,b有3分。
y计分板:Dahesor有10分。
z计分板:c有500分,d有24分。
那么,运算结束后:
x计分板:a有10分,b有10分,c有10分,d有10分,Dahesor有10分。
y计分板:Dahesor有10分。
z计分板:c有500分,d有24分。
你看,z计分板在指令中完全没有被指令提及,但是,只要在任意计分板上有分数,就会被“*”选中。
例2:
- /scoreboard players operation Dahesor x = * y
复制代码 这会将Dahesor在x计分板上的分数依次设置为所有在计分板上有分数的对象在y计分板上的分数。
若原值:
x计分板:Dahesor只有0分。
y计分板:a有5分,b有10分。
那么,运算结束后:
y计分板不变,Dahesor在x计分板上的分数——还是0分。
为什么?
因为Dahesor的分数会依次被赋值为“所有在任意计分板上有分数的对象在y计分板上的分数”。
我们是一个接一个地“赋值”,所以说哪个分数在最后,Dahesor就会变成哪个分数。
在同一计分板上分数从高到低排列。
谁在y计分板上的分数最低呢?
是Dahesor,分数为0(空的)。
所以,Dahesor在x计分板上的零蛋被赋值为Dahesor在y计分板上的零蛋————还是零蛋。
例3:
- /scoreboard players operation Dahesor x *= * y
复制代码 本指令的含义为,将Dahesor在x计分板上的分数乘以所有“在任意计分板上有分数的对象的分数”。
若原值:
x计分板:
Dahesor有2分。
y计分板:
a有3分,b有8分,Dahesor有5分。
没有其他计分板。
那么,运算后,Dahesor在x计分板上的分数为:
等于240分。
注意,在本例中,只要要有任意一个对象在y计分板上的分数等于0,那么最后Dahesor的分数都会变成零——因为无论什么数,乘以0都等于0。
以上就是本帖的全部内容了。
......实际上,还有一个子指令enable还没讲到。记得前面跳过的准则“trigger”么?这是和那相关的。本子指令会在以后讲/trigger时详细提到。
结束了呢,开心开心,又可以放假了,回到水论坛和泡Bilibili的时光了。
本帖本来是打算和上一帖一起发布的,但中间遇到了很多麻烦,连本帖都是经历了断网和断电一系列麻烦才发出的。
那,期待后续的就收藏一下好吧......还有我终于快拿到小麦种子勋章了(好感动)。
附录
#更新日志
Java 1.16.5/a 页面发布,版本1.16.5
Java 1.16.5/b 感谢种拔的提醒,加入了关于除法余数的问题
Java 1.16.5/c 前往1.12版本教程的帖子因过久而被锁定,加入了新的链接
Java 1.16.5/d 根据Wiki命令:语法,更改了命令语法、
Java 1.16.5/e 补充了大量对“*”的说明。
Java 1.17/a 1.17版本升级完成
Java 1.18/a 1.18版本升级完成
上一帖:[命令] 有关队伍/team 命令教程“真”从零开始 (四)
系列《命令教程“真”从零开始》
前往来自 麻瓜草稿簿 的 系列教程索引
下一篇:[命令] /tag指令,与进阶~选择器参数 命令教程“真”从零开始 (六)
|