談?wù)凪C戰(zhàn)斗(三)
上次我談到衡量擊退的價(jià)值,所以我做了個(gè)打點(diǎn)計(jì)時(shí)器。改進(jìn)之后,計(jì)時(shí)器還會(huì)記錄目標(biāo)與我的高度差。
結(jié)論:
擊退的XZ速度,是擊退力度與原本XZ速度一半做疊加。因此,原本靜止的物體受到0.4力度的擊飛后,會(huì)在XZ方向以0.4的速度飛出。
玩家近戰(zhàn)攻擊生物時(shí),擊退的方向是兩者中點(diǎn)的連線。
生存模式下,近戰(zhàn)攻擊距離為3格,修改REACH_DIST屬性并不增長攻擊距離(但理論上可以縮短);創(chuàng)造模式下影響,但可以忽略。
生物落地一瞬間會(huì)出現(xiàn)速度異常,加速后退。原因不明。
對(duì)于僵尸這種移速屬性為0.23,實(shí)際移速為0.115的生物來說,一次0.4的擊退,會(huì)讓他最多倒退1.25格左右,大約花24刻它才能走回被擊退的位置。
有一些事情必須先想清楚,那就是,MC的物理系統(tǒng)與現(xiàn)實(shí)有一定差別,這差別來自多方面:
MC的時(shí)間并非連續(xù)的,而是按照刻(tick)來的。比如某個(gè)物體第一刻在(0,0,1)的位置,下一刻在(0,0,2)的位置,那么我們并不能說物體“在1.5刻時(shí)處于兩者之間”,因?yàn)楦揪筒淮嬖?.5刻。這與現(xiàn)實(shí)世界有1.5s、1.05s有很大不同。在進(jìn)入量子力學(xué)的尺度之前,現(xiàn)實(shí)世界的物理是連續(xù)且可分的。MC在前端會(huì)做一個(gè)現(xiàn)實(shí)上的插值,但在實(shí)際計(jì)算碰撞的時(shí)候,很容易發(fā)生穿透——你玩游戲的時(shí)候之所以不會(huì)有明顯的感受,都是因?yàn)楹笈_(tái)做了彌補(bǔ)處理。
MC具有阻力系統(tǒng),所以并不是機(jī)械能守恒的。不過這個(gè)倒也很好說,看一眼它的阻力機(jī)制就知道了。不同的實(shí)體會(huì)有不同,是否處于水中也會(huì)對(duì)阻力有影響。
機(jī)械能守恒等在連續(xù)世界里,靠積分分散成立的東西,在MC里只能用來做近似估計(jì)。比如,你想通過起跳速度
來計(jì)算跳躍高度的話,那么你計(jì)算出來的只是近似高度,結(jié)果必須用excel等時(shí)機(jī)推演一下。比如,如果重力加速度是10,你以10的速度起跳,那么在連續(xù)世界里,
,但實(shí)際上,你會(huì)往上移動(dòng)10格。因?yàn)?,你的速度在這一個(gè)tick內(nèi)都不會(huì)變化,所以直接上飛10格后停在空中,然后又10速下落了。
在這樣一個(gè)不連續(xù)的世界,我們要如何定義“速度”?那必然是”下一刻和這一刻之間的位移”。為什么不是這一刻與上一刻的位移?因?yàn)樵诖a里有motion等變量,它們會(huì)指導(dǎo)這個(gè)物體下一刻移動(dòng)到哪里,這樣與編程里的概念對(duì)應(yīng)較好。至于編程里為什么那么定義,我覺得但凡自己寫過游戲里的運(yùn)動(dòng)系統(tǒng)的人都會(huì)知道,就不贅述了。
在現(xiàn)實(shí)世界里,速度的量綱和位移并不一致。另外,MC里的速度其實(shí)也有兩種,一種是“格每秒”,一種是“格每刻”。本文討論的基本都是“格每刻”。并且,假定MC里的方塊邊長為1米,這樣說起來省事。

那個(gè)很尖銳的灰色線繪制在右邊的副坐標(biāo)軸上,藍(lán)色和黃色的圓滑線繪制在左邊的主坐標(biāo)軸上。
黃色的線是僵尸和玩家的水平距離,藍(lán)色線是僵尸與玩家的垂直距離,灰色線是僵尸相對(duì)玩家的水平速度。
上次就很奇怪為什么玩家的速度會(huì)有一次抖動(dòng),這次結(jié)合了垂直距離可知,僵尸在接觸地面之前,往后倒退的速度會(huì)略微變快。

是的,還沒接觸地面,提前兩幀左右,倒退的速度卻自行變快。這怎么也講不通。倒退的速度增加,本來只有被擊退的第一幀而已。
我們都知道,在現(xiàn)實(shí)世界里,人類沒法直接二段跳,忽略空氣阻力的話,在空中怎么擺動(dòng)身體都沒法扭轉(zhuǎn)重心運(yùn)動(dòng)的路線。但是,在MC世界里,你在空中按方向鍵的話,是可以控制水平速度的。
所以是僵尸自己控制了速度導(dǎo)致嗎?那也說不通。如果是僵尸開始努力的話,不應(yīng)該往后倒退得越來越猛,畢竟僵尸是朝著玩家撲過去的,而不是被嚇得使勁往回跑。而且,這個(gè)事情必現(xiàn),不是因?yàn)殡S機(jī)因素導(dǎo)致。在這里記錄一下,留給以后看代碼分析了。
看到這,我需要研究一個(gè)問題,那就是,我對(duì)僵尸的擊退,會(huì)不會(huì)打歪。
如果你看過代碼的話,你會(huì)知道,多數(shù)普通的attackEntityFrom都會(huì)造成力度0.4的擊退。那么,玩家攻擊的時(shí)候,擊退的方向是玩家與怪物的連線,還是玩家的視野方向呢?

d1是兩者的x距離,d0初始是兩者的z距離。
這個(gè)怪異的循環(huán)是在干嗎?他是在施加隨機(jī)擾動(dòng),如果兩者在xz平面的距離小于0.01,他就會(huì)把d0和d1隨機(jī)設(shè)置一波,一直隨機(jī)到大于0.01。這代碼寫的有點(diǎn)奇怪,for括號(hào)里的第三部分完全可以提取到循環(huán)體內(nèi),第一段完全可以提到循環(huán)外面,整體寫成while循環(huán)才是正常人的寫法。
然后,我們按照xz距離把參數(shù)傳進(jìn)去,進(jìn)行擊退。也就是說,如果兩者距離大于等于0.01,那么擊退就是以中心連線算的,并非按照玩家視野朝向。所以,我們忽略了兩者連線的切向速度,這個(gè)研究方法并沒有問題。(補(bǔ)充:擊退附魔則是以玩家視野方向算,與此不一致,代碼分析略)

他被打之后,水平速度只有0.34,算上垂直速度也只有0.36。
0.4力度的擊退為什么擊飛后,目標(biāo)的速度不是0.4呢?
我們看看擊退的代碼。
物體的原本x、z速度折半,然后把strength按照xz參數(shù)作為方向參量正交分解為速度。
也就是說,如果物體原本在x、z方向不運(yùn)動(dòng)的話,那么你對(duì)他進(jìn)行0.4力度的擊退,它的XZ初速度必為0.4。
僵尸原本在XZ平面以0.115的速度向玩家靠近,受到了一個(gè)0.4力度的反向擊退,得到的新速度是0.4-0.115/2,約等于0.34,理論計(jì)算與實(shí)際吻合。Y方向獨(dú)享一份,就不管他了。
好了,這一部分理清楚了,那么,到底一次擊退有多大的價(jià)值呢?

平均幾次的實(shí)驗(yàn)結(jié)果來看,我們可以認(rèn)為,一次擊退大約能擊退1.25米,生物想要恢復(fù)原本的移動(dòng)速度大約需要20刻,但想走回被擊飛前的位置,大約需要24刻。也就是說,如果你近戰(zhàn),穩(wěn)定地用劍1秒(20刻)攻擊一次僵尸的話,僵尸身后只要有個(gè)1.5m的空間往后飛,那么你可以穩(wěn)定地確保僵尸離你越來越遠(yuǎn),直到你打不中。
查看代碼可以得知,玩家默認(rèn)的REACH_DISTANCE為5.0,也就是說只要不超過代碼里的額外限制的話,玩家可以攻擊5米內(nèi)的敵人……嗎?
上一段NetHandlerPlayServer的代碼。
如果你能看得見目標(biāo)的話,那么你可以夠到6m(36的平方根)的怪物;如果你看不見的話,只能打到3m的怪物(9的平方根)。即使你的REACH_DISTANCE再大也不能超過這個(gè)限制。
至于“能看見”的話,查看EntityLivingBase::canEntityBeSeen的代碼:
這就知道了,只取決于視線上有沒有實(shí)體方塊擋住,有就會(huì)變嚴(yán)格。有人說了,那我視線被擋住,隔著墻不是根本打不到嗎?實(shí)際上,因?yàn)檠舆t和動(dòng)畫插值等緣故,前端和后端可能有偏差。這里只是各自算各自的,前端判定了之后,后端再次判定罷了。
也就是說,普通情況下在開闊地帶,玩家有5米的攻擊距離,但是有了柵欄等在中間阻礙的話,3米的距離才比較穩(wěn)妥。果真如此嗎?實(shí)際上,我把自己用命令方塊精確傳送了一下,但是只能打掉三格以外的盔甲架。REACH_DISTANCE的含義還有待商榷?代碼里,這玩意看起來確實(shí)是用來處理方塊觸及的。


嚴(yán)格來說,他確實(shí)先用觸及距離做了判定,但是之后如果目標(biāo)超過3格,目標(biāo)實(shí)體就會(huì)被清掉了,設(shè)為MISS。
可我明明記得修改觸及距離對(duì)攻擊范圍有效???所以我打開游戲,掛上我的陣地做成附魔。實(shí)測發(fā)現(xiàn),在創(chuàng)造模式我能打五個(gè),手變長后我可以多打一個(gè)盔甲架,但是生存模式,仍然只能打3格的盔甲架。好吧,那就是沒有效果了。真遺憾,謹(jǐn)記3這個(gè)前端參數(shù)把。不過,前后端的不一致是不是給掛端留下了空間?
至于倒退速度的異常成因,以及對(duì)其他生物的分析,就留待下一篇記錄了。到時(shí)候打斷點(diǎn)看看代碼。