文科生也能看懂的黑客數(shù)學(xué)-如何制作瞄準(zhǔn)機(jī)器人

在許多年前有一條流傳在許多源碼、教程和論壇帖子上的所謂“CalcAngle”方法。是誰發(fā)明的這個方法我暫且蒙古。簡而言之,它非常魔幻,尤其是57.2957...這個神奇數(shù)字......(我們并不一定需要角度轉(zhuǎn)弧度)光靠閱讀代碼也很難理解實(shí)際發(fā)生的事情。 它長這個樣 void CalcAngle( float *src, float *dst, float *angles ) { double delta[3] = { (src[0]-dst[0]), (src[1]-dst[1]), (src[2]-dst[2]) }; double hyp = sqrt(delta[0]*delta[0] + delta[1]*delta[1]); angles[0] = (float) (asinf(delta[2]/hyp) * 57.295779513082f); angles[1] = (float) (atanf(delta[1]/delta[0]) * 57.295779513082f); angles[2] = 0.0f; if(delta[0] >= 0.0) { angles[1] += 180.0f; } } 顯然,你已經(jīng)頭昏眼花不愿意繼續(xù)理解這段代碼,不過沒關(guān)系因?yàn)樗缫驯缓诳蛡儊G進(jìn)trash bin??因此你不必為此煩惱 因此,我不會像拼樂高積木一樣復(fù)制粘貼這個我根本不知道做了什么的函數(shù),而是要教你一種更好、更快速、更準(zhǔn)確的方法來計算本質(zhì)上相同的東西。這將適用于內(nèi)部或外部黑客(主要的工作是計算,基本原理對于其他FPS游戲同樣適用,但我以起源引擎游戲舉例),如果你想要在起源引擎游戲中使用這樣的黑客,我強(qiáng)烈建議您嘗試使用內(nèi)部黑客,因?yàn)槠鹪匆妫ㄒ苍S包括起源2)提供了一些非常有用的輔助方法。 如果您不知道 CalcAngle 的作用,它只是在src和dst兩個參數(shù)中獲取兩個 3D 位置,并計算dst在angles的角度然后輸出。這基本上算是瞄準(zhǔn)機(jī)器人,您將本地玩家的eye position(說白了,攝像機(jī)位置)傳入src,將目標(biāo)的頭部position傳入dst,然后利用得到的角度設(shè)置viewangles,你的準(zhǔn)星就會跑到敵人頭上。 學(xué)一點(diǎn)向量
認(rèn)為自己對空間向量已經(jīng)熟悉得不能再熟悉的同學(xué)可以直接跳過這一部分 在C艸中,Vector是存儲笛卡爾坐標(biāo)值的第 n 維數(shù)據(jù)類型。在最基本的層面上,它是一條直線。最常見的向量是 2 維和 3 維的。一維向量通常稱為標(biāo)量,只是實(shí)數(shù)(即沒有復(fù)數(shù))。存在更高維的向量,但我們事實(shí)上無法在笛卡爾平面上表示它們,因?yàn)槲覀兊唾v的三維生物無法在三維世界中想象它們。 如果你沒有結(jié)束高中一年級的課程學(xué)習(xí),那么你也許對空間向量還不了解,這也許會影響你的想象能力,但是沒關(guān)系 這是一個 3 維向量 (3, 7, 5) 的樣子:
向量可以用多種方式表示: 對于沒學(xué)過空間向量的同學(xué)的小提示,只需將向量起點(diǎn)視為原點(diǎn)理解 單位向量形式: 3i + 7j + 5k 這在數(shù)學(xué)中經(jīng)常使用,但在高中階段的教科書中只是提到一嘴罷了,因?yàn)樗举|(zhì)上可以被有序集形式替代,并且它計算機(jī)科學(xué)中完全沒用。i、j 和 k 分別代表終點(diǎn)的 x、y 和 z坐標(biāo) 有序集形式(A.K.A.坐標(biāo)形式): (3, 7, 5) 你的數(shù)學(xué)老師會教你,將向量起點(diǎn)放到原點(diǎn),向量終點(diǎn)的坐標(biāo)就是有序集形式的向量表示方式。它非常好理解,對于坐標(biāo)計算而言也非常方便,只需要一個統(tǒng)一的空間坐標(biāo)系。 就像示意圖中坐標(biāo)系上的有序?qū)σ粯印1窘坛讨械南蛄繋缀跬耆捎眠@種形式。 極坐標(biāo)形式: (9.11, 56.71°) 這是最有趣的形式,因?yàn)檫@是不是在笛卡爾平面上而是在極平面上表示的矢量。第一項(xiàng)是幅度或斜邊,第二項(xiàng)是矢量形成的角度。在本教程結(jié)束時,我們將基本上轉(zhuǎn)換為這種形式。因?yàn)関iewangles本質(zhì)上是帶有三個角度的數(shù)組(是的,對于瞄準(zhǔn)我們只用到兩個)
向量可以看作是兩個三角形的組合,所以我們可以對它進(jìn)行正則三角運(yùn)算??梢哉f最重要的部分是找到向量的大小。如前所述,大小是向量的長度。有兩種方法可以做到這一點(diǎn)。我們可以使用tan并求解 XY 斜邊,然后tan再次使用并求解幅度。但我們可以做得更快。您可能已經(jīng)在高一學(xué)習(xí)平面向量的時候(或者甚至在初中幾何)學(xué)習(xí)過平面距離公式。這是從勾股定理推導(dǎo)出來的a^2 + b^2 = c^2。 我們將使用它的 3D 變體,它就像 2D 公式一樣,只是另一個維度的額外術(shù)語。 模= sqrt (( x2 - x1 )^ 2 + ( y2 - y1 )^ 2 + ( z2 - z1 )^ 2 ) 當(dāng)然,因?yàn)槲覀兲幚淼氖窍蛄浚跃嚯x總是與原點(diǎn)的距離。所以,公式可以進(jìn)一步簡化。 模= sqrt ( x ^ 2 + y ^ 2 + z ^ 2 ) 對于沒有學(xué)習(xí)過C艸的同學(xué),sqrt()函數(shù)用于開方 對于起源引擎黑客的小技巧 起源引擎的SDK提供了由 Vector(x, y, z) 初始化的 Vector 類,并且有一個方便的函數(shù) Vector::Length 可以計算大小。 對于其他游戲我建議您創(chuàng)建一個包含 x、y 和 z 坐標(biāo)的結(jié)構(gòu)以及一個計算向量大小的函數(shù)。 學(xué)完了空間向量,現(xiàn)在我們切入正題。 我們要做什么
所以我們想做一個瞄準(zhǔn)機(jī)器人。像 CalcAngle 一樣,我們需要找出使我們直接瞄準(zhǔn)敵人的viewangles角度。 我們需要做的第一件事是獲取local player攝像機(jī)在地圖中的位置。這很容易。您只需要獲取原點(diǎn)向量并將其添加到視圖偏移量。然后你必須找到敵人的頭部位置 對于起源引擎黑客,可以使用函數(shù)IClientEntity::SetupBones找到玩家頭部位置,然后使用CStudioHdr類獲取碰撞箱。外部黑客可以通過迭代骨骼結(jié)構(gòu)并找到您正在尋找的骨骼,這里不再贅述。 其他游戲黑客會有各自的方法,也許可以在一些論壇中找到解決方案 所以我們需要找到的是目標(biāo)相對于攝像機(jī)的坐標(biāo)
也就是我們和目標(biāo)之間的向量。 從目標(biāo)的head position減去我們的eye position,可以很容易地計算出這個向量。得到的結(jié)果將是目標(biāo)相對于攝像機(jī)的位置。向量加減運(yùn)算對于任何一個接受過高中教育的人來說都非常容易。 如果您沒學(xué)習(xí)過,在我們的例子中: (3, 4.5, 5) - (-2, -5, 5) ----------------- (5, 9.5, 0) 起源引擎SDK提供了輔助函數(shù)VectorSubtract(a, b, c),其中相減的向量為a和b,得到的向量為c。DX SDK也有D3DXVec3Subtract(out, a, b) 你當(dāng)然也可以自己寫一個,不難的 于是我們得到了
很好,進(jìn)入下一步 簡單的三角函數(shù)
有人不知道sin是什么,我不說是誰 有了我們想要瞄準(zhǔn)的向量之后,就要計算瞄準(zhǔn)這個向量的角度。 如果你已經(jīng)學(xué)習(xí)了平面向量,那么空間向量的角度計算只需要視作兩個平面坐標(biāo)系就可以了(不嚴(yán)謹(jǐn)?shù)恼f法,但是可以這么理解) 假設(shè)示例玩家的視角為 (12°, 30°),分別為俯仰角和偏航角。讓我們在極坐標(biāo)平面上繪制視角 這里規(guī)定半徑均為1
Yaw便是偏航軸,Pitch便是俯仰軸,它們分別繞著右手坐標(biāo)系的y軸和x軸,因此對應(yīng)起源引擎中的viewangles.y和viewangles.x 現(xiàn)在我們讓向量形成一個直角三角形,模為斜邊,就可以使用標(biāo)準(zhǔn)三角函數(shù)來找到角度。(不知道為什么的翻回前面看) 轉(zhuǎn)化為圖形
有X和Y,可以使用反正切來找到偏航角。 有 Z 和斜邊長度,所可以使用反余弦來求出音高。 對于高中的你,也許是一頭霧水吧?反正切就是tan的反函數(shù),反余弦就是cos的反函數(shù),就這么簡單,這里只需要用現(xiàn)成的函數(shù) 偏航軸 角度= arctan(y/x) (因?yàn)閟in = 對邊/斜邊, cos = 鄰邊/斜邊, tan = sin/cos) pitch = arccos(z/斜邊) 或者直接使用起源引擎SDK的VectorAngles(vector, angle)函數(shù)?? 大功告成?
是的,你已經(jīng)成功計算了角度,只需要hook到viewangles并賦值為計算出來的角度,你的準(zhǔn)星就會瞬移到敵人頭上捏。 什么?你不想準(zhǔn)星瞬移?很簡單的 首先是把算出來的角度減去當(dāng)前攝像機(jī)角度,得到角度差 把你的瞄準(zhǔn)機(jī)器人函數(shù)來個延遲循環(huán)(起源引擎內(nèi)部可以直接監(jiān)聽create move) 然后把要加上viewangles的值除以一個常數(shù) cmd -> viewangles += 角度差 / 4 當(dāng)然,你也可以為俯仰和偏航軸使用不同的常數(shù) cmd -> viewangles.y += 角度差.y / 3 cmd -> viewangles.x += 角度差.x / 4 使用隨機(jī)數(shù)生成這個常數(shù)也可以哦 學(xué)習(xí)愉快~~~