欢迎光临散文网 会员登陆 & 注册

离地跳(BH)-iw百科

2020-03-20 18:00 作者:魔方12139  | 我要投稿

定义

离地跳(bunny hop, BH)是指在IWBTG系列游戏闯关时,通过在不稳定状态下起跳,使得kid起跳点或最大跳跃高度达到常规手段无法达到的值,从而通过某些常规手段无法或很难通过的障碍。属于高级技巧,最常用的场合是4.5格高墙和一段过平地纳豆。

离地跳不属于作弊或开挂,是游戏内的合理操作。

标准4.5格,常规跳法一般无法越过
一段过纳豆,常规跳法一般无法做到

操作方法

一般操作方法如下:站在地面上,一段跳跳到空中,自然下落,当kid的脚与地面的头相距不足1.5像素,且超过0.875像素时,再次按下shift,此时系统判断kid使用一段跳,这种跳法即为离地跳。

对于kid的脚与地面相距不足1.5像素,且超过0.875像素这一判据,肉眼通常难以鉴别,因此一般的判别方式是粗略观察或在多次练习后凭直感判断。

(其实更一般的说法是:在kid的脚和地面似碰非碰的瞬间跳起来)

4.5格操作演示
一段过平地纳豆操作演示

原理解释

下面以标准4.5格为例,解释离地跳的原理和必要性。

众所周知,在IWBTG系列游戏中,kid一般可以二段跳。在较流行的游戏引擎(yuuutu/yoyoyo)中,kid一段跳、二段跳的定义如下:


公理一:kid跳跃力度公理

跳跃力度,即在跳跃发生时,对kid竖直速度的赋值赋成多少。kid一段跳的力度是-8.5像素每步,二段跳的力度是-7像素每步。

yuuutu源码中kid跳跃力度定义


公理二:kid重力值公理

kid的重力值是0.4像素每平方步。

yuuutu源码中kid重力值定义


公理二点五:kid上升速度截断公理

如果在kid上升中松开跳跃键,那么kid的竖直速度变成原值的0.45倍。


yuuutu源码中kid上升速度截断部分


公理三:kid重力与速度效应公理

在每个步循环中,对kid是否跳跃进行的判断、kid的重力对kid竖直速度的改变、kid竖直速度对其实际位置的改变,这三个操作顺序如下:

判断kid是否进行跳跃 -> 给kid的竖直速度加上kid的重力 -> 给kid的竖直位置加上kid的速度

(其中第2、3步由系统完成)


推论一:kid最大跳跃高度推论

首先对一段跳进行分析。通过上述公理和简单除法运算可以得出,如果使用全力一段跳(长时间不松开跳跃键),其竖直速度为负,处在上升状态的“上升步”有:

floor(8.5/0.4) = 21步

这些步中其竖直速度分别是(单位是像素每步):

(-8.5+0.4), (-8.5+0.4*2), (-8.5+0.4*3), ...... , (-8.5+0.4*21)

于是一段跳的最大位移就是:

(-8.5+0.4)+(-8.5+0.4*2)+(-8.5+0.4*3)+......+(-8.5+0.4*21)

=(-8.1-0.1)*21/2

=-86.1像素

即最大跳跃高度是86.1像素。

同法可计算出二段跳的“上升步”有17步,最大位移是:

(-7+0.4)+(-7+0.4*2)+(-7+0.4*3)+......+(-7+0.4*17)

=(-6.6-0.2)*17/2

=-57.8像素

由于连续使用一段跳、二段跳必经历一个松开跳跃键-重按跳跃键的过程,且如果在同一步内做出这两个操作,就会引发二段取消跳(JC),使二段跳的高度被大大降低。因此,两段跳连用能达到的最大高度,并不等于两段跳分开计算所得最大高度之和143.9像素。

为了避免引发取消跳,必须将松开跳跃键和重按跳跃键的操作错开一步,由于速度截断公理,这样会牺牲一些速度。显然,可能是最优选择的两个选择分别是:

  1.  在一段跳的最后一个上升步(开始跳跃20步后)松键,下一步重按。这样在该步的速度就不是(-8.5+0.4*21)=-0.1,而是((-8.5+0.4*20)*0.45+0.4)=0.175,损失了(0.175-(-0.1))=0.275像素每步的速度,其他各步的运动状态都无变化。于是最大跳跃高度就是(143.9-0.275)=143.625像素。

  2. 在一段跳的最后一个上升步的下一步(开始跳跃21步后)松键,再下一步重按。这样就多出了一步,该步的速度是(-0.1+0.4)=0.3,是下落步,不会发生速度截断。其他各步的运动状态都无变化,于是最大跳跃高度就是(143.9-0.3)=143.6像素。

可见选择1是最优选择,即:

在开始跳跃20步后松键,下一步重按,即可达到常规二段跳模式下的最大跳跃高度,143.625像素。


推论二引言:

在人们的一般印象中,只要kid的脚比地面高的时候往那边走,就能走过去(这话好像有点土)。因此,kid跳过障碍时只要跳到脚比障碍高再走就可以了。这符合人们日常生活中的直观印象。然而符合直观印象的事情并不一定准确:


公理四:kid与砖块碰撞规则公理

yuuutu源码中关于kid和砖块碰撞规则的部分


猜想一:place_free()小数情况下判断规则猜想

如图,以kid向右跳过一堵高墙为例。

kid向右跳过一堵高墙

从公理四中的代码中不难看出,这种情况下kid能否越过高墙,取决于在最高点处的place_free(x+hspeed,y)是真还是假:如果是假,执行的动作是:令kid贴紧墙体,并令kid的水平速度为0,即不发生水平移动,也就无法越过高墙;否则,不发生任何事,kid保持正常水平速度,在这个步循环中的特定时刻,kid的坐标加上这个速度,就越过了高墙。

那么,函数place_free()是什么?翻阅文档,描述如下:

文档中对place_free()函数的描述,特别鸣谢玉米汉化

即,假设把当前物体移动至指定位置,判断它是否会与某些固体实例相碰撞,返回计算结果。它不会实际移动物体,只是假设移动到指定的位置。

在本例中,固体实例是砖块,其他都是非固体实例。

(也就是用来判断一下,如果他继续往前走会不会碰砖头)

当各个实例的位置都是整数值时,对是否发生碰撞的判断较容易。以两个水平坐标值相等的等大矩形为例(图中1个小方格代表1个像素):

碰撞的边界条件

假设蓝色矩形的头(最上面一行像素的竖直位置)是10,那么绿色矩形的脚(最下面一行像素的竖直位置)最少是10才能保证二者在交界处发生碰撞;是9则不发生碰撞。

那么如果绿色矩形的位置可以是小数呢?(实际上在IWBTG的一般引擎——GameMaker中这也是可以的)根据经验,我们作出以下猜想:

  1. 绿色矩形的脚大于9即是发生碰撞。

  2. 绿色矩形的脚不小于10即是发生碰撞。

  3. 绿色矩形的脚四舍五入为整数值后,大于9即是发生碰撞。

实验一:小数位置下place_free()的判断规则探究实验

使用GameMaker编写程序进行测试,蓝色矩形、绿色矩形都是长度80,宽度60,绿色矩形是固体,由蓝色矩形判断在本身位置的place_free(),结果如下:

测试用例1
测试用例2
测试用例3
测试用例3.5
测试用例4
测试用例5

做出初步结论,蓝色矩形的脚四舍五入为整数值后,大于20即是发生碰撞。猜想1的分支3成立。

但此处隐藏着一个诡异的设定。新增将蓝色矩形高度修改为61的另一组测试用例,结果如下:

测试用例7
测试用例8

由此可见,如果蓝色矩形的高度为偶数,则小数部分不大于0.5判舍,大于0.5则判入;

否则,根据整数部分的奇偶性判断舍入:

如果整数部分是奇数,则小数部分小于0.5判舍,不小于0.5则判入;

如果整数部分是偶数,则小数部分不大于0.5判舍,大于0.5则判入。

(非常诡异,我不理解GameMaker为什么会出现这样的情况)

kid的碰撞盒高度为21像素,是奇数,因此遵循后一种判断规则,即小数部分等于0.5时,是舍是入取决于整数部分的奇偶性。由于该种情况下判断方式过于复杂,后续不进行讨论。

于是,当kid的脚四舍五入后高于高墙的头,也即kid的脚高于(高墙的头-0.5像素的位置)时,就算kid跳过了高墙,此时向高墙方向走就能走到墙上。

(举个例子,假如墙的头是512,那kid的脚高于511.5,比如511.49、511.3等,就算他跳过了。)


推论二:怎么才算kid跳过了障碍推论

当kid的脚高于(高墙的头-0.5像素)时,就算kid跳过了高墙。


定义一:平地情况下的稳定状态定义

对于kid的一组y坐标和竖直速度值,如经过一个步循环后这组值没有变化,则称kid处在稳定状态。


推论三:kid稳定状态下起跳,起跳点是多高推论

首先规定,起跳点就是开始跳跃的那一步中kid的脚。

有读者朋友可能会问,这不是废话吗,不就是地面的头-1吗?

首先抛出结论,不是。

事实就是最好的证明

图为标准yuuutu引擎下测试结果。

kid的y坐标+8就得到了脚,是511.40,而地面的头是512,并不符合我们的猜想。下面解释原因。

根据yuuutu源码,本例中由playerStart创建的player,初始y坐标是503。

yuuutu源码:playerStart-Create
yuuutu源码:playerStart-Room Start

在kid被创建后玩家无操作,在一个步循环中,竖直速度由于重力效应从0改变成0.4,于是竖直位置增加0.4。此时,kid的脚是511.40,竖直速度是0.4,不与砖块发生碰撞(511.40四舍五入是511,不足512)。

下一步,kid的竖直速度变成0.8,脚变成512.20,发生了与砖块的碰撞。由于固体的“碰撞弹回”效应(即物体发生与固体的碰撞事件,则位置会回到上一步的位置),kid的脚变回511.40。随后在公理四的代码中,kid的竖直速度被赋值为0,此时kid的脚是511.40,竖直速度是0。

再下一步,kid的竖直速度变成0.4,脚变成511.80,发生了与砖块的碰撞。由于固体的“碰撞弹回”效应,kid的脚变回511.40。随后在公理四的代码中,kid的竖直速度被赋值为0,此时kid的脚是511.40,竖直速度是0,与上一步一致。因此在后续的时间内,kid稳定在脚是511.40,竖直速度是0的状态。

这是在自然状态下,由直接摆放在地面上的playerStart创建出的player的变化规律。但player的稳定状态并不止这一种,由上面的推理可知,一种状态是稳定状态当且仅当其有如下性质:

  1. kid在当前位置不与砖块相碰。

  2. kid的竖直速度是0。

  3. kid在下一步与砖块相碰。

其中第1条除非一开始就把playerStart放在砖里,否则是不会发生的。(因为一碰就被弹回了)而在本例中,满足第2和第3条的kid的脚必处在下述区间:

(511.10, 511.50)

左限制条件是511.50-0.4(竖直速度是0,重力效应加0.4后与砖块相碰),右限制条件是511.50(当前不与砖相碰)。

因此:

如果kid站在地面上稳定后起跳,起跳点必在下述区间:(地面的头-0.9, 地面的头-0.5)


定义二:kid的ya定义

kid的y坐标的小数部分称为kid的ya(y-alignment),如kid的y坐标是511.10,其ya则是0.10。


推论五:kid站在地面上起跳,最高能跳多高推论

之前已经计算出kid的最大跳跃高度是143.625,结合推论四,有:

如果kid站在地面上稳定后起跳,则根据ya的不同,最高点必在下述区间:(地面的头-144.525, 地面的头-144.125)


推论六:为什么常规跳法一般跳不了4.5格推论

4.5格高墙的头=地面的头-144,根据推论二(怎么才算kid跳过了障碍推论),kid的最高点也就必须高于(地面的头-144.5)才算他跳过去了。由于游戏中操作复杂,随机性很强,kid的ya可能处于任意值,就像抛硬币一样。假设kid的ya在可能范围,即(0.1, 0.5)内随机取值,且玩家操作非常完美(正好与推论一中所述符合),那么:

如果kid可跳过4.5格,其最高点必处在:

(地面的头-144.525, 地面的头-144.5)

于是,其起跳点必处在:

(地面的头-0.9, 地面的头-0.875)

其ya就必处在:

(0.1, 0.125)

而在地面上稳定后其ya是:

(0.1, 0.5)

故能跳过去的概率是:

(0.125-0.1)/(0.5-0.1)=6.25%

这个概率很小,在大量重复实验中平均每16次会出现一次。

实际上,玩家的操作也不一定能做到那么精确。推论一中计算表明,在出现失误的情况下次优跳法跳出的高度也只有143.6,无论kid的ya是多少,都不能越过4.5格。所以,用平地起跳的常规跳法去跳4.5格,一般要么就是操作失误,要么就是kid的ya不在那可怜的6.25%范围内(玩家并不能用肉眼直接看出kid的ya是多少),实战价值不大,这就是使用离地跳的必要性。即:

由于kid的ya随机性和操作的严格性,用常规跳法跳过4.5格的实战价值不大,有必要使用离地跳。


公理五:kid起跳判断公理

yuuutu引擎中关于起跳判断的代码如下(反重力情况略去):

yuuutu的核爆码风

在普通地面上起跳时,发生的是否一段跳就取决于place_meeting()函数的返回值是否真。place_meeting()的文档描述如下:

place_meeting()的文档描述

即,假设当前物体在指定位置,判断其是否会与指定实例碰撞,并返回结果。与place_free()很相似,只是place_free()判断固体实例,本函数则判断指定的实例。

与实验一相似的实验表明,place_meeting()对小数的处理与place_free()一致,故不难得出,使得其判断为真的kid的脚必低于(地面的头-1.5)。例如地面的头是512,则kid的脚需低于510.5(注意place_meeting()的判断点在y+1),如510.51,511等。即:

对于在平地起跳的情况,如kid的脚低于(地面的头-1.5),则使用的是一段跳。


定义三:平地情况下的不稳定状态定义

称kid不是处在稳定状态,却能使用一段跳的状态为不稳定状态。


推论七:为什么离地跳有战略价值推论

由推论三可知,kid稳定状态下起跳,起跳点处在下述范围内:

(地面的头-0.9, 地面的头-0.5)

而公理五表明,一段跳的使用条件,是kid的脚在下述范围内:

(地面的头-1.5, 地面的头-0.5)

未必是处在稳定状态。

可见,对于kid脚的某些更高的取值,kid不是处在地面稳定状态却能进行一段跳(这也是“离地”二字的含义),并且在操作完美前提下都能越过4.5格。因此,积极寻找这种不稳定状态来起跳,对于跳过4.5格就很有帮助。不妨一算,假设不稳定状态下kid的脚在该范围内随机取值,能跳过4.5格的概率是:

(1.5-0.875)/(1.5-0.5)=62.5%

是稳定状态下6.25%的整整10倍。

此外,离地跳也使得kid在某些非完美操作下也能越过4.5格。例如,次完美操作对应的跳跃高度是143.6像素,常规跳法不可能跳过4.5格。而增大了kid脚的范围后,只需其处在下述区间,即可越过4.5格:

(地面的头-1.5, 地面的头-0.9)

跳过的概率是:

(1.5-0.9)/(1.5-0.5)=60%

从0到60%,挺恐怖的不是吗?

即:

离地跳能大大提高跳过4.5格的概率,有实战价值。


理论数据

数据一:如何将ya=0.4调整至(0.1, 0.125)

在标准yuuutu引擎中,kid从平地上的playerStart出生,稳定后ya是0.4,此时如果存档,读档后ya也会是0.4。因此,虽然在实战中ya不可见且会受到多种高随机性因素影响,但0.4是一个相对确定可控的值。此时如果能通过某些简单操作使稳定后的ya处在(0.1, 0.125),则在完美二段下就可以直接越过4.5格障碍。

通常改变稳定后ya的操作是原地一段跳。如果所需的高度容易控制,则可以在实战中通过这样的跳跃将ya调整至所需的值。显然,跳跃次数越少可控性就越强。根据计算,对初始ya为0.4,各个步数的一段跳进行一次后会将稳定后的ya改变为下列值:

${一段跳步数}: ${新ya}

(注:冒号前的数字表示一段跳步数,即如果在第0步按下跳跃键,第5步松开跳跃键,则称一段跳的步数是5步。因在第22步及以后松开跳跃键已经不会发生速度截断,故一段跳步数最多是22。)

可见,不能通过一次一段跳将ya从0.4改变至(0.1, 0.125)。退一步搜索可行的两次一段跳是否存在,结果如下:


(${首次一段跳步数}, ${二次一段跳步数}): ${新ya}

注意,两次一段跳的步数可以互换,结果不变。

两次一段跳都控制到想要的步数一般较为困难。3次一段跳的可行方案很多,筛选出其中每一段都是9步以下或全力跳的可行方案如下:

(${首次一段跳步数}, ${二次一段跳步数}, ${三次一段跳步数}): ${新ya}

22表示全力跳。

其中还有一种特殊情况:当在0.4的初始ya下连续三次全力跳起后,ya会改变为0.1,根据实验一中的结论,如果地面的头是偶数(在以8, 16, 32为单位网格的地图中很常见),则kid站在地面上时,其y坐标的整数部分就是奇数,小数部分是0.5会判定为与地面相碰撞,因此其ya会稳定在0.1。由于全力跳非常容易控制,在一般情况下,都可以通过这种方式将ya调整至0.1,然后在稳定状态下跳过4.5格。

(注意,这些数据的大前提是使用GameMaker8的yuuutu引擎。著名跳跃测试工具jtool使用的GameMaker版本是GameMaker: Studio,其中的情况可能与本理论不符合,尤其是最后提到的特殊情况。)


数据二:初始ya=0.4下一般的离地跳操作

前述中指出,准备动作结束后再次一段跳的时机,是“kid的脚离地面不足1.5像素且超过0.875像素”。由于kid的最高下落速度是9像素每步,加上重力效应,一步后y坐标最大增量是9.4,远超(1.5-0.875)=0.625。因此,对于固定的初始ya,如果准备动作中一段跳的力度不合适,kid可能不会落到(0.875, 1.5)的区间内,也就意味着离地跳必然失败。下面以固定初始ya=0.4为前提讨论,经计算,这种情况下可以顺利跳上4.5格的动作如下:


(${首次一段跳步数}, ${二次一段跳步数}): 二次一段跳起跳点

括号中第一个数是第一次一段跳的步数,第二个数是第二次一段跳的时刻(取第一次一段跳为第0步),冒号后的数是第二次一段跳的起跳点。例如,数据 (4, 26): -0.405 表示:在第0步使用一段跳跳起来,第4步松开跳跃键,第26步再次按下跳跃键并全力进行二段跳,则能够从(地面的头-0.405)处起跳,跳过4.5格。

从表中也可以看出,一段跳的步数是2、12、15、16、17、21、22时,离地跳必定失败。此外也可以看出,第一次用8步一段跳可以使第二次一段跳起跳点最高。


总结

公理一(kid跳跃力度公理):kid的一段跳跃力度是-8.5,二段跳跃力度是-7。

公理二(kid重力值公理):kid的重力值是0.4像素每平方步。

公理三(kid重力与速度效应顺序公理):在每个步循环中,对kid是否跳跃进行的判断、kid的重力对kid竖直速度的改变、kid竖直速度对其实际位置的改变,顺序如下:判断kid是否进行跳跃 -> 给kid的竖直速度加上kid的重力 -> 给kid的竖直位置加上kid的速度。

推论一(kid最大跳跃高度推论):在开始跳跃20步后松键,下一步重按,即可达到常规二段跳模式下的最大跳跃高度,143.625像素。

公理四(kid与砖块碰撞规则公理):代码略

猜想一(place_free()小数情况下判断规则猜想):猜想中指定的两矩形固定位置相碰的情形中,碰撞检查函数place_free()小数情况下判断规则可能如下:

  1. 绿色矩形的脚大于(蓝色矩形的头-1)即是发生碰撞。

  2. 绿色矩形的脚不小于蓝色矩形的头即是发生碰撞。

  3. 绿色矩形的脚四舍五入为整数值后,大于(蓝色矩形的头-1)即是发生碰撞。

实验一(小数位置下place_free()的判断规则探究实验):实验证实猜想一中的分支3成立。

推论二(怎么才算kid跳过了障碍推论):当kid的脚不低于(高墙的头-0.5像素)时,就算kid跳过了高墙。

定义一(平地情况下的稳定状态定义):对于kid的一组y坐标和竖直速度值,如经过一个步循环后这组值没有变化,则称kid处在稳定状态。

推论三(kid稳定状态下起跳,起跳点是多高推论):如果kid站在地面上稳定后起跳,起跳点必在下述区间:(地面的头-0.9, 地面的头-0.5)。

定义二(kid的ya定义):kid的y坐标的小数部分称为kid的ya(y-alignment)。

推论五(kid稳定状态下起跳,最高能跳多高推论):如果kid站在地面上稳定后起跳,则根据ya的不同,最高点必在下述区间:(地面的头-144.525, 地面的头-144.125)。

推论六(为什么常规跳法一般跳不了4.5格推论):由于常规跳法对ya要求和玩家操作过于苛刻,而ya和操作的可控性不强,用常规跳法跳过4.5格的实战价值不大,有必要使用离地跳。

公理五(kid起跳判断公理):对于在平地起跳的情况,如kid的脚低于(地面的头-1.5),则使用的是一段跳。

定义三(平地情况下的不稳定状态定义):称kid不是处在稳定状态,却能使用一段跳的状态为不稳定状态。

推论七(为什么离地跳有战略价值推论):离地跳能大大提高跳过4.5格的概率,有实战价值。

数据一(如何将ya=0.4调整至(0.1, 0.125)):一次一段无法做到,二次、三次一段可以做到。通常情况下三次全力跳可以将ya调整至0.1。

数据二(初始ya=0.4下一般的离地跳操作):如果初始ya=0.4,而第一次一段跳的步数是2、12、15、16、17、21、22时,离地跳必定失败。使得起跳点最高的第一次一段跳是8步。


感谢各位读者朋友的认真阅读。如有错误,欢迎私信或在评论区指正。 


第一次修改:

修改零:更换了一段过纳豆刺阵图。原图可以站倒刺。

修改一:将离地跳的跳跃时机修改为“距地面不足1.5像素且超过0.875像素”,原表述“距地面不足1.5像素”只是能用一段跳的范围,而不是使用离地跳的范围,是错误表述。

修改二:重写推论一,原表述逻辑不清晰。

修改三:总结中ya的定义修改为“定义二”,原写法“定义一”属笔误。

修改四:添加了理论数据部分。

修改五:修改实验一的步骤和结论,原实验步骤和结论有误。

EOF

离地跳(BH)-iw百科的评论 (共 条)

分享到微博请遵守国家法律