遊戲設計中有哪些經典的計算公式?
減法公式:受到傷害=敵人攻擊力-防禦力
除法公式:受到傷害=敵人攻擊力*敵人攻擊力/(防禦力+敵人攻擊力)
乘法公式:受到傷害=敵人攻擊力*(1-免傷率)
經典概率演算法
圓桌概率演算法
屬性池概念
=======2013.7.19號更新============
來填坑了。。。。
沒做過DOTA類遊戲的平衡,LOL也玩得不多,只能說下我自己的辦法
第一個問題:符文系統和天賦系統存在的必要性和對戰局的影響?
先引入兩個概念:
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里隊伍積分和個人積分分別有什麼用?
戰鬥系統的公式來來回回就那麼幾個,就不提了。
成長系統其實不需要用公式,手調才是王道。
以前夢幻做活動投放的時候,最初搞的不很嚴謹,好東西比如彩果什麼的,都是在第一時間就刷光了(有掉落總量限制,相當於初級的掉落池),所以所有人都急沖沖地卡著活動開始的點沖,伺服器壓力非常大,後來學聰明了,把活動時間段內分成了很多個部分,每個部分有獨立的掉落池,加上一些規則上的完善,伺服器壓力還是分攤了不少,而且這樣掉落也顯得更多。
這個設計是很值得一用的,尤其在集中投放的時候。
雙曲線公式用來設計定價階梯,COC中大量粗暴的使用
ELO演算法:貌似wow和11平台的天梯都有用到
如果你說遊戲業最有名的,影響最深遠,而且最具傳奇性的。
肯定是卡馬克快速平方根
它讓計算平方根倒數的計算速度提高了4倍,導致了3D遊戲的革命。沒有這個演算法,恐怕到現在3D遊戲里的物體仍然沒影子(想想看CS的畫面)。
這個演算法在上世紀就出現了,但是在10年前才引起遊戲圈的關注,演算法的原理很清楚,但是作為演算法核心的那個常數,至今沒人知道它是怎麼得出來的。有傳言說是外星人入侵互聯網時留下了這個常數。遊戲業各位大牛紛紛在源代碼後面寫上了一句注釋:what the fuck?
平方根倒數速演算法
轉一下最早介紹這個事情的文章,應該是來自MSDN的
在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為常數
所以只需要解方程:
R^(-1/2)
= (1+M)^(-1/2) * 2^(-E/2)
= 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好了。但演算法思想是通用的。大家可以嘗試推算一下相應的平方根演算法。
提名坦克世界的靈魂:點亮距離公式
這個遊戲的其他方面本質上和其他MOBA遊戲沒有什麼區別,而且還更簡單,但是它採用了一個非常獨特的設計,即敵人是不可見的(不是依靠戰爭迷霧),需要雙方接近到足夠視野範圍抵消敵人的隱蔽係數時才會被點亮,而在這個距離之外就已經可以開火了。
詳細的公式:點亮距離=50+(視野範圍-50)×(1-隱蔽係數)
公式確保了50米以內所有的敵人都會被點亮,避免敵人貼到你臉上還不亮,而在50米以外就完全取決於視野和隱蔽了。
這個機制確定了遊戲的核心玩法,很多時候都要依靠高隱蔽係數和高視野範圍的坦克去前線偵查,然後藉助隊友的配合打擊敵人,對於負責偵查的玩家來說這是一件非常考驗技術的事情。
在加上草叢和灌木可以增加隱蔽係數,開炮和移動會降低隱蔽係數的設計,就使得遊戲性豐富了起來,經常出現一輛高隱蔽係數和高視野範圍的坦克以一己之力擊殺數量遠多於它的敵人,這種戰局也具有很強的觀賞性,是玩家繼續遊戲的動力之一。
平方根倒數速演算法。雷神之錘 III 的亮點。
補充:感慨一下無人贊同,看來這個系列真的沒落了(我從ps2上時代開始也是開金手指調錢無腦刷看動畫了,反倒是偶爾得簡單算下別一炮轟死了那些得留10%以下血什麼的人……)
ROLL100!
火炎紋章系列,它是有一個亂數表,遊戲裡面你能不能打中敵人,打出多少傷害,會不會出必殺,敵人能不能打中你,會有多少傷害會不會出必殺,全部由亂數表裡的數決定,而且一旦確定就沒辦法改,也就是不能S/L,對於只能存中斷檔的遊戲,萬一有個差錯,只能那一關重新來。所以遊戲難度就很高。
經典的公式,現今主流用於製作的就是減法和除法的各種拓展公式。太複雜的公式玩家不易理解,製作者也不好操控。
戰鬥公式應該首推蘭切斯特方程式,根據蘭切斯特方程式可以獲得三個變形方程式,可以用來解釋戰場人數 、裝備 、單兵素質、援兵補充(在單位時間上的支援,包含了因醫療條件決定的損傷兵力的重新投入戰場)所決定的戰場損耗。根據戰鬥公式可以逆向的推出設計者所需要的任意時間段的具體參數,總結所得參數可以獲取該參數的規律性並設計相應的基礎公式。
突然發現這個:用迭代快速算平方根的c++程序,出自Carmack的QUAKE3
/* ================
SquareRootFloat
================
*/
#include &
using namespace std;
float SquareRootFloat(float number)
{
long i;
float x, y;
const float f = 1.5F;
x = number * 0.5F;
y = number;
i = * ( long * ) y;
i = 0x5f3759df - ( i &>&> 1 ); //魔術數
y = * ( float * ) i;
y = y * ( f - ( x * y * y ) ); //迭代1 1/sqrt(number)
y = y * ( f - ( x * y * y ) ); //迭代2 1/sqrt(number)
//y = y * ( f - ( x * y * y ) ); //迭代3 1/sqrt(number),如需要更高的精度請迭代多次
return number * y;
}
{
float b = 9852.0;
//cout&<&
float e = c * c ;
cout&<&
}
a*演算法,卡馬克捲軸演算法
DD中的各種檢定計算,簡單而複雜的引入了世界的隨機現象:操作和理解簡單;但是演繹起來的又足夠複雜
蘭徹斯特戰鬥方程對策略類遊戲很有用~
一個隊伍等級分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。
時間=金錢(遊戲內購)
= =加減乘除,越複雜的東西,越難維護。
推薦閱讀:
※用反派 Boss 的視角看主角是一種怎樣的體驗?
※英雄聯盟世界觀里,德瑪西亞是個什麼樣的地方?
※如何評價基於遊戲毀滅戰士(Doom)的AI死亡競賽大賽結果?
※從角色設定的角度看,防禦力和 HP 有區別嗎?
※你在遊戲里做過最無聊的事情是什麼?