第二十六章 更加精確的目標(biāo)選擇器 下
——游戲模式——
用游戲模式篩選玩家的參數(shù),在Java1.13及以上版本中是gamemode,在基巖版以及低于Java1.13的版本均為m。
那么它們是怎么用的呢?
眾所周知,基巖版服務(wù)器并沒(méi)有像Java版服務(wù)器一樣具有出生點(diǎn)保護(hù),所以在基巖版,要讓服務(wù)器主城不被惡意破壞,最基本的操作就是使用『范圍冒險(xiǎn)模式』。比如這個(gè)中國(guó)版租貸服最初就用了如下指令:
/gamemode a @a[x=726,y=89,z=-263,r=50]
重復(fù)執(zhí)行這條指令,就可以讓主城范圍50格內(nèi)的所有玩家都改為冒險(xiǎn)模式。但這有個(gè)缺點(diǎn):腐竹也被改為冒險(xiǎn)模式了。為了解決這個(gè)問(wèn)題,這個(gè)腐竹給該目標(biāo)選擇器添加了一個(gè)參數(shù),變成:
/gamemode a @a[x=726,y=89,z=-263,r=50,m=s]
這條指令和上一條指令的唯一區(qū)別就在于,它不會(huì)將不是生存模式的玩家改為冒險(xiǎn)模式,這樣子腐竹開著創(chuàng)造就不會(huì)受到影響了。其中新添加的m參數(shù),值是s,也就是survival(生存)的縮寫。
m參數(shù)可以使用游戲模式的全稱,縮寫和數(shù)字ID。比如:
/tp @a[r=20,m=6]^^^-100(僅適用于基巖版)
這條指令的作用是:將以基準(zhǔn)點(diǎn)(在這是指令執(zhí)行位置)為中心,半徑20格內(nèi)的所有處于旁觀模式的玩家,全都傳送到執(zhí)行者背后100米處(^^^-100為局部坐標(biāo),會(huì)在第五十九章講到?!?』在這是基巖版1.19及以上版本為實(shí)驗(yàn)玩法的旁觀者模式的數(shù)字ID。沒(méi)錯(cuò),基巖版也有旁觀者模式了,只不過(guò)在測(cè)試而已)
而gamemode參數(shù).......在Java1.13版本中,Mojang重寫了大量游戲基礎(chǔ)代碼,導(dǎo)致Java1.12.2和1.13版本中,許多游戲內(nèi)容差異極大。所以在之前的章節(jié)中,你會(huì)發(fā)現(xiàn)許多指令都在Java1.13更新中發(fā)生了大改,這種情況在以后的章節(jié)中也會(huì)持續(xù)存在。游戲模式也一樣,在Java1.13版本更新后,游戲模式就僅支持全稱,即:
survival(生存模式)、creative(創(chuàng)造模式)、adventure(冒險(xiǎn)模式)和spectator(旁觀模式)。
所以,雖然gamemode參數(shù)和m用法一樣,但它僅支持上面四個(gè)值。
現(xiàn)在我們知道如何選擇特定游戲模式的玩家。但如果我們要反過(guò)來(lái),排除特定模式的玩家該怎么辦?
這位腐竹造了一個(gè)房子。為了防止他的房子被破壞,就做了一個(gè)簡(jiǎn)易的安保措施:
/kill @a[r=15,m=!c]
這條指令的意思是:將范圍15格內(nèi)所有不處于創(chuàng)造模式的玩家全部殺死。
仔細(xì)觀察這條指令,你發(fā)現(xiàn)了什么?
沒(méi)錯(cuò),m參數(shù)要反過(guò)來(lái)排除特定模式的玩家,只需要在值前面加一個(gè)英文半角感嘆號(hào)。和m參數(shù)一樣,gamemode參數(shù)也同理:
/kill @a[distance=..15,gamemode=!creative]
感嘆號(hào)的這種用法,其實(shí)就是不等號(hào)在計(jì)算機(jī)語(yǔ)言中的常見形式(=!)。這種不等號(hào)反轉(zhuǎn)選擇的用法在接下來(lái)幾個(gè)目標(biāo)選擇器參數(shù)中也會(huì)頻繁出現(xiàn)。
——目標(biāo)名稱——
name參數(shù)可以用于選取指定名稱的實(shí)體。
使用/give給予某位特定玩家物品時(shí),一般不會(huì)用到目標(biāo)選擇器,而是直接指定該玩家的玩家名(不會(huì)吧,不會(huì)吧,不會(huì)真的有人會(huì)用玩家的UUID來(lái)使用/give指令吧)。
但如果要用目標(biāo)選擇器,還要鎖定這名玩家該怎么辦?
舉個(gè)例子:
/give @a[name=JIE灬揮刀亂砍] Skyward_Blade
這樣子就可以鎖定這名玩家并給予物品了。
name參數(shù)不光可以用于玩家名上,還可以用于實(shí)體名上。
比如某位Java腐竹為了實(shí)現(xiàn)將寶箱隨機(jī)放在世界各處,用了如下指令:
/summon minecraft:armor_stand ~~~{CustomName:“\“A\““}
\\召喚一個(gè)名為A的盔甲架\\
/spreadplayers ~~ 32 10000 false @e[type=minecraft:armor_stand,name=A]
\\將所有名為A的盔甲架隨機(jī)傳送到以該命令方塊為中心的20001×20001范圍內(nèi),且每個(gè)盔甲架間距不小于32格,不考慮盔甲架的隊(duì)伍屬性\\
/execute as @e[type=minecraft:armor_stand,name=A] at @s run ......(后面省略)
\\將執(zhí)行者、執(zhí)行位置和旋轉(zhuǎn)角度都設(shè)定為名為A的盔甲架,并運(yùn)行.....\\
可以發(fā)現(xiàn),該腐竹為了防止執(zhí)行指令時(shí)和其他實(shí)體發(fā)生沖突,特別使用了名叫A的盔甲架并用name參數(shù)鎖定。同時(shí),這位腐竹還用到了type參數(shù)。關(guān)于這個(gè)參數(shù)待會(huì)會(huì)講到。
name參數(shù)也可以像m、gamemode參數(shù)一樣,使用感嘆號(hào)反轉(zhuǎn)為排除指定名稱的實(shí)體,比如:
/kill @e[name=!A]
這條指令的作用就是:殺死名字不是A的實(shí)體。
需要注意一點(diǎn),如果名字中包含空格,需要用雙引號(hào)括起。比如:
/kill @e[name=“genshin impact“]
——垂直旋轉(zhuǎn)角度——
——水平旋轉(zhuǎn)角度——
還記得第九章的/tp嗎?我們就在那第一次接觸到了垂直旋轉(zhuǎn)角度和水平旋轉(zhuǎn)角度:
這兩個(gè)由于是同類,本書就合起來(lái)講了。
在Java1.13及以上版本中,垂直旋轉(zhuǎn)角度參數(shù)是x_rotation,水平旋轉(zhuǎn)角度參數(shù)是y_rotation。在Java1.13以下和基巖版中,兩類角度分別是rx、rxm和ry、rym。
唉,你發(fā)現(xiàn)了沒(méi)有?這和我們之前了解過(guò)的經(jīng)驗(yàn)參數(shù)(l、lm和level)還有距離參數(shù)(r、rm和distance)差不多。那么格式是不是也是一樣呢?
還真是一樣的。既然格式一樣,這里就不多說(shuō)它的格式了。
rx、ry參數(shù)的作用是:選取垂直、水平旋轉(zhuǎn)角度小于等于RX或RY的實(shí)體
rxm、rym參數(shù)的作用是:選取垂直、水平旋轉(zhuǎn)角度大于等于RXM或RYM的實(shí)體
垂直旋轉(zhuǎn)角度其范圍是:90度(看地上)到-90度(看天空)。
水平旋轉(zhuǎn)角度其范圍是:-180度(北)到180度(還是北),或者說(shuō)是上北-180°,下南0°。左西90°,右東-90°。
等等,我們?cè)谥vtp時(shí),不是說(shuō)水平旋轉(zhuǎn)角度是:『以實(shí)體為中心,以正南(z軸正方向)為0°,順時(shí)針下來(lái),實(shí)體朝向和正南方向的夾角(也或者說(shuō)實(shí)體在真南方位角體系中朝向的角度),就是該實(shí)體的水平旋轉(zhuǎn)角度?!?p> 那這怎么跑出來(lái)負(fù)數(shù)了?
其實(shí)在Minecraft中,水平旋轉(zhuǎn)角度雖然可以像我們之前在第九章講tp時(shí)那么用,但大多數(shù)時(shí)候,你都得這么用:
以正南(z軸正方向)為0°,順時(shí)針旋轉(zhuǎn)180°通過(guò)正西至正北,用正數(shù),逆時(shí)針旋轉(zhuǎn)180°通過(guò)正東至正北,用負(fù)數(shù)。比如-45°,就代表以正南為基準(zhǔn),逆時(shí)針旋轉(zhuǎn)45°的方向;30°,就代表以正南為基準(zhǔn),順時(shí)針旋轉(zhuǎn)30°的方向。
也就是說(shuō),在Minecraft中,水平旋轉(zhuǎn)角度的正確范圍是-180°~180°,而不是0°~360°。至于為什么我要在第九章那么講,只是怕一下子就把負(fù)數(shù)搬出來(lái)會(huì)嚇你們一跳。
現(xiàn)在我們回到正題。
舉個(gè)例子。某網(wǎng)易手機(jī)租貸服為了讓玩家回城方便,搞了一個(gè)“回城雪球”,其指令如下:
A→B→C→
A:重復(fù),無(wú)條件,始終活動(dòng)
/execute @e[type=snowball]~~~ execute @p[r=1.5,rx=90,rxm=60]~~~ execute @e[type=snowball,c=1]~~~ tag @s add back_home
\\選取雪球作為指令執(zhí)行者,再以這個(gè)雪球?yàn)橹行膶ふ野霃?.5格內(nèi)最近的低著頭(頭自水平線向下90°到向下60°)的玩家。如果找到,再以該玩家為中心尋找最靠近他的雪球,并給這個(gè)雪球賦予back_home標(biāo)簽。\\
B:連鎖,有條件的,始終活動(dòng)
/execute @e[type=snowball,tag=back_home]~~~ tp @p[r=1.5] 323 65 72
\\選取具有back_home標(biāo)簽的雪球,并以它為中心將半徑1.5格內(nèi)最靠近它的玩家傳送到(323,65,72)。\\
C:連鎖,有條件的,始終活動(dòng)
/kill @e[type=snowball,tag=back_home]
\\清除所有具有back_home標(biāo)簽的雪球\\
其中就有用到rx和rxm參數(shù),用于篩選那些低著頭扔雪球的玩家。
至于其中出現(xiàn)的tag參數(shù),我們?cè)谏弦徽乱呀?jīng)略過(guò)了。關(guān)于tag會(huì)在以后講到計(jì)分板時(shí)提到。
ry和rym參數(shù)目前來(lái)說(shuō)沒(méi)有特別廣的用途,只能舉個(gè)沒(méi)啥用的例子:
/kill @a[ry=180,rym=-180]
這條指令可以殺死所有面向正北的玩家(神奇的是這并不會(huì)框選住所有活著的玩家,@a[ry=180,rym=179]才會(huì)框選住幾乎所有活著的玩家)
至于x_rotation和y_rotation參數(shù),你應(yīng)該知道怎么用了吧?
@a[x_rotation=35..]——所有頭水平線朝下35°及以上的玩家
@a[x_rotation=..35]——所有頭沒(méi)有水平線朝下35°以上的玩家
@a[x_rotation=0..35]——所有頭水平線朝下0到35°(含)的玩家
@a[x_rotation=35]——所有頭水平線朝下35°的玩家
@a[y_rotation =60..]——所有朝向是在南偏西60°順時(shí)針到正北這個(gè)范圍內(nèi)的玩家
@a[y_rotation =..60]——所有朝向是在南偏西60°逆時(shí)針到正北這個(gè)范圍內(nèi)的玩家
@a[y_rotation =60..120]——所有朝向是在南偏西60°順時(shí)針到北偏西60°這個(gè)范圍內(nèi)的玩家
@a[y_rotation =60]——所有朝著南偏西60°的玩家
——實(shí)體類型——
實(shí)體類型是type,上面我們已經(jīng)見過(guò)了。
type和name本質(zhì)上是差不多的,但是它篩選不是通過(guò)名字,而是通過(guò)實(shí)體種類。
什么是實(shí)體種類?比如一個(gè)玩家叫Notch,另一個(gè)玩家叫Herobrine,雖然名字不同,但他們都是『玩家』種類的。又比如這里有一只馬,那里有一只叫馬的驢,雖然它們都叫馬,但前者是馬,后者是驢,并不是一個(gè)種類的。
type可以選定指定類型的實(shí)體,比如:
/kill @e[type=minecraft:villager]
就可以殺死全部已生成的村民。
type一般來(lái)說(shuō)僅用于@e,因?yàn)橹挥蠤e是包含非玩家實(shí)體的。在Java1.13以下和基巖版中,你也可以用在@r中來(lái)隨機(jī)選擇特定類型的實(shí)體。
和name一樣,type也支持感嘆號(hào)反轉(zhuǎn):
/kill @e[type=!player]
這條指令的作用是:殺死所有非玩家實(shí)體。
需要注意的是,name和type這兩個(gè)參數(shù)在非感嘆號(hào)反轉(zhuǎn)的情況下都是不可重疊的,比如:
@e[type=cow,type=player]
像上面那樣是不可以的,Minecraft中可沒(méi)有既是牛又是玩家的動(dòng)物。如果真有,那么也應(yīng)該合并成為一個(gè)新的實(shí)體,也許會(huì)叫作cow_player(牛人)呢。
——實(shí)體家族——
我們知道通過(guò)type可以選取特定類型的實(shí)體。但如果我們要選取一堆不同類型的實(shí)體用于執(zhí)行同一種指令呢?
記分板、NBT和標(biāo)簽可以很好的解決這個(gè)問(wèn)題。但在了解這三個(gè)東西之前,我們暫且沒(méi)有除多弄命令方塊以外的更好的辦法。
Mojang估計(jì)看我們這么可憐,于是在基巖版1.16.100中,加入了family參數(shù)。
family參數(shù)和type參數(shù)差不多,只不過(guò)它是通過(guò)實(shí)體家族篩選的。
什么是實(shí)體家族?
舉個(gè)例子:
僵尸知道吧?僵尸一般來(lái)說(shuō)有三類變種:
尸殼、僵尸村民、溺尸
雖然它們客觀上并不屬于同一種實(shí)體,但主觀上我們?nèi)匀粫?huì)將它們歸類到一個(gè)大類:僵尸類。
用Mojang的說(shuō)法,它們都是屬于同一個(gè)族(family)的。
現(xiàn)在你應(yīng)該知道實(shí)體家族到底是什么了吧?
舉個(gè)例子:
/tp @e[family=creeper]@s
這條指令的作用是:將所有屬于苦力怕家族的實(shí)體傳送到自己身旁。
當(dāng)然,你也可以使用感嘆號(hào)將作用反轉(zhuǎn)。需要注意,和type、name參數(shù)不同的是,family參數(shù)在非反轉(zhuǎn)情況下也是可以疊加使用的,因?yàn)橛行?shí)體可能會(huì)屬于多個(gè)族。
你可以在Minecraft Wiki上搜索『族』詞條來(lái)查看原版所有可用的實(shí)體家族。
——物品——
我們知道,在Java版中,如果要篩選具有指定物品的實(shí)體,可以使用NBT或/clear。那在基巖版中該怎么辦?使用/replaceitem或/clear嗎?
這的確是兩種可行的方法,但Mojang還給了我們第三個(gè)方法:
hasitem目標(biāo)選擇器參數(shù)
這個(gè)參數(shù)可能會(huì)比較復(fù)雜,因此在了解這個(gè)參數(shù)之前,我們得先了解一下:背包中的物品
背包具有很多個(gè)物品欄,每個(gè)物品欄具有多個(gè)欄位,欄位儲(chǔ)存著物品。因此,每個(gè)放在背包中的物品都具有欄位標(biāo)簽。物品有很多個(gè)種類,因此,物品還具有id標(biāo)簽。大部分類型的物品可以堆疊,因此,物品還具有數(shù)量標(biāo)簽。在Java1.13以下版本和基巖版中,同id的物品也可能不同,因此,物品在這些版本中還具有數(shù)據(jù)值標(biāo)簽。
hasitem參數(shù)可以用來(lái)選取具有指定物品的實(shí)體。更準(zhǔn)確一點(diǎn)來(lái)說(shuō),hasitem參數(shù)可以通過(guò)檢測(cè)已選實(shí)體的背包中指定條件下的物品,來(lái)篩選實(shí)體。
hasitem參數(shù)的值比較特別,它的值可以是單個(gè)條件,也可以是由多個(gè)條件組成的條件列表。讓我們來(lái)看看hasitem參數(shù)的一個(gè)條件項(xiàng)目到底可以指定哪些東西。
一個(gè)條件項(xiàng)目可以檢測(cè)單個(gè)類型的物品,具體來(lái)說(shuō)可以指定以下的參數(shù):
item——物品id
data——物品的數(shù)據(jù)值[可選]
quantity——限制所選范圍內(nèi)物品的總數(shù)量[可選]
location——需要檢測(cè)的物品欄[可選]
slot——需要檢測(cè)的槽位[可選,必須配合location參數(shù)使用]
比如:
{item=bed,data=1}
這個(gè)條件可以篩選背包內(nèi)具有橙色床的實(shí)體。不難發(fā)現(xiàn),單個(gè)條件可以具有多個(gè)不同的篩選參數(shù),并且外面要使用花括號(hào)({})包裹起來(lái)。
需要注意的是,data參數(shù)目前有個(gè)BUG,就是不能適用于方塊類物品。如果你對(duì)一個(gè)方塊類物品使用了data參數(shù),那么不管你怎么改data的值,游戲總會(huì)認(rèn)為該參數(shù)的值為0。怎么判斷一個(gè)物品是不是方塊類的呢?看物品的圖標(biāo)。如果圖標(biāo)是直接給出了方塊的3D圖像(也就是渲染圖),比如羊毛,那就是方塊類物品。像是床這種圖標(biāo)是專門畫的就不是方塊類物品,所以能夠正常使用data參數(shù)。
quantity參數(shù)得好好講一講,它并不是說(shuō)檢測(cè)單個(gè)欄位內(nèi)物品的數(shù)量,而是檢測(cè)整個(gè)范圍內(nèi)的指定類型物品數(shù)量總和。比如:
{item=dirt,quantity=100..}
這個(gè)條件可以選擇到那些背包內(nèi)泥土數(shù)量達(dá)到甚至超過(guò)100塊的實(shí)體。也就是說(shuō),假設(shè)這里有一個(gè)張三,背包內(nèi)有兩組泥土,那么這個(gè)條件就可以選擇到它。
不難發(fā)現(xiàn),quantity的值簡(jiǎn)直是基巖版的一股清流,竟然向Java1.13及以上的版本學(xué)習(xí),采用了Java版先進(jìn)的『兩點(diǎn)法』,不錯(cuò)不錯(cuò),值得表?yè)P(yáng)。而且,這參數(shù)還在Java版的基礎(chǔ)上改造了一下,變成了還可以使用不等號(hào)進(jìn)行反選:
{item=dirt,quantity=!100..}
這將會(huì)選取擁有泥土數(shù)量<100的實(shí)體。
對(duì)了,如果你指定了這個(gè)參數(shù)為0,那就可以選擇『沒(méi)有指定物品的實(shí)體』:
{item=dirt,quantity=0}
這將會(huì)選取背包內(nèi)沒(méi)有泥土的實(shí)體。
location參數(shù)可以縮小檢測(cè)的范圍到指定的物品欄。具體可以使用哪些物品欄以及這里的物品欄是個(gè)啥東西.....這就需要你前往第三十八章了解/replaceitem指令。
這里就先假裝你已經(jīng)搞懂了這些內(nèi)容。舉個(gè)例子:
{item=dirt,quantity=0,location=slot.enderchest}
這將會(huì)選取所有在其末影箱內(nèi)沒(méi)有泥土的實(shí)體。需要注意,對(duì)于玩家來(lái)說(shuō),默認(rèn)是不會(huì)檢測(cè)到末影箱的。也就是說(shuō),如果你在末影箱內(nèi)放了一塊泥土,那么{item=dirt,quantity=0}這個(gè)條件還是會(huì)選擇到你,但{item=dirt,quantity=0,location=slot.enderchest}這個(gè)條件則不會(huì)。另外,即使是對(duì)于沒(méi)有末影箱的非玩家實(shí)體,游戲仍然會(huì)假裝其具有末影箱,然后又因?yàn)橛螒蚣傺b出來(lái)的末影箱內(nèi)沒(méi)有泥土,導(dǎo)致上述條件也會(huì)選擇到非玩家實(shí)體。
在使用location參數(shù)時(shí),還可以更進(jìn)一步使用slot參數(shù)來(lái)縮小檢測(cè)范圍到指定的欄位。比如:
{item=dirt,quantity=1..,location=slot.enderchest,slot=0}
這將會(huì)選取到所有在其末影箱左上角第一格內(nèi)放有泥土的玩家。和quantity一樣,這參數(shù)同樣也支持升級(jí)后的『兩點(diǎn)法』:
{item=dirt,quantity=1..,location=slot.enderchest,slot=1..}
\\選取到所有在其末影箱內(nèi)除了左上角第一格外其他位置放有泥土的玩家\\
{item=dirt,quantity=1..,location=slot.enderchest,slot=!0}
\\同上\\
上面這些都是一個(gè)條件內(nèi)可以弄的參數(shù),hasitem參數(shù)的值也確實(shí)可以直接放入單個(gè)條件:
/testfor @a[hasitem={item=dirt,quantity=1..,location=slot.enderchest,slot=!0}]
但是如果要多個(gè)條件呢?這時(shí)候就需要用到列表:
@a[hasitem=[{item=dirt},{item=apple}]]
這將會(huì)選擇到背包內(nèi)同時(shí)具有泥土和蘋果的玩家。
不難發(fā)現(xiàn),在多個(gè)條件組成的列表中,每個(gè)條件也是使用逗號(hào)分開,列表最外側(cè)被中括號(hào)([])包起來(lái)。
這就是hasitem參數(shù)的具體使用方法,其中部分內(nèi)容超綱了一些,但總體上還是易于理解的。
——NBT——
——進(jìn)度——
——謂詞——
上面這三個(gè)均為Java版獨(dú)有,且我們還未接觸到,暫時(shí)先留個(gè)坑,以后再填。
附錄:目標(biāo)選擇器發(fā)展歷史
Java
1.4.2——加入目標(biāo)選擇器,最初只有@a、@r、@p三個(gè)變量
1.8——加入了@e變量和dx、dy、dz參數(shù)
1.9——m參數(shù)現(xiàn)在接受游戲模式全稱和縮寫,在此版本之前只支持?jǐn)?shù)字ID。并加入了tag參數(shù)。
1.11——移除了隱含目標(biāo)選擇器(如@a[26,65,-28],代表@a[x=26,y=65,z=-28]),并且錯(cuò)誤的目標(biāo)選擇器不再略過(guò),而是會(huì)報(bào)錯(cuò)。
1.12——加入了@s變量
1.13——加入了NBT和進(jìn)度advancements參數(shù),并對(duì)原本的參數(shù)進(jìn)行大改
1.15——加入了謂詞predicate
基巖版
1.16.100——加入了family參數(shù)
1.17.10——加入@initiator變量用于NPC
1.18.30——加入了hasitem參數(shù)
?。ㄗⅲ壕W(wǎng)易版我的世界截止目前[2022.8.3]僅僅更新到1.18.10版本,因此沒(méi)有hasitem參數(shù))