我的世界函数指令如何编辑和使用?喋血代码游戏
我的世界函数指令如何编辑和使用?
感谢方官大大:以下是我的讲解《我的世界》1.12版本新增了函数命令这一内容,很多玩家觉得非常复杂,也有玩家发现这个命令可以完全脱离命令方块而存在。今天文超将推荐的是《我的世界》1.12函数命令系统入门教程 ,希望大家能够喜欢。
函数系统的构成
函数系统的由来
函数(function)系统,是 MC 1.12 Pre-1 版本中新增的一个功能,它将原来进度系统中返回指令的部分单独提取出来,做成了现在的函数系统。
函数系统的形式
函数系统由命名空间和函数文件组成,这些文件保存在存档目录/data/functions/下。functions目录下的文件夹,称为命名空间,各个命名空间下存放不同的函数文件。实际上,命名空间就是方便我们编写者分类并管理各种函数文件。
函数文件是以.mcfunction为后缀名的文本文件,建议采用utf-8无BOM编码以防显示错乱。简单来讲,一个函数等价于一个多行命令方块,函数文件里面每一行写一条指令,当执行这个函数时,里面的指令会按行依次执行。如果在一个函数中调用其它函数,那么在同一游戏刻,被调用的函数中所有指令先执行完,再继续当前函数中后续的指令,就像插队一样,我们在后面对比命令方块时还会说到这个。
请注意:在 1.12 Pre-3 版本中存在一个严重漏洞,即命令执行体不能正确地通过execute传递到被调用的函数中去,这个漏洞有望在后续版本以及正式版修复。
以下是本文用到的一个函数系统的目录,带有"+"的表示为目录
+ functions
+ say
hi.mcfunction
bye.mcfunction
Text1.mcfunction
text2.mcfunction
+ system
+ process
_process.mcfunction
_main.mcfunction
player_tick.mcfunction
如何调用函数
在 1.12 中,MOJANG新增了function指令和一条名为gameLoopFunction的游戏规则来辅助我们使用函数系统。function指令的格式如下:
function <命名空间:函数名>
function <命名空间:函数名> <if|unless> <选择器>
这两条都是可行的。其中,if|unless是在1.12 pre-4加入的功能,后面我会解释到这个。我们先来说说第一种形式。例如上面的目录中,要调用system这个命名空间下的_main文件,就是输入这样的指令:
function system:_main
现在,我们来看一个例子例如say命名空间下的Text1.mcfun
Text1.mcfunction
#这是一个范例,在function文件中可以用#来注释行。请注意,不能够使用//来注释!
say 1
function say:text2
say 2
text2.mcfunction
say 3
say 4
当我在系统后台输入function say:text1时,聊天框会出现这些内容:
[server] 1
[server] 3
[server] 4
[server] 2
也就是说,执行function指令的人,会把函数里面的指令依次执行——我在系统后台输入function指令,就是系统在执行,我自己输入function指令,就是我本人在执行。大家可能注意到了,函数中支持使用#进行注释(旧版本支持//注释,当前版本已经不再支持),也就是说被注释行不会作为指令而执行,这一点有多方便相比不比我再说了。同时需要大家注意:函数中所有指令不能够以/开头。例如,你可以这样写:
say @s
但是不能这样写:
/say @s
最后有一点需要注意的是,在function指令中调用函数时,不区分大小写。例如前面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"execute @a ~ ~ ~ function say:tellraw
则每位玩家每分钟将会看到1~5中随机一个数字出现在聊天框。也就是说,只有计时器分数满1200的人会执行后面的随机部分。那么很显然,带有if的意思就是,如果能找到后面的选择器,就执行这个函数,否则不执行。相当于testfor。
那么unless的意思也就很明显了:在找不到后面的选择器的时候,执行这个函数,相当于testfor+非门。
gameLoopFunction
讲完调用,就该讲讲高频了。玩命令方块的人都知道高频是实现许多功能的前提。在函数系统中,MOJANG 为我们提供了一条名为gameLoopFunction的游戏规则来实现高频。它的格式是
gamerule gameLoopFunction <命名空间:函数>
也就是说,你可以指定一个函数来高频执行,这个高频是20Hz的,也就是每一个游戏刻都会执行一遍。新建的存档如果没有执行过这条指令,而是用gamerule gameLoopFunction来查询的话,得到的返回值是-
为了方便,我们将这个规则简称为glf。在旧版本中,glf指定的函数,由系统(server)作为执行体;而在新的版本中,MOJANG 引入了虚拟执行体,例如将 say:text2 指定为glf时,每一个游戏刻得到的结果是这样的
[say:text2] 3
[say:text2] 4
也就是说,系统不再作为执行体,而是由虚拟的执行体代为执行。
关于 glf 多说两句。使用 glf 去高频执行一个函数,和使用 RCB(循环型命令方块,紫色那种)去执行,是不一样的。区别主要在于其更新顺序先后。一般而言不会造成严重影响,但是在某些情况会不一样。比如,使用 CB 能检测到生物的{HurtTime:10s}这个 NBT,而使用 glf 执行函数只能检测到的是{HurtTime:9s},检测不到10,这是因为关于函数的更新,都放在了生物更新之后,而 CB 的更新则是在生物更新之前。详情可以看这里。按照 Searge 的说法,函数并不是命令方块的完全替代。这个说法,大家就见仁见智了。对我个人而言这个影响不大函数系统的模块调用
对于一个完整的命令系统而言,模块一般可以分为三类:对执行顺序先后有要求的高频模块、对执行顺序先后无要求的高频模块、非高频模块。在函数系统中,我们同样可以将模块分成这三类。为了方便后续讲解。我们作这样的设定:
将 system:_main设为 glf ,并称之为主进程或者主时钟
对于上面讲到的三类模块,我们通过三种不同的方式去调用。
对执行顺序先后有要求的高频模块,在主进程中按照需要的顺序排列好来调用。对执行顺序先后没有要求的高频模块,在主进程中可以比较随意放置位置,但是一般不会考虑优先执行。特别地,如果这个模块是针对每一个玩家独立执行的,可以使用进度系统中的"tick"触发器来调用,而不需要放在主进程中。仅在特定情况下触发的非高频模块,在主进程中调用,但是辅以execute、scoreboard和选择器参数去控制其在合适的时候被调用,这里的选择器,包括了在1.12 pre-4中新增的if/unless的部分。
非高频模块在特定条件下激活,也在很大程度上减少了模块中大量重复出现execute的现象,并完全杜绝了超长的Conditional链,因为function中并不直接支持Conditional。不直接支持,说明可以间接支持,对吧。我们来看一个例子。
假设有红蓝两队,在开始前考虑到互殴问题不进行分队,而是采用挂tag的方式。
红队以tag=redTeam为标记,蓝队则以tag=blueTeam为标记,准备观战的玩家以tag=specTeam为标记
当玩家站在相应区域(红蓝两队的所有玩家还需要选择了职业)添加Ready的标记,视为准备就绪。
如果玩家不在相应区域时就移除Ready的标记。
选择了职业的玩家,其记分板项selectClass数值大于等于1
全部玩家准备就绪后,游戏进入倒计时,倒计时结束时游戏开始
倒计时未结束,有玩家脱离准备就绪的状态,则倒计时中断
条件比较多,我们先来看看怎么写这个模块,再进行分析。在这里,我们准备了一个名为gameStat的aec实体作为标记,所有游戏进程会以tag或者score的形式挂载到该实体上。请看指令部分
execute @p[tag=redTeam,score_selectClass_min=1] ~ ~ ~ execute @p[tag=blueTeam,score_selectClas。,"rnd_title3"]}
srules: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。
以上是利用进度系统的 enter_block(玩家进入方块) 这一触发器来实现落水即死功能的,如果单纯依靠函数,不依靠进度系统去实现的话,可以这样写
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=wa函数系统与命令方块的对比
如果你看上面的看得有点迷糊,那我们来简单讲讲函数系统和命令方块(CB)系统的对比吧,进度作为函数的联动触发形式,就不作过多讲解了。
前面讲到的三种模块中,对执行顺序无要求的高频模块无论是用函数还是CB都没有什么问题,而那些需要严格保证执行顺序的模块,以前我会将他们全部连在一起,只用一个 RCB(循环型命令方块,即高频CB源)作为“信号源”。
为什么不划出做成子模块(通常以ICB-脉冲型命令方块起头,后面跟一串CCB -连接型命令方块)调用呢?因为你在当前游戏刻调用了ICB子模块以后,它会等到下一个游戏刻才执行。可不要小看这一个游戏刻的延迟,它往往可能让你的系统出现意外,进而产生各种蜜汁bug。
而函数系统中,调用的子模块会立即插队执行,从而能够严格保证执行顺序,出错的可能性大大降低了。
函数系统不能够直接支持Conditional模式,也就是条件激活,而CB是支持的。关于这一点,以我个人的经验,影响是不大的,过去1.8没有
Conditional不也是这么过来了吗?
函数系统的主进程使用gamerule gameLoopFunction <命名空间:函数>来挂载,而CB系统的"主进程"使用 RCB 作为高频信号源。
在过去的版本,通过glf挂载的主进程,其执行者是系统,也就是server。这个设定会产生各种各样的安全隐患,于是在后来的版本中,MOJANG将其执行者改成了glf所挂载的函数(前面也讲到了)。就目前而言,仅仅通过函数系统,就能够实现过去CB能够实现的功能,甚至还有一些是CB难以实现的功能。在这里就不过多讲了,希望对大家有所启发,可以研发各种各样的黑科技出来~
这里插入讲一点,我想对于地图制作者来讲是绝对的福音。函数系统中,调用的子模块会立即插队执行,从而能够严格保证执行顺序,出错的可能性大大降低了。
函数系统不能够直接支持Conditional模式,也就是条件激活,而CB是支持的。关于这一点,以我个人的经验,影响是不大的,过去1.8没有
Conditional不也是这么过来了吗?
函数系统的主进程使用gamerule gameLoopFunction <命名空间:函数>来挂载,而CB系统的"主进程"使用 RCB 作为高频信号源。
在过去的版本,通过glf挂载的主进程,其执行者是系统,也就是server。这个设定会产生各种各样的安全隐患,于是在后来的版本中,MOJANG将其执行者改成了glf所挂载的函数(前面也讲到了)。就目前而言,仅仅通过函数系统,就能够实现过去CB能够实现的功能,甚至还有一些是CB难以实现的功能。在这里就不过多讲了,希望对大家有所启发,可以研发各种各样的黑科技出来~
这里插入讲一点,我想对于地图制作者来讲是绝对的福音。
mcf系统直接支持样式代码§。
CB系统的颜色黑科技什么的在这个面前根本不值一提。
资源占用方面,简单说一下我个人的经验。
我们花了不到一天的时间把《喋血冰封II》升级到新的命令系统。新系统在资源占用方面明显比之前庞大的CB系统少了很多,流畅度不降反升,这也得益于函数系统更加接近游戏底层。CB系统在方块更新这一方面就输掉了一大截。更何况它需要占地想一下,如果你的系统足够庞大,出生地可以加载的区域放多CB,你能够记得住吗?你在调试系统的时候,需要花多少时间去找到你要修改的指令呢?
此外,对于一些不放在出生点的模块,我们还需要考虑到区块加载的问题,相信这也是让许多人头疼的问题吧?
函数系统显然不需要担心这个,因为它所有的内容都保存在文件里,不具体地出现在游戏世界中,在资源占用方面相比与CB系统而言,是要占优的。
我们知道,写一个功能可能只要一两天,debug可能要一周。过去CB系统,不依靠编辑器的话,你得手动检查,如果要在中间插入什么指令的话,还得整体移动CB,实际工作效率是十分感人的;借助于编辑器,我们可以通过ooc导入的方式来实现快速修改
而函数系统呢?你需要改点什么,直接去翻文件改,改完了保存一下,再在游戏里通过/reload指令直接刷新,完事儿了。游戏都不用退出重进。
但凡地图制作者,知道了这些,都应该会心动的吧。
讲了这么多,相信大家对新系统也有一定的了解了,说不定已经激动得说不出话来了吧,那么更多内容就请大家自行去体验一下吧。在接下来的更新里,没准还会多出什么意想不到的东西呢!
以上就是文超今天推荐的《我的世界》1.12函数命令系统入门教程 ,希望大家能够喜欢。谢谢
以下所述仅代表个人观点哦
首先函数系统是1.12版本以后的一个功能,他将原来进度系统中返回指令的部分单独提取出来,做成现在的函数系统。
函数系统有命名空间和函数文件组成。命名空间就是方便我们编写者分类管理各种函数文件,而函数文件,简单来讲,一个函数等价于多个命令方块,函数文件里面每一行写一条指令,当执行这个函数时,里面的指令会按行依次执行。如果在一个函数中调用其他函数,那么在同一游戏刻,被调用的函数中,所有指令先执行完,就像插队一样。
function指令格式如下
function <命名空间:函数名>
function<命名空间:函数名> <选择器>
此外,对于一些不放在出生点的模块,我们还需要考虑到区块加载的问题,相信这也是让许多人头疼的问题吧。
函数系统显然不需要担心这个,因为它所有的内容全都保存在文件里,不具体的出现在游戏世界中,再资源占用方面相比于cb系统而言是要占优势的。
我们知道,写一个功能可能只要一两天,bebug可能要一周。过去cb系统不依靠编辑器的话,你得手动检查,如果要在中间插入什么指令的话,还得整体移动,工作效率不高。
而函数系统,你要改什么,直接去翻文件改,改完了保存一下,再在游戏里通过/reload指令直接刷新就完事儿了,游戏都不用重进。
想必大家对函数系统有了一定的了解了吧,那么其他的大家一定还是要自己去探索。毕竟自己探索了才会记得更加牢固,还没准儿会多出什么意想不到的东西呢。
注:以上只代表个人看法和以往经验,并不代表官方权威数据。