天天看點

遊戲設計中有經典的計算公式

第一個問題:符文系統和天賦系統存在的必要性和對戰局的影響?

先引入兩個概念:

Ehp:effective health point 有效生命

Ehp受自身的HP、閃避、防禦、護甲、韌性、格擋、招架、免傷、技能系數、等級加成、各種抗性等等數值影響。

舉例:假如你有1W生命,且有50%減傷(與對方命中無關),那你的ehp就是2W。

Edps:effective damage per second有效輸出

Edps受自身的攻擊力、命中值、暴擊率、暴擊效果、穿刺、急速、等級加成、各種屬性攻等等數值影響。

舉例:假如你的輸出間隔是1S,100%命中,攻擊力為100,暴擊率為100%,暴擊效果為150%,則你的edps為150。

則在在兩個人之間的勝負結果,始終可以用下面的公式來表示:

所謂的符文、天賦、裝備等等各種系統,歸根結底都是對人物數值的影響,本質上并無任何差別,每新增一個系統,不過是把每個屬性的數值成長上限放高而已。所有以上沒有哪個系統是必要存在的,今天可以做成符文系統,明天還可以換成後宮加成系統,表現形式不同而已。至于對戰局的影響,最優解的問題會談到。

第二個問題:關于數值成長中最優解的存在

(開會去。。。晚點填)

==============================================================

ELO等級分體系

(很久之前做過的PPT,東西太多有點亂,粘一部分上來)

簡介

ELO等級分體系是根據它的推廣者埃洛(elo) 名字命名,它是一種以數值表示的體系,将等級差别轉化 為分數或取勝機率。

理論基礎

粗略看一下很多比賽的成績表,能夠看出某個選手的表現是有起伏的,即有“狀态”之分。強手未必恒定表現好于弱手,每人之狀态在不同的日子不同的比賽裡都會有好壞不同。而總的來說整個生涯裡每一點上,一名選手的表現将大緻圍繞在某個平均水準上下波動,有時會有背離,而出現大背離的情況比出現小背離的情況頻率要低。

于是,有了ELO體系的第一個假定:可以建立這麼一個等級量表,某個體在這個表裡的不同表現将正常分布。

第二個假定簡單地說:在某一個特定的實力範疇裡,盡管可能存在實力上的差異,但總的來說可以預期沒有誰比誰好或差很多。由此可以定量劃分區間。

等級量表-區間尺度

等級差别是可能性方面的唯一重要因素。

指對陣雙方誰有多大機會勝/負/和,唯一影響因素在于他們之間的等級差别,這樣排除了難以确定的“狀态好壞”(第一假定),也排除了具體誰對誰的影響(第二假定)。

是以即使出現“爆冷”或 “克星”,也視為偶發情況,因為ELO體系是建立在樣本足夠大量的統計基礎上的。

标準分類間隔(附表)

即某一個等級裡最高與最低之間的差别。在國際象棋裡,FIDE(即國際棋聯)采用每200分為一個間隔的分類法,并且給每一個間隔取一個名字或排名以更好分辨。

常态分布函數

強手未必總是勝過弱手,于是就使用一個“常态分布函數來代表一名選手的波動表現,這是統計學上的概念。從這個函數裡可以得出另一個函數叫“常态機率函數” ,這個就定義了根據比賽對抗結果可得出的等級差别,或者根據已知的等級差别可得出的預期比賽對抗結果。它是這樣的:

P(D)這個值,就是以等級分差别D為自變量計算出來的預期取勝可能性(預期得分率),它可近似用下面這個公式來計算:

舉例一

Ra:表示隊伍A目前的等級分

Rb:表示隊伍B目前的等級分

Sa表示隊伍A的比賽結果,勝利S值為1,平局S值為0.5,失敗S值為0

Ea:表示A在這場比賽中的勝負值期望

Eb:表示B在這場比賽中的勝負值期望

其中Ea+Eb=1,也就是勝率和為1

舉例二

一個等級分1950的選手,她的對手等級分1700分,那麼她取勝的機會有多大呢? 

等級分差别D=1950-1700=250,代入上面那麼近似計算公式,就是:

也就是說,她勝利的機會有80.8%,大約是81%。事實上,看下表,即可得知等級分差别在246-256之間的強手預期取勝可能性就是81%。不用計算。

上面看不懂?沒關系!

目前等級分公式

Rn = Ro + K * (W - We)

Rn是賽事後的新等級分;Ro是賽事前的原等級分;K是單局得分的等級分點值,它是一個系數,取值有約定的;W是實際對局得分(勝得1、和得0.5);We是在原等級分基礎上的預期對局得分。 

這個公式是用來在連續基礎上(也就是每局或每個賽事之後)計算新等級分的。它把最新的表現調整考慮進先前的等級分中。它的邏輯意義是一個選手的表現高于他的預期得分以及低于他的預期失分。

系數K決定了事前等級分和本次表現分的相應權數。K值越高,那麼越近的賽事表現的分量越大。反之則反之。一般K值範圍從10到32。下面是一個K取值參考表:

舉例三

一個隊伍等級分1650,比賽中分别與等級分為2050、1270和1550的三個隊伍對了陣,戰勝了低分的兩個,逼和了最高分的那個。問新等級分是多少?

K值取10;Ro=1650;W(勝2和1) = 1 + 1 + 0.5 = 2.5

We = P(1650 - 1270) + P(1650 - 1550) + P(1650 - 2050)

=0.910 + 0.638 + (1-0.921)

=1.627

套入第二個公式,即Rn = Ro + K * (W - We) = 1650 + 10 * (2.5 - 1.627) = 1659

也就是她在這次賽事後,等級分升了大約9分,成為1659。

舉例四

某競技場隊伍等級分2350,11場比賽5勝6負,K取32;對陣11場情況如下:

已知原等級分Ro為2350,已知本次比賽實際對局得分W=5,已知K值取32,已知(總)預期對局得分We為5.24, 計算時可省略為5.2,那麼根據公式(2),Rn = Ro + K * (W - We),新等級分Rn = 2350 + 32 * (5 - 5.2) = 2343.6 , 大約是2344,比之前下降了。

課後小思考

①K值如果往上取,會造成什麼情況?

②K值如果往下取,會造成什麼情況?

③WOW與DOTA天梯明顯的不同在什麼地方?

④以上的不同為WOW帶來了什麼漏洞?

⑤WOW裡隊伍積分和個人積分分别有什麼用?

回複:

1、卡馬克快速平方根

平方根倒數速算法

它讓計算平方根倒數的計算速度提高了4倍,導緻了3D遊戲的革命。沒有這個算法,恐怕到現在3D遊戲裡的物體仍然沒影子(想想看CS的畫面)。

這個算法在上世紀就出現了,但是在10年前才引起遊戲圈的關注,算法的原理很清楚,但是作為算法核心的那個常數,至今沒人知道它是怎麼得出來的。有傳言說是外星人入侵網際網路時留下了這個常數。遊戲業各位大牛紛紛在源代碼後面寫上了一句注釋:what the fuck?

在3D圖形程式設計中,經常要求平方根或平方根的倒數,例如:求向量的長度或将向量歸一化。C數學函數庫中的sqrt具有理想的精度,但對于3D遊戲程式來說速度太慢。我們希望能夠在保證足夠的精度的同時,進一步提高速度。

Carmack在QUAKE3中使用了下面的算法,它第一次在公衆場合出現的時候,幾乎震住了所有的人。據說該算法其實并不是Carmack發明的,它真正的作者是Nvidia的Gary Tarolli(未經證明)。

//

// 計算參數x的平方根的倒數

float InvSqrt (float x)

{

float xhalf = 0.5f*x;

int i = *(int*)&x;

i = 0x5f3759df - (i >> 1); // 計算第一個近似根

x = *(float*)&i;

x = x*(1.5f - xhalf*x*x); // 牛頓疊代法

return x;

} 該算法的本質其實就是牛頓疊代法(Newton-Raphson Method,簡稱NR),而NR的基礎則是泰勒級數(Taylor Series)。NR是一種求方程的近似根的方法。首先要估計一個與方程的根比較靠近的數值,然後根據公式推算下一個更加近似的數值,不斷重複直到可以獲 得滿意的精度。其公式如下:

函數:y=f(x)

其一階導數為:y'=f'(x)

則方程:f(x)=0 的第n+1個近似根為

x[n+1] = x[n] - f(x[n]) / f'(x[n])NR最關鍵的地方在于估計第一個近似根。如果該近似根與真根足夠靠近的話,那麼隻需要少數幾次疊代,就可以得到滿意的解。

現在回過頭來看看如何利用牛頓法來解決我們的問題。求平方根的倒數,實際就是求方程1/(x^2)-a=0的解。将該方程按牛頓疊代法的公式展開為:

x[n+1]=1/2*x[n]*(3-a*x[n]*x[n])将1/2放到括号裡面,就得到了上面那個函數的倒數第二行。

接着,我們要設法估計第一個近似根。這也是上面的函數最神奇的地方。它通過某種方法算出了一個與真根非常接近的近似根,是以它隻需要使用一次疊代過程就獲得了較滿意的解。它是怎樣做到的呢?所有的奧妙就在于這一行:

i = 0x5f3759df - (i >> 1); // 計算第一個近似根超級莫名其妙的語句,不是嗎?但仔細想一下的話,還是可以了解的。我們知道,IEEE标準下,float類型的資料在32位系統上是這樣 表示的(大體來說就是這樣,但省略了很多細節,有興趣可以GOOGLE):

bits:31 30 ... 0

31:符号位

30-23:共8位,儲存指數(E)

22-0:共23位,儲存尾數(M)所 以,32位的浮點數用十進制實數表示就是:M*2^E。開根然後倒數就是:M^(-1/2)*2^(-E/2)。現在就十厘清晰了。語句 i>>1其工作就是将指數除以2,實作2^(E/2)的部分。而前面用一個常數減去它,目的就是得到M^(1/2)同時反轉所有指數的符号。

至于那個0x5f3759df,呃,我隻能說,的确是一個超級的Magic Number。

那個Magic Number是可以推導出來的,但我并不打算在這裡讨論,因為實在太繁瑣了。簡單來說,其原理如下:因為IEEE的浮點數中,尾數M省略了最前面的1,所 以實際的尾數是1+M。如果你在大學上數學課沒有打瞌睡的話,那麼當你看到(1+M)^(-1/2)這樣的形式時,應該會馬上聯想的到它的泰勒級數展開, 而該展開式的第一項就是常數。下面給出簡單的推導過程:

對于實數R>0,假設其在IEEE的浮點表示中,

指數為E,尾數為M,則:

R^(-1/2)

= (1+M)^(-1/2) * 2^(-E/2)

将(1+M)^(-1/2)按泰勒級數展開,取第一項,得:

原式

= (1-M/2) * 2^(-E/2)

= 2^(-E/2) - (M/2) * 2^(-E/2)

如果不考慮指數的符号的話,

(M/2)*2^(E/2)正是(R>>1),

而在IEEE表示中,指數的符号隻需簡單地加上一個偏移即可,

而式子的前半部分剛好是個常數,是以原式可以轉化為:

原式 = C - (M/2)*2^(E/2) = C - (R>>1),其中C為常數

是以隻需要解方程:

= C - (R>>1)

求出令到相對誤差最小的C值就可以了上面的推導過程隻是我個人的了解,并未得到證明。而Chris Lomont則在他的論文中詳細讨論了最後那個方程的解法,并嘗試在實際的機器上尋找最佳的常數C。有興趣的朋友可以在文末找到他的論文的連結。

是以,所謂的Magic Number,并不是從N元宇宙的某個星系由于時空扭曲而掉到地球上的,而是幾百年前就有的數學理論。隻要熟悉NR和泰勒級數,你我同樣有能力作出類似的優化。

在http://GameDev.net上有人做過測試,該函數的相對誤差約為0.177585%,速度比C标準庫的sqrt提高超過20%。如果增加一次疊代過 程,相對誤差可以降低到e-004的級數,但速度也會降到和sqrt差不多。據說在DOOM3中,Carmack通過查找表進一步優化了該算法,精度近乎 完美,而且速度也比原版提高了一截(正在努力弄源碼,誰有發我一份)。

值得注意的是,在Chris Lomont的演算中,理論上最優秀的常數(精度最高)是0x5f37642f,并且在實際測試中,如果隻使用一次疊代的話,其效果也是最好的。但奇怪的 是,經過兩次NR後,在該常數下解的精度将降低得非常厲害(天知道是怎麼回事!)。經過實際的測試,Chris Lomont認為,最優秀的常數是0x5f375a86。如果換成64位的double版本的話,算法還是一樣的,而最優常數則為 0x5fe6ec85e7de30da(又一個令人冒汗的Magic Number - -b)。

這個算法依賴于浮點數的内部表示和位元組順序,是以是不具移植性的。如果放到Mac上跑就會挂掉。如果想具備可移植性,還是乖乖用sqrt好了。但算法思想是通用的。大家可以嘗試推算一下相應的平方根算法。

2、簡單公式

減法公式:受到傷害=敵人攻擊力-防禦力

除法公式:受到傷害=敵人攻擊力*敵人攻擊力/(防禦力+敵人攻擊力)

乘法公式:受到傷害=敵人攻擊力*(1-免傷率)

經典機率算法

圓桌機率算法

屬性池概念

3、雙曲線公式:COC中大量粗暴的使用

4、ELO算法:貌似wow和11平台的天梯都有用到

5、超級機器人大戰傷害計算公式

6、D&D中的各種檢定計算

7、卡馬克卷軸算法

8、仙境傳說:護甲值是def,體力值vit 受到的傷害=對方〔atk*(100-def)/100〕-vit 從兩方面減傷,同時強調了護甲值和加點體力的重要性

9、蘭切斯特方程式

10、火炎紋章系列亂數表

繼續閱讀