命令方块吧 关注:6,128贴子:69,040
  • 13回复贴,共1

[CBL|玄素]这不是教程 §1游戏机制与命令

取消只看楼主收藏回复

原帖链http://www.mcbbs.net/thread-625526-1-1.html
同步更新。


IP属地:江苏1楼2016-09-10 15:42回复
    为什么我会在一个命令教程(并不是)的开头写这样一章呢?
    命令是mc中的一部分,它的运行依托于游戏机制,这使得很多时候写命令需要严格考虑游戏本身的机制对命令的影响,否则就会发现在你完全没有料到的情况下mojang给了你一板砖。
    挺疼的。
    这里的机制讲解未必会对整个机制面面俱到,但会展示它对命令的影响。熟悉掌握这些知识,写系统的时候就会避免很多“并不逻辑错误”的逻辑错误。


    IP属地:江苏2楼2016-09-10 15:43
    回复
      游戏刻和时序
      游戏刻
      游戏刻的定义知者应当甚众。gametick(游戏刻)简称gt,是minecraft的基本运行时钟。所有的对这个游戏世界产生的影响,都以1/20秒一次的速度被游戏处理。玩家的移动,方块的挖掘,物品的合成,生物的spawn和despawn,这些一切的游戏因素全部依赖于gametick。
      自然也包括了命令。
      从1.7的时代开始,玩家就通过summon FallingSand/setblock的方式,使得命令的激活速度能够达到游戏机制允许的上限,也就是20次/秒。每gametick执行一次,一般足够去获取一切我们需求的数据。1.9之后rcb的出现极大地方便了这一超高频系统的构建,也可以使现在的高频系统不再需要大量的红石产生的方块更新,卡顿--。
      tick在minecraft中文wiki中的注解是这样的:
      【几乎所有的游戏(包括Minecraft)都是由一个大循环程序运行的。就像钟内的每个齿轮是和钟摆同步一样,推动游戏模拟进程的每个任务也是和循环程序同步的。相称的,循环程序的一个周期被称之为一“刻(tick)”。】


      IP属地:江苏本楼含有高级字体3楼2016-09-10 15:44
      回复
        看起来同步,实际上..
        作为一个程序,所有的代码运行都有先后次序。你可以要求程序同时计算1+2和2+3,程序会同时告诉你结果,但在中间你所看不到的步骤,这两个加法一定有一个是先执行的。
        在mc的世界里,亦然。
        在接受了上面描述过的main loop(主循环)也就是tick的运行机理之后,你会明白为什么你对游戏的影响看起来是在同一个1/20s上发生的;但同时你也要明白,这些看似同时发生的事情,实际上也有着自己的先后次序。
        假设一个红石块的放置的位置能激活两个cb,这两个cb对命令的执行也存在先后次序。想想看1.8时代的fill高频,就是通过这两个cb之间的执行次序防止红石块反复激活cb,来实现高频激活整个系统的。
        判断操作的执行顺序本身就是一门学问。这里有一个基于源码的更新顺序介绍帖子:http://tieba.baidu.com/p/4126971513,如果能看懂的话你会觉得发现了新大陆..很多以前觉得特别特性的东西都能通过这套更新理论得到解答:比如为什么rcb被命令关闭后还会产生一次输出?因为这个时候他已经默默把自己加入到NTE了..果然是work as intended..
        通过这套理论解释1.9以后的cb执行顺序是很便捷的,因为实际执行次序就是被加入NTE的次序。但是显然这么说并不好理解..所以这里给出一个更便于理解的解释:
        [每条cb链的开头方块都会试图将其后满足激活条件的ccb依次执行。cb链间的执行次序由开头cb的执行次序决定,cb链内的次序由cb链次序决定。rcb执行次序取决于最后一次激活的次序(跨tick,每次更新激活状态均会影响这个次序);icb执行次序取决于tick内激活次序。每次重进游戏会重新加载区块,此时rcb执行次序将无视之前次序,新次序为区块加载次序。]
        tick内激活次序,就像之前已经提到过了的1.8时代fill高频的模式一样。红石块对周围cb的激活次序是不同的——严格地遵循xyz从小到大的次序,即先比较x值大小并由小到大执行;x值相等时比较y值;y值相等时比较z值。例如在(3,3,3)处放置一个红石块,(2,3,3)处的cb将在(3,2,3)处的cb之前执行。
        除cb执行顺序和操作更新顺序之外,很多依旧是看着“这肯定是同时执行的东西”之间之间同样有着自己的一套次序,甚至实际上这些次序被提及的次数并不比cb间执行顺序少..
        比如fill里方块的放置也是按照xyz小到大的次序来放置方块;
        比如execute嵌套里不同层次execute对对象检索的递归关系;
        比如实体选择器是先选择后执行,还是变执行边选下一个目标...
        玩家们几乎就是在不断的试错之下逐渐拨清迷雾理顺关系,唔,或是翻源码..
        我自己也很难整理出一张明确的表单来描述所有的时序关系,cb目前的时序还算简单明了,但这些基于游戏本身设定的时序设定只能靠多尝试,多积累。不管如何,当自己的系统发生故障时,不妨问问自己,是不是时序出问题了?


        IP属地:江苏本楼含有高级字体5楼2016-09-10 15:44
        回复
          命令时序
          在构建系统的时候我们必然会去思考:什么命令需要先执行,什么命令需要后执行。
          不管是时间跨度以秒甚至分为单位的rpg剧情系统,还是执行全在1tick内的单tick执行模块,只要是一个由多条命令构成的系统,都会存在时序的问题。
          命令的次序不同常会导致完全相异的结果。很简单的例子比如这个:
          scoreboard players tag @p add say
          say @a[tag=say]
          scoreboard players tag @p remove say
          显然在无论是单次执行还是循环,你的名字都会被say输出。可是如果顺序稍微交换一下..
          scoreboard players tag @p remove say
          say @a[tag=say]
          scoreboard players tag @p add say
          和刚才相反,这样say就不会再输出你的名字了。命令都是相同的,仅仅是交换次序就得到了完全不一致的结果。
          越是庞大的系统往往越看重时序。比如很常见的pvp地图,就存在着许多需要考虑的时序问题——
          ·判断玩家准备好之后,才能开始进行游戏开始检定
          ·技能之间的叠加和覆盖,净化类效果要么最后生效,或是用tag的方式使tick内其后的效果选择不到净化下的玩家
          ·胜利和失败,死亡和分数
          沧海一粟。
          有时不同的模块间的工作并行不悖没有相互的干扰,但内部却有着严格的时序控制;有的时候模块之间存在相互干涉,这时候时序就更显其复杂而充满魅力的一面:通过合理安排命令的执行次序,该做的工作精确的得到了完成。
          掌握了时序,也就掌握了踏足大型系统制作的密匙。


          IP属地:江苏本楼含有高级字体6楼2016-09-10 15:45
          回复
            单tick的命令需求
            由于cb在tick内仅能激活一次的性质,我们很难构建一个tick内的条件循环出来。这时,如果要做到类似编程中while效果,我们就要借助于游戏本身的时钟通过条件控制cb来进行耗时多tick的循环。但是时间跨及多tick必然会导致一个问题:命令结果的反馈失去了即时性。这对一些需求即时反馈即时处理的系统是致命的打击。
            这时我们会考虑想一些方式来让它成为tick内可执行的东西,这样和其余高频模块之间的关系就可以准确的建立。
            这类方式一般分为两种:算法优化和穷举。
            所谓穷举,即将可能的结果一一例举并给出对应的解的方式。你可以不需要知道什么是加法,但你有一张写下了10以内加减法的表,你依旧可以对他人的提问应答自如。用穷举来应对单tick需求是可行的,因为有时我们要做的循环类似于“每tick给未标记玩家一个标记”,这时候直接举出有多少玩家来直接往身上贴对应的标记,不失为一种解决的手段。不过穷举最大的问题就是系统会变得庞大臃肿……毕竟要给每种可能的情况都建立一个解。除此之外,如果情况超出了你所穷举的范围,整个故事一下子就变得直接尴尬了起来……
            而算法优化则更偏重于脑洞。完全放弃用原有的方案来实现功能,而另辟蹊径寻找新的实现方式,这意味这你需要放弃一些已经成熟了的东西,甚至往往对自己游戏之外的知识有着需求。但是一旦成功了,你就掌握了独此一家的黑科技,这不也是一件很让人愉快的事情吗?


            IP属地:江苏本楼含有高级字体7楼2016-09-10 15:46
            回复
              跳tick..wtf!
              cber经常会遇到一件能让自己非常痛苦的事:跳tick。
              对,在关键的时刻命令没有执行,结果下一刻,玩家状态变了..
              系统:一脸懵逼
              跳tick一般来说是服务器过载的原因,优化系统可以很好的缓解这个问题。但是如果你的系统必须要这样写..
              这就很尴尬了。
              关于这个话题,我也知之甚少,并无法对这个机制作出完整的描述和处理,因而这里不再做过多解释,仅为抛砖引玉之用。


              IP属地:江苏本楼含有高级字体8楼2016-09-10 15:47
              回复
                方块更新

                方块更新是一个红石玩家常常提起的机制,我们耳熟能详的bud就是基于这个机制的构筑。但是对于cber,这个机制产生的影响可以忽视吗?显然问题的答案是否定的。
                方块更新是什么?当一个方块的状态发生了改变,它会向周围六个邻接的方块发出一个信号,告诉它们,“你们该检查一下要不要因为我的变化而变化啦!”这让当你敲掉一个沙子之后,它上面其余的沙子也会跟着落下来;或是破坏掉高草之后整个草都会消失。红石元件往往有着更广泛的更新范围,因为它们之间的信号联系会使得“跨方块”产生方块状态的更改。
                我们可以用setblock命令去放置一些正常情况下不会存在的方块,比如悬空不流动的岩浆...但是假若你想fill一片这样的岩浆,你会发现它并没有顺着你的意停留在半空,而是如同正常的岩浆一样开始流动。为什么会这样呢?//流动也好,更新也好,明明是我先的...
                这里又提到了在前一小节提起过的“在mc里没有同时发生的事”。造成这个结果的原因很简单,fill的实质是按照xyz从小到大顺序(怎么又是这个顺序..)逐一放置方块。于是方块相互更新,gg。
                这个机制对命令系统的构建未必是必然的好或坏,合理利用特性才是最合适的手段..
                嘛,虽然我也想不出什么利用上的例子.........[尴尬脸]


                IP属地:江苏本楼含有高级字体9楼2016-09-10 15:48
                回复
                  实体相关


                  实体属性
                  不同的实体有着不同的属性,这毋庸置疑。
                  wiki中写到了实体的分类。同分类的实体有着相似的nbt标签,有着相似的特性;在实体分类的眼光下,显然鸡蛋和雪球亲缘关系比鸡蛋和鸡更近。
                  同样在一个命令系统之中,不同的实体除了它本身在游戏中的定位之外,也会被用作完全不同的功能,甚至这些功能mojang也想不到。至少我想,mojang没有想到玩家会把村民用作右键探测的媒介吧?没有想到玩家会把凋灵头(1.8快照期)/药水云(1.9之后)作为游戏中的标记实体(Marker)吧?他们觉得盔甲架就够用了√
                  要发掘出这些作用,我们需要一万个脑洞,决心和黑科技。
                  实体属性显然不需要一一介绍了,对mc稍有了解的玩家都应该会能如数家珍。至于你能用这些特性挖掘出什么全新的玩法?那就看你自己啦。


                  IP属地:江苏本楼含有高级字体10楼2016-09-10 15:49
                  回复
                    实体的spawn和despawn
                    在生存模式中摸爬滚打过来的我们大致都懂得一些关于生物生成的知识:怪物刷新于阴暗的角落,而家畜们除了繁殖以外,一般在光亮的草地上刷新;墨鱼刷新于水中,末影螨会随着末影珍珠的使用而诞生;蝙蝠会在万圣节的时候增加刷出率......
                    等到了接触命令之后,眼中生物的概念变成了实体,也有了更加多种多样的实体出现和消失的条件:Item随着各种掉落而出现,被捡起或是到达Age上限便会消失;药水云会随着每次施加效果而改变它的范围,当范围大小足够小时即便存在时间上限未到它也会消失;PrimedTnt是少见的“就算我掉到虚空里了我也要自己炸死自己”的“坚强”实体......接触的越多,不同实体的不同生成和消失属性也就让我们越加在意。
                    为什么要关注于这些属性?它们能给我们带来些什么?
                    这让我们知道我们需要在什么时候对哪些实体做处理。
                    举个很简单的例子,AreaEffectCloud作为marker时,不填写Duration会让这个实体在下一Tick消失,就像没有Time的FallingSand一样。通过这样一个小技巧,就可以不需要在使用之后kill掉这个瞬间marker——它会自行消失。


                    IP属地:江苏本楼含有高级字体11楼2016-09-10 15:49
                    回复
                      生物寻路和生物AI
                      特意把这个东西抓出来讲,实际上是因为之前看到过的一幅地图。里面作者用了非常巧妙的方式来探测玩家选择的难度——看到这一小节的标题想必你也猜到了。没错,他利用了僵尸的寻路。越高的难度之下,僵尸会越倾向于从更近的道路接近村民——哪怕那意味着它会因为摔落而损失更多的血量。
                      这实际上利用了怪物的AI。我们可能并不怎么关注于游戏中生物本身的做法,而喜欢把它们变成一切行动由我们控制的“boss”。但有的时候,原版自带的这些机制加以好好利用,可以做到让别人啧啧称奇的黑科技效果。
                      怪物在面对玩家时更倾向于做些什么?面对别的生物呢?我们都知道Creeper畏惧豹猫而Skeleton害怕狗群(大概是因为怕被当骨头啃了??),但是对这些机制的利用其实并不多。在适当的地方带上一笔,会让你的地图变得更加“有趣”。


                      IP属地:江苏本楼含有高级字体13楼2016-09-10 15:50
                      回复
                        有时不光卸载会带来麻烦……
                        在一个没有玩家在线的服务器里,出生点cb所summon的,本来应该在下一tick消失的AreaEffectCloud不消失了......
                        ——后来怎么样?
                        几乎是理所应当的,服务器崩了。
                        尴尬的世界,不是么?
                        [小节注:之前有人问到是否写错小标题,答案是没有。强调的是你本来以为区块会卸载不会再summon,结果发现只summon不despawn——这不坑爹么。]


                        IP属地:江苏本楼含有高级字体15楼2016-09-10 15:53
                        回复
                          ……但是你又不能乱加载
                          你可能会问,“既然区块加载的问题那么麻烦,不如给所有区块都设上常加载,不就没问题了?”
                          正如前文所提到的,为什么就算区块加载机制会带来很多麻烦,mojang依旧选择了这样的机制呢?因为它能节省很多不必要的资源。
                          是的,你可以用一万个cb去加载一万个区块,可是这会带来什么?严重的资源浪费,后果就是严重的卡顿。更何况,大部分区块加载器本身就要消耗一些资源,积少成多亦不是一个小数目。
                          我们能做的,只是用尽量少的区块加载需求,去做到尽可能多的事。如果出现了必须要强行加载大量区块的时候,比如你要fill掉几百个区块……呃,分步来吧,服务器娘已经够辛苦了,我们需要的是给它一个抱抱。


                          IP属地:江苏本楼含有高级字体16楼2016-09-10 15:53
                          回复
                            第一章搬运完毕。贴吧的排版和贴吧的制度一样辣鸡。


                            IP属地:江苏17楼2016-09-10 15:54
                            收起回复