《我的世界》1.12版本新增了函數命令這一內容,很多玩家覺得非常復雜,也有玩家發(fā)現這個命令可以完全脫離命令方塊而存在,那么下面小編就為大家?guī)怼段业氖澜纭?.12函數命令系統(tǒng)入門教程,告訴大家函數命令...

《我的世界》1.12版本新增了函數命令這一內容,很多玩家覺得非常復雜,也有玩家發(fā)現這個命令可以完全脫離命令方塊而存在,那么下面小編就為大家?guī)怼段业氖澜纭?.12函數命令系統(tǒng)入門教程,告訴大家函數命令怎么用,希望大家喜歡。

寫在前面的話

1.9的更新為我們帶來了三色命令方塊,讓命令方塊脫離了紅石成為獨立的體系,我們因此可以更好實現一些想法;時隔3個版本,MOJANG再次為我們帶來驚人的變革。

1.12中,函數與進度系統(tǒng)的出現,讓命令脫離命令方塊——這句曾經說過的玩笑般的預言,正式成為可能。

《我的世界》1.12函數命令系統(tǒng)入門教程 函數命令怎么用

函數系統(tǒng)的構成

函數系統(tǒng)的由來

函數(function)系統(tǒng),是 MC 1.12 Pre-1 版本中新增的一個功能,它將原來進度系統(tǒng)中返回指令的部分單獨提取出來,做成了現在的函數系統(tǒng)。

函數系統(tǒng)的形式

函數系統(tǒng)由命名空間函數文件組成,這些文件保存在存檔目錄/data/functions/下。functions目錄下的文件夾,稱為命名空間,各個命名空間下存放不同的函數文件。實際上,命名空間就是方便我們編寫者分類并管理各種函數文件。

函數文件是以.mcfunction為后綴名的文本文件,建議采用utf-8無BOM編碼以防顯示錯亂。簡單來講,一個函數等價于一個多行命令方塊,函數文件里面每一行寫一條指令,當執(zhí)行這個函數時,里面的指令會按行依次執(zhí)行。如果在一個函數中調用其它函數,那么在同一游戲刻,被調用的函數中所有指令先執(zhí)行完,再繼續(xù)當前函數中后續(xù)的指令,就像插隊一樣,我們在后面對比命令方塊時還會說到這個。

請注意:在 1.12 Pre-3 版本中存在一個嚴重漏洞,即命令執(zhí)行體不能正確地通過execute傳遞到被調用的函數中去,這個漏洞有望在后續(xù)版本以及正式版修復。

以下是本文用到的一個函數系統(tǒng)的目錄,帶有"+"的表示為目錄

+ functions + say hi.mcfunction bye.mcfunction Text1.mcfunction text2.mcfunction + system + process _process.mcfunction _main.mcfunction player_tick.mcfunction

如何調用函數

在 1.12 中,MOJANG新增了function指令和一條名為gameLoopFunction游戲規(guī)則來輔助我們使用函數系統(tǒng)。function指令的格式如下:

function <命名空間:函數名> function <命名空間:函數名> <if|unless> <選擇器>

這兩條都是可行的。其中,if|unless是在1.12 pre-4加入的功能,后面我會解釋到這個。我們先來說說第一種形式。例如上面的目錄中,要調用system這個命名空間下的_main文件,就是輸入這樣的指令:

function system:_main

現在,我們來看一個例子例如say命名空間下的Text1.mcfunctiontext2.mcfunction,里面分別寫上這些內容

Text1.mcfunction

#這是一個范例,在function文件中可以用#來注釋行。請注意,不能夠使用//來注釋! say 1 function say:text2 say 2

text2.mcfunction

say 3 say 4

當我在系統(tǒng)后臺輸入function say:text1時,聊天框會出現這些內容: [server] 1 [server] 3 [server] 4 [server] 2

也就是說,執(zhí)行function指令的人,會把函數里面的指令依次執(zhí)行——我在系統(tǒng)后臺輸入function指令,就是系統(tǒng)在執(zhí)行,我自己輸入function指令,就是我本人在執(zhí)行。大家可能注意到了,函數中支持使用#進行注釋(舊版本支持//注釋,當前版本已經不再支持),也就是說被注釋行不會作為指令而執(zhí)行,這一點有多方便相比不比我再說了。同時需要大家注意:函數中所有指令不能夠以/開頭。例如,你可以這樣寫:

say @s

但是不能這樣寫:

/say @s

最后有一點需要注意的是,在function指令中調用函數時,不區(qū)分大小寫。例如前面say命名空間下的Text1.mcfunction,我在調用的時候寫的是say:text1

然后是第二種形式,也就是帶有if|unless的。我簡單舉兩個例子,大家就知道是什么意思了。

say:tellraw.mcfunction scoreboard objectives add timer dummy 計時器 scoreboard players add @s timer 1 function random:title if @s[score_timer_min=1200] scoreboard players reset @s[score_timer_min=1200] timer

random:title.mcfunction summon area_effect_cloud ~ ~ ~ {Tags:["rnd_title","rnd_title1"]} summon area_effect_cloud ~ ~ ~ {Tags:["rnd_title","rnd_title2"]} summon area_effect_cloud ~ ~ ~ {Tags:["rnd_title","rnd_title3"]} summon area_effect_cloud ~ ~ ~ {Tags:["rnd_title","rnd_title4"]} summon area_effect_cloud ~ ~ ~ {Tags:["rnd_title","rnd_title5"]} entitydata @r[r=0,type=area_effect_cloud,tag=rnd_title] {CustomName:"rnd_title"} execute @e[name=rnd_title,tag=rnd_title1] ~ ~ ~ tellraw @a[r=0,c=1] ["1"] execute @e[name=rnd_title,tag=rnd_title2] ~ ~ ~ tellraw @a[r=0,c=1] ["2"] execute @e[name=rnd_title,tag=rnd_title3] ~ ~ ~ tellraw @a[r=0,c=1] ["3"] execute @e[name=rnd_title,tag=rnd_title4] ~ ~ ~ tellraw @a[r=0,c=1] ["4"] execute @e[name=rnd_title,tag=rnd_title5] ~ ~ ~ tellraw @a[r=0,c=1] ["5"]

將say:tellraw放到主進程中

execute @a ~ ~ ~ function say:tellraw

則每位玩家每分鐘將會看到1~5中隨機一個數字出現在聊天框。也就是說,只有計時器分數滿1200的人會執(zhí)行后面的隨機部分。那么很顯然,帶有if的意思就是,如果能找到后面的選擇器,就執(zhí)行這個函數,否則不執(zhí)行。相當于testfor

那么unless的意思也就很明顯了:在找不到后面的選擇器的時候,執(zhí)行這個函數,相當于testfor+非門。

gameLoopFunction

講完調用,就該講講高頻了。玩命令方塊的人都知道高頻是實現許多功能的前提。在函數系統(tǒng)中,MOJANG 為我們提供了一條名為gameLoopFunction的游戲規(guī)則來實現高頻。它的格式是

gamerule gameLoopFunction <命名空間:函數>

也就是說,你可以指定一個函數來高頻執(zhí)行,這個高頻是20Hz的,也就是每一個游戲刻都會執(zhí)行一遍。新建的存檔如果沒有執(zhí)行過這條指令,而是用gamerule gameLoopFunction來查詢的話,得到的返回值是-

為了方便,我們將這個規(guī)則簡稱為glf。在舊版本中,glf指定的函數,由系統(tǒng)(server)作為執(zhí)行體;而在新的版本中,MOJANG 引入了虛擬執(zhí)行體,例如將 say:text2 指定為glf時,每一個游戲刻得到的結果是這樣的

[say:text2] 3 [say:text2] 4

也就是說,系統(tǒng)不再作為執(zhí)行體,而是由虛擬的執(zhí)行體代為執(zhí)行。

關于 glf 多說兩句。使用 glf 去高頻執(zhí)行一個函數,和使用 RCB(循環(huán)型命令方塊,紫色那種)去執(zhí)行,是不一樣的。區(qū)別主要在于其更新順序先后。一般而言不會造成嚴重影響,但是在某些情況會不一樣。比如,使用 CB 能檢測到生物的{HurtTime:10s}這個 NBT,而使用 glf 執(zhí)行函數只能檢測到的是{HurtTime:9s},檢測不到10,這是因為關于函數的更新,都放在了生物更新之后,而 CB 的更新則是在生物更新之前。詳情可以看這里。按照 Searge 的說法,函數并不是命令方塊的完全替代。這個說法,大家就見仁見智了。對我個人而言這個影響不大。

以上是函數系統(tǒng)的相關構成,以及如何調用函數。接下來我們來了解一下函數系統(tǒng)的模塊分類。

函數系統(tǒng)的模塊調用

對于一個完整的命令系統(tǒng)而言,模塊一般可以分為三類:對執(zhí)行順序先后有要求的高頻模塊、對執(zhí)行順序先后無要求的高頻模塊、非高頻模塊。在函數系統(tǒng)中,我們同樣可以將模塊分成這三類。為了方便后續(xù)講解。我們作這樣的設定:

將 system:_main設為 glf ,并稱之為主進程或者主時鐘

對于上面講到的三類模塊,我們通過三種不同的方式去調用。

對執(zhí)行順序先后有要求的高頻模塊,在主進程中按照需要的順序排列好來調用。對執(zhí)行順序先后沒有要求的高頻模塊,在主進程中可以比較隨意放置位置,但是一般不會考慮優(yōu)先執(zhí)行。特別地,如果這個模塊是針對每一個玩家獨立執(zhí)行的,可以使用進度系統(tǒng)中的"tick"觸發(fā)器來調用,而不需要放在主進程中僅在特定情況下觸發(fā)的非高頻模塊,在主進程中調用,但是輔以execute、scoreboard和選擇器參數去控制其在合適的時候被調用,這里的選擇器,包括了在1.12 pre-4中新增的if/unless的部分。

非高頻模塊在特定條件下激活,也在很大程度上減少了模塊中大量重復出現execute的現象,并完全杜絕了超長的Conditional鏈,因為function中并不直接支持Conditional。不直接支持,說明可以間接支持,對吧。我們來看一個例子。

假設有紅藍兩隊,在開始前考慮到互毆問題不進行分隊,而是采用掛tag的方式。 紅隊以tag=redTeam為標記,藍隊則以tag=blueTeam為標記,準備觀戰(zhàn)的玩家以tag=specTeam為標記 當玩家站在相應區(qū)域(紅藍兩隊的所有玩家還需要選擇了職業(yè))添加Ready的標記,視為準備就緒。 如果玩家不在相應區(qū)域時就移除Ready的標記。 選擇了職業(yè)的玩家,其記分板項selectClass數值大于等于1 全部玩家準備就緒后,游戲進入倒計時,倒計時結束時游戲開始 倒計時未結束,有玩家脫離準備就緒的狀態(tài),則倒計時中斷

條件比較多,我們先來看看怎么寫這個模塊,再進行分析。在這里,我們準備了一個名為gameStat的aec實體作為標記,所有游戲進程會以tag或者score的形式掛載到該實體上。請看指令部分

execute @p[tag=redTeam,score_selectClass_min=1] ~ ~ ~ execute @p[tag=blueTeam,score_selectClass_min=1] ~ ~ ~ scoreboard players tag @e[type=area_effect_cloud,name=gameStat,tag=notGaming] add allReady execute @p[tag=!Ready,m=2] ~ ~ ~ scoreboard players tag @e[name=gameStat,type=area_effect_cloud,tag=notGaming] remove allReady execute @p[tag=!Ready,m=2] ~ ~ ~ execute @e[name=gameStat,type=area_effect_cloud,tag=notGaming] ~ ~ ~ execute @s[tag=!allReady,score_waitTime_min=1] ~ ~ ~ title @a clear execute @p[tag=!Ready,m=2] ~ ~ ~ execute @e[name=gameStat,type=area_effect_cloud,tag=notGaming] ~ ~ ~ execute @s[tag=!allReady,score_waitTime_min=1] ~ ~ ~ title @a reset execute @p[tag=!Ready,m=2] ~ ~ ~ execute @e[name=gameStat,type=area_effect_cloud,tag=notGaming] ~ ~ ~ scoreboard players reset @s[tag=!allReady] waitTime scoreboard players add @e[name=gameStat,tag=allReady] waitTime 1 execute @e[name=gameStat,score_waitTime=1,score_waitTime_min=1] ~ ~ ~ title @a times 10 140 10 execute @e[name=gameStat,score_waitTime=1,score_waitTime_min=1] ~ ~ ~ title @a subtitle [{"color":"aqua","text":"請玩家站在準備區(qū)域不要離開"}] execute @e[name=gameStat,score_waitTime=1,score_waitTime_min=1] ~ ~ ~ title @a title [{"color":"yellow","text":"游戲即將開始"}] execute @e[name=gameStat,score_waitTime=40,score_waitTime_min=40] ~ ~ ~ title @a subtitle [{"color":"aqua","text":"3"}] execute @e[name=gameStat,score_waitTime=40,score_waitTime_min=40] ~ ~ ~ execute @a ~ ~ ~ playsound block.note.pling voice @p ~ ~ ~ 1 0 execute @e[name=gameStat,score_waitTime=60,score_waitTime_min=60] ~ ~ ~ title @a subtitle [{"color":"aqua","text":"2"}] execute @e[name=gameStat,score_waitTime=60,score_waitTime_min=60] ~ ~ ~ execute @a ~ ~ ~ playsound block.note.pling voice @p ~ ~ ~ 1 0 execute @e[name=gameStat,score_waitTime=80,score_waitTime_min=80] ~ ~ ~ title @a subtitle [{"color":"aqua","text":"1"}] execute @e[name=gameStat,score_waitTime=80,score_waitTime_min=80] ~ ~ ~ execute @a ~ ~ ~ playsound block.note.pling voice @p ~ ~ ~ 1 0 execute @e[name=gameStat,score_waitTime_min=100] ~ ~ ~ title @a times 10 30 10 execute @e[name=gameStat,score_waitTime_min=100] ~ ~ ~ title @a title [{"color":"gold","text":"游戲開始"}] scoreboard players set @e[name=gameStat,type=area_effect_cloud,score_waitTime_min=100] gameStat 1 scoreboard players reset @e[name=gameStat,score_gameStat_min=1,score_gameStat=1] waitTime scoreboard players tag @e[name=gameStat,score_gameStat_min=1,score_gameStat=1] remove allReady execute @e[type=area_effect_cloud,name=gameStat,score_gameStat_min=1,score_gameStat=1] ~ ~ ~ function system:StartGame

接下來我們來慢慢分析。

首先是開始的條件。有紅藍兩隊,那么這兩隊都肯定需要有人,才能夠開始,考慮到同一選擇器中不能重復使用tag的參數,我們保留了區(qū)分隊伍的參數,而不是區(qū)分是否準備就緒的參數。因此,第一條指令的意思是,當存在選了職業(yè)并選紅隊的玩家以及選了職業(yè)并選藍隊的玩家,我們給中心實體加上allReady這個標記,以表明可能滿足開始條件。

至于滿足條件嗎?如果有未準備就緒的玩家,就說明不滿足,那我們就讓一個沒有準備就緒的玩家來去掉allReady這個標記好了。

對于3~5行,我們放后面點講。先看后面。滿足開始條件以后,我們會給中心實體加分(使用waitTime這個記分板項),在第一刻加分后出現提示文字提示準備開始,然后進入循環(huán)計時,最后計時滿了,調用system:startgame這個函數來開始游戲(這里不是例子的部分,不作說明)。

那么回過頭來看3~5行,這里明顯是打斷的部分。打斷,就是要清掉提示文字、重置計時器。如果此時都還沒有進行過加分,那么我們就不必進行那三條指令,因此可以看到中間有個選擇器里有score_waitTime_min=1的參數加以限制。

重點來了,我們看到這3條指令前面相當長一串execute是重復的。因為在以前用cb寫的時候,這里我使用了Conditional,而現在函數不直接支持Conditional,所以我用了一大堆execute,但是這里我們可以稍作修改,對不對?請看下面

execute @p[tag=redTeam,score_selectClass_min=1] ~ ~ ~ execute @p[tag=blueTeam,score_selectClass_min=1] ~ ~ ~ scoreboard players tag @e[type=area_effect_cloud,name=gameStat,tag=notGaming] add allReady execute @p[tag=!Ready,m=2] ~ ~ ~ scoreboard players tag @e[name=gameStat,type=area_effect_cloud,tag=notGaming] remove allReady execute @p[tag=!Ready,m=2] ~ ~ ~ execute @e[name=gameStat,type=area_effect_cloud,tag=notGaming] ~ ~ ~ execute @s[tag=!allReady,score_waitTime_min=1] ~ ~ ~ function system:cond_breakstartcount scoreboard players add @e[name=gameStat,tag=allReady] waitTime 1 execute @e[name=gameStat,score_waitTime=1,score_waitTime_min=1] ~ ~ ~ title @a times 10 140 10 execute @e[name=gameStat,score_waitTime=1,score_waitTime_min=1] ~ ~ ~ title @a subtitle [{"color":"aqua","text":"請玩家站在準備區(qū)域不要離開"}] execute @e[name=gameStat,score_waitTime=1,score_waitTime_min=1] ~ ~ ~ title @a title [{"color":"yellow","text":"游戲即將開始"}] execute @e[name=gameStat,score_waitTime=40,score_waitTime_min=40] ~ ~ ~ title @a subtitle [{"color":"aqua","text":"3"}] execute @e[name=gameStat,score_waitTime=40,score_waitTime_min=40] ~ ~ ~ execute @a ~ ~ ~ playsound block.note.pling voice @p ~ ~ ~ 1 0 execute @e[name=gameStat,score_waitTime=60,score_waitTime_min=60] ~ ~ ~ title @a subtitle [{"color":"aqua","text":"2"}] execute @e[name=gameStat,score_waitTime=60,score_waitTime_min=60] ~ ~ ~ execute @a ~ ~ ~ playsound block.note.pling voice @p ~ ~ ~ 1 0 execute @e[name=gameStat,score_waitTime=80,score_waitTime_min=80] ~ ~ ~ title @a subtitle [{"color":"aqua","text":"1"}] execute @e[name=gameStat,score_waitTime=80,score_waitTime_min=80] ~ ~ ~ execute @a ~ ~ ~ playsound block.note.pling voice @p ~ ~ ~ 1 0 execute @e[name=gameStat,score_waitTime_min=100] ~ ~ ~ title @a times 10 30 10 execute @e[name=gameStat,score_waitTime_min=100] ~ ~ ~ title @a title [{"color":"gold","text":"游戲開始"}] scoreboard players set @e[name=gameStat,type=area_effect_cloud,score_waitTime_min=100] gameStat 1 scoreboard players reset @e[name=gameStat,score_gameStat_min=1,score_gameStat=1] waitTime scoreboard players tag @e[name=gameStat,score_gameStat_min=1,score_gameStat=1] remove allReady execute @e[type=area_effect_cloud,name=gameStat,score_gameStat_min=1,score_gameStat=1] ~ ~ ~ function system:StartGame

system:cond_breakstartcount.mcfunction

title @a clear title @a reset scoreboard players reset @s waitTime

雖然這個獨立出來的子模塊只有3條指令,但是如果分離出來的是30條而不是3條呢?能夠節(jié)省多少功夫想必不需要我解釋了吧?

以上是關于函數系統(tǒng)模塊調用的部分,當中有提到使用進度系統(tǒng)來調用部分獨立模塊,我們接下來來講這一部分。

函數系統(tǒng)與進度系統(tǒng)的聯動

advancement,亦簡稱adv,目前wiki翻譯叫進度。這里就不多作介紹了。在17w17b中MOJANG允許進度返回指令作為達成進度的獎勵,讓不少玩家發(fā)現了新大陸。隨后在17w18b中,MOJANG進一步完善進度系統(tǒng),使其可以完全獨立于命令方塊而建立起一個命令系統(tǒng);在1.12 pre1中,MOJANG又作出了修改,將進度系統(tǒng)中的命令部分拿出來做成了如今的函數系統(tǒng)。

但是這并不意味著進度系統(tǒng)就不可以參與到命令系統(tǒng)中來,因為如今的進度系統(tǒng)可以返回函數作為達成進度的獎勵。

相信很多人已經知道進度系統(tǒng)的結構了,但仍有相當一部分朋友還沒有了解,在這里我們不妨來溫習一下。

自定義的進度,所有文件都保存在存檔目錄/data/advancements/下,在這里新建的文件夾同樣都稱為命名空間,命名空間下存放各種進度文件。進度文件使用 json 格式。這里展示一個用于進度命令系統(tǒng)的例子

所涉及的兩個文件分別是data/advancements/system/HelloTitle.json和data/functions/system/HelloTitle.mcfunction,這里進度和函數都用同樣的命名空間和文件名方便記憶和管理,可以看到函數文件是 .mcfunction,而進度文件是 .json

system:HelloTitle.json

{ "criteria":{ "custom_name":{ "trigger":"minecraft:tick" } }, "rewards":{ "function":"system:hellotitle" } }

system:HelloTitle.mcfunction

#revoke adv,用于下次再激活 advancement revoke @s only system:hellotitle #命令部分 scoreboard objectives add helloTitle stat.leaveGame scoreboard players tag @s[tag=HelloTitle,score_helloTitle_min=1] remove HelloTitle tellraw @s[tag=!HelloTitle] ["",{"text":"Hello ","color":"yellow"},{"selector":"@s"},{"text":"! Welcome to Minecraft!","color":"yellow"}] scoreboard players tag @s[tag=!HelloTitle] add HelloTitle scoreboard players reset @s[score_helloTitle_min=1] helloTitle

這個進度會在下一個游戲刻達成,對象是全體在線玩家,達成進度后會執(zhí)行HelloTitle.mcfunction中的指令。其實現的效果是,當玩家進入這個世界時,會在聊天框看見問候語(其他人看不到)

可以看到,相比于以前命令方塊高頻,這里采用了進度系統(tǒng)的 tick 觸發(fā)器和@s選擇器。如果單純用命令方塊高頻或者函數系統(tǒng),那么只需要這樣

scoreboard objectives add helloTitle stat.leaveGame scoreboard players tag @a[tag=HelloTitle,score_helloTitle_min=1] remove HelloTitle execute @a[tag=!HelloTitle] ~ ~ ~ tellraw @s ["",{"text":"Hello ","color":"yellow"},{"selector":"@s"},{"text":"! Welcome to Minecraft!","color":"yellow"}] scoreboard players tag @a[tag=!HelloTitle] add HelloTitle scoreboard players reset @a[score_helloTitle_min=1] helloTitle

區(qū)別就是選擇器上的不一樣。如果大家覺得進度系統(tǒng)很麻煩,可以不去使用,但是接下來我們會看到一個使用進度系統(tǒng)的其他觸發(fā)器來調用函數的例子。例如,要讓所有冒險模式玩家入水即死。

rules:DieInWater.json

{ "criteria":{ "1":{ "trigger":"enter_block", "condition":{ "block":"water" } } }, "rewards":{ "function":"rules:dieinwater" } }

rules:DieInWater.mcfunction

#revoke advancement revoke @s only rules:dieinwater #commands scoreboard players tag @p[m=2,r=0] add waterKill execute @s[tag=waterKill] ~ ~ ~ tellraw @a [{"selector":"@s"},{"color":"white","text":" 被水淹沒了"}] execute @s[tag=waterKill] ~ ~ ~ gamerule showDeathMessages false kill @s[tag=waterKill] execute @s[tag=waterKill] ~ ~ ~ gamerule showDeathMessages true scoreboard players tag @s[tag=waterKill] remove waterKill

當玩家踏入水中時,我們要給玩家加上一個tag,然后殺掉他。至于為什么用@p而不用@s呢?因為@p不能選中死人,而@s可以,如果不想看到聊天框刷屏,就不要選擇用@s。

以上是利用進度系統(tǒng)的 enter_block(玩家進入方塊) 這一觸發(fā)器來實現落水即死功能的,如果單純依靠函數,不依靠進度系統(tǒng)去實現的話,可以這樣寫

rules:DieInWater_FUNCONLY.mcfunction

execute @a[m=2] ~ ~ ~ detect ~ ~ ~ water -1 scoreboard players tag @p[r=0] add waterKill execute @a[tag=waterKill] ~ ~ ~ tellraw @a [{"selector":"@s"},{"color":"white","text":" 被水淹沒了"}] execute @a[tag=waterKill] ~ ~ ~ gamerule showDeathMessages false kill @a[tag=waterKill] execute @a[tag=waterKill] ~ ~ ~ gamerule showDeathMessages true scoreboard players tag @a[tag=waterKill] remove waterKill

然后將這個函數扔進主進程中高頻執(zhí)行即可。

我們講完了函數系統(tǒng)與進度系統(tǒng)的聯動部分。道理而言已經講完了函數系統(tǒng)的基礎使用,那么在最后,我們來聊聊函數系統(tǒng)與命令方塊系統(tǒng)的對比吧,看看它們各自的優(yōu)缺點。

函數系統(tǒng)與命令方塊的對比

如果你看上面的看得有點迷糊,那我們來簡單講講函數系統(tǒng)和命令方塊(CB)系統(tǒng)的對比吧,進度作為函數的聯動觸發(fā)形式,就不作過多講解了

前面講到的三種模塊中,對執(zhí)行順序無要求的高頻模塊無論是用函數還是CB都沒有什么問題,而那些需要嚴格保證執(zhí)行順序的模塊,以前我會將他們全部連在一起,只用一個 RCB(循環(huán)型命令方塊,即高頻CB源)作為“信號源”。

為什么不劃出做成子模塊(通常以ICB-脈沖型命令方塊起頭,后面跟一串CCB -連接型命令方塊)調用呢?因為你在當前游戲刻調用了ICB子模塊以后,它會等到下一個游戲刻才執(zhí)行。可不要小看這一個游戲刻的延遲,它往往可能讓你的系統(tǒng)出現意外,進而產生各種蜜汁bug。

而函數系統(tǒng)中,調用的子模塊會立即插隊執(zhí)行,從而能夠嚴格保證執(zhí)行順序,出錯的可能性大大降低了。

函數系統(tǒng)不能夠直接支持Conditional模式,也就是條件激活,而CB是支持的。關于這一點,以我個人的經驗,影響是不大的,過去1.8沒有

Conditional不也是這么過來了嗎?

函數系統(tǒng)的主進程使用gamerule gameLoopFunction <命名空間:函數>來掛載,而CB系統(tǒng)的"主進程"使用 RCB 作為高頻信號源。

在過去的版本,通過glf掛載的主進程,其執(zhí)行者是系統(tǒng),也就是server。這個設定會產生各種各樣的安全隱患,于是在后來的版本中,MOJANG將其執(zhí)行者改成了glf所掛載的函數(前面也講到了)。就目前而言,僅僅通過函數系統(tǒng),就能夠實現過去CB能夠實現的功能,甚至還有一些是CB難以實現的功能。在這里就不過多講了,希望對大家有所啟發(fā),可以研發(fā)各種各樣的黑科技出來~

這里插入講一點,我想對于地圖制作者來講是絕對的福音

mcf系統(tǒng)直接支持樣式代碼§。

CB系統(tǒng)的顏色黑科技什么的在這個面前根本不值一提。

資源占用方面,簡單說一下我個人的經驗。

我們花了不到一天的時間把《喋血冰封II》升級到新的命令系統(tǒng)。新系統(tǒng)在資源占用方面明顯比之前龐大的CB系統(tǒng)少了很多,流暢度不降反升,這也得益于函數系統(tǒng)更加接近游戲底層。CB系統(tǒng)在方塊更新這一方面就輸掉了一大截。更何況它需要占地。

試想一下,如果你的系統(tǒng)足夠龐大,出生地可以加載的區(qū)域放多CB,你能夠記得住嗎?你在調試系統(tǒng)的時候,需要花多少時間去找到你要修改的指令呢?

此外,對于一些不放在出生點的模塊,我們還需要考慮到區(qū)塊加載的問題,相信這也是讓許多人頭疼的問題吧?

函數系統(tǒng)顯然不需要擔心這個,因為它所有的內容都保存在文件里,不具體地出現在游戲世界中,在資源占用方面相比與CB系統(tǒng)而言,是要占優(yōu)的。

我們知道,寫一個功能可能只要一兩天,debug可能要一周。過去CB系統(tǒng),不依靠編輯器的話,你得手動檢查,如果要在中間插入什么指令的話,還得整體移動CB,實際工作效率是十分感人的;借助于編輯器,我們可以通過ooc導入的方式來實現快速修改

而函數系統(tǒng)呢?你需要改點什么,直接去翻文件改,改完了保存一下,再在游戲里通過/reload指令直接刷新,完事兒了。游戲都不用退出重進。

但凡地圖制作者,知道了這些,都應該會心動的吧。

講了這么多,相信大家對新系統(tǒng)也有一定的了解了,說不定已經激動得說不出話來了吧,那么更多內容就請大家自行去體驗一下吧。在接下來的更新里,沒準還會多出什么意想不到的東西呢!

如轉載涉及版權等問題,請作者與我司聯系,我司將在第一時間刪除或支付稿酬。