遊戲數學建模工程手冊

abraxas71發表於2020-05-18
遊戲數學建模工程手冊

宣告:abraxas71投稿,轉載需經作者本人同意

他告訴一位朋友:之所以故意把《原理》弄得儘可能艱澀難懂,是“避免受到對數學一知半解的人打擾”

——《牛頓傳》

本手冊有一個雄心勃勃的目標:將遊戲數學建模的工作變得專業、規範和標準,同時像其他工程行業的手冊一樣,可供相關人士翻閱、應用或得到啟發。如果目標能夠達成,好處是顯而易見的:

1】標準化有利於遊戲數學建模的規範、可靠、高效,以及人員的甄別
2】專業性的提高,不僅降低專案開發尤其是數值除錯階段的成本,往往也伴隨著收入水平的提高
3】直接或間接的令遊戲數學建模發展、發現新的方法,進一步促使其專業化

為達成上述目標,本手冊採取了儘可能數學的闡述方式,這種闡述方式具有工程的可操作性,並且避免了不必要和非專業的爭論。

手冊由如下內容組成:

【評估建模】如同各數學應用領域存在對演算法的穩健、無偏、精度、穩定性、一致等指標以評價演算法,這部分討論了什麼才是好的模型,又如何評估,它包括:

——時間複雜度
——可操作性
——充分近似

【不好的建模】這部分內容討論了一些建模方式,這些方式或時間複雜度過高,或缺乏理論聯絡實際,甚或基於錯誤的理解,它包括:

——隨意新增、濫用引數和運演算法則
——濫用戰力、價值
——反推數值
——技能迴圈

【有用的建模】這部分內容體現“手冊”一詞的含義,討論了一些遊戲實際模型的構建與演算法:

——減法傷害公式的近似與應用
——戰力的認識與計算
——技能建模:三種演算法的綜合
——自由分配屬性點:最值問題
——經濟建模:齊次方程組與樣條插值解
——廣義PVE模型

【數學建模與遊戲開發】作為本手冊的最後一節,這部分討論了遊戲數學建模工作者在遊戲開發中的作用與位置。

【評估建模】


時間複雜度


壞的設計會招致在它上面疊加壞的設計



——《架構之法》


【時間複雜度】時間複雜度是用數學形式來表達、對比同一功能但不同程式碼之間的程式執行時間,用以橫向評估程式的質量。該方法同樣可以評估廣泛使用excel的遊戲數學建模工作的質量。

我們將非重複的寫入、修改1個單元格的操作時間花費視為常數1,非重複是說通過如複製、依序拉出、excel函式結果可變的操作仍視為常數1。

先從一個簡單的例子開始。屬性/道具有兩種分配方法,一種是給出總的量分給各系統模組(下稱總-分),另一種是系統模組單獨給定然後彙總(下稱分-總)。那麼,這兩種建模方法,哪種更好呢?

使用總-分方法時,給出總量所需操作時間為常數1,總計有n個系統模組進行分配各操作1次,累積操作時間為n*1,每個系統模組需要改名來讓函式從總量裡提取到正確的分配額度同樣花費n*1,總-分方法時間複雜度為T(n)=1+2n。使用分-總方法時,除了有總-分方法的操作步驟外,還需在彙總函式里加入n個系統模組的單元格連結來花費n*1,於是分-總的時間複雜度為1+3n。兩者在漸近時間複雜度上是一個量級的O(n),因此n足夠大時,兩者時間複雜度相差無幾,但在實際工作中n不會太大,於是,總-分的時間複雜度更低、更可取。

再以養成模組進度規劃(下稱遊戲節奏)的3種建模方法進一步闡述時間複雜度在建模/模型評估上的應用:根據產耗計算養成模組進度、齊次方程組解析解、齊次方程組插值解。

根據產耗計算養成模組進度——當我們為一個系統模組給定產出和消耗後,這個系統模組的遊戲節奏就被確定了,我們需要知道這個遊戲節奏情況如何,好知曉遊戲內容被玩家消耗的情況、怪物們應該匹配的強度。我們有n個系統模組產出需要規劃,其時間複雜度為k*n*m,其中k表示平均而言1個系統模組的時間花費常數,m為道具種類,相應的,我們有m個道具消耗要規劃,其時間複雜度為k*m,我們需要計算出生命週期為t的遊戲節奏,並且要先彙總產出,則花費t*n*m,於是“根據產耗計算養成模組進度”這種經濟建模方式的時間複雜度為T(n)=k*n*m+k*m+t*n*m。1個道具至少安排1個系統模組負責產出,故n>=m,我們取最小值n=m,則T(n)=k*n^2+k*n+t*n^2,其漸近時間複雜度為O(n^2),隨著道具種類和系統模組的增多,這種建模方式耗費的時間以平方級別增長。

齊次方程組解析解——1個方程組代表了1個系統模組的遊戲節奏,產出消耗均由齊次方程組的解提供。因此我們需要先規定生命週期為t的遊戲節奏,有n個系統模組要規定,其複雜度為t*n,然後設定齊次方程組的係數a_00.........a_tm*2,m*2裡的2分別代表產出和消耗,係數用來表達方程組裡的本行方程(節奏)的產耗是第一個方程(節奏)產耗的多少倍,花費時間為2*t*n*m。最後,齊次方程組的解析解是基礎解系,我們還需線性放大縮小來匹配特定道具數量所需的量級,我們要放縮m個道具的產耗,該操作時間複雜度為m,於是,“齊次方程組解析解”的時間複雜度為T(n)=t*n+2*t*n*m+m,取n=m,則T(n)=t*n+2*t*n^2+n,漸近時間複雜度為O(n^2),該建模方式耗費的時間仍以平方級別增長,但比起“根據產耗計算養成模組進度”它只有1個高階項。

齊次方程組插值解——每個系統模組的全部進度必須完整的由齊次方程組表示,插值解方法將其改進為:在一些我們關注的時間節點才規定具體進度,其餘節點由插值解自動估計。這樣的改進要求我們必須規劃產出,用插值求解消耗從而匹配所需的遊戲節奏,則規劃產出的時間複雜度為k*n*m。關注的時間節點遠小於t,因此規定遊戲節奏的複雜度僅為n,我們還要彙總m個道具,複雜度為m,則“齊次方程組插值解”的時間複雜度為T(n)=k*n*m+n+m,取n=m,則T(n)=k*n^2+2n,漸近時間複雜度仍為O(n^2),比起“齊次方程組解析解”少1個線性項,並且沒有t。當t較大時,“齊次方程組解析解”用方程組去描述遊戲節奏耗時以線性方式積累,當t較小時,“齊次方程組解析解”仍要放縮m個道具。因此,改進方法減輕了時間複雜度裡一次項的影響,相對高效。

我們最後討論一種建模方式的時間複雜度來結束本節。同一用途的道具存在內部品質/級別區別,是不同養成階段所需。一種方式是將其視為不同道具,然後分佈在產出規則細節中(下稱細分道具),另一種方式是將所有高階品質/級別的道具視為最低品質/級別道具的特例,與最低品質道具是一個常數k_1......k_n線性放大的關係,其中n表示品質/級別的數量,然後將最低品質道具分佈在產出規則細節中,當從某個節點要求特定品質道具時,則將該道具除以k求出高階品質道具(下稱廣義道具)。

細分道具——我們有n個同一用途不同品質的道具要投放在a個節點上,a起到隔板作用,故a=n-1,複雜度為n-1。平均而言每個節點之間有m個投放點(比如關卡數),需操作n*m的時間複雜度,顯然n<=n*m且有n<=n^2,取n=m。於是“細分道具”的時間複雜度T(n)=n-1+n^2。漸近時間複雜度為O(n^2)。

廣義道具——在這種方式下,我們僅需投放1個道具並依序給到全部投放點,花費時間為常數1,設定a個節點複雜度為n-1,我們使用以lookup為核心的函式來令所有投放點知曉自己是否應當除以常數k_1......k_n,函式時間花費常數1,要設定n個常數k複雜度為n-1(因為k_1始終為1無需設定)。舉例來說第1個節點填寫k_2,由於k_n>k_n-1....>k_1,因此lookup固定頭部單元格後道具只能查詢到最後的非空值k來除以它。於是,“廣義道具”的時間複雜度僅為T(n)=n-1+1+1+n-1=2n,漸近時間複雜度為O(n),時間複雜度為線性的“廣義道具”方法優勢明顯。

不同於程式輸入不同規模的資料實際的檢視演算法的執行時間來精確比對,遊戲數學建模只能使用T(n)和漸近量級的O(n)來討論。時間複雜度是一個衡量、評估數值策劃建模效率的工具,如果太多建模部分的方法時間複雜度較高,尤其是多項式或指數級的(以及模型面對的目標龐大的),那麼整體的時間花費同樣較高,這也是多數數值策劃工作的現狀。

可操作性


測量一切可測之物,並把不可測變為可測


——伽利略


【可操作性】和常識用語甚至哲學討論不同,所有工程應用均強調可操作性,並且以如何操作的描述來確立名詞,稱呼為操作性定義。同為工程應用數學的遊戲數學建模,也應遵循這一原則:充分描述建模的操作過程、細節使得他人可以復現。

用一個簡單的例子來引出我們將討論的可操作性:飢餓這一說法不具備可操作性,我們使用未進食t小時來描述它。這個例子包含了如何測量以及量化的單位,接下來讓我們看看更多的例子。

戰鬥平衡是一個經常會提及的詞彙並且我們需要為之建模,大體上我們對它的理解並不含糊,儘管有時會被濫用在與其含義擦邊的地方。我們將戰鬥平衡描述為:在有限的時間t內,2個戰鬥單位均以100%生命值為代價擊敗對方。它如何具備可操作性?已知描述2個單位戰鬥過程的基本公式:

遊戲數學建模工程手冊


將所有引數移到左邊:

遊戲數學建模工程手冊


作為工程應用數學,右邊的1我們賦予其現實意義:100%生命值(在後文我們還會看到它有另一現實意義)。根據這個公式,2單位的戰鬥平衡意味著調整左邊任意引數的線性放縮,使得等式恆為1。在得知平衡的操作方法後,自然延伸出戰鬥優勢的可操作性:1個單位僅需p且0<=p<1的生命比例為代價,我們稱這個單位有1-p的優勢。戰鬥優勢有一個不夠中立的稱呼“不平衡”,然而不平衡也意味著角色通過成長、付費等途徑獲得好處,所以本手冊以中立的戰鬥優勢來稱呼這種情況。

另一個可自然延伸出的是戰鬥體驗的可操作性。顯而易見,戰鬥體驗由諸多因素組成,許多因素難以操作和量化,如果我們苛求這些並一頭扎進繁雜的細節裡,除了得到一堆猜想外只會無從下手。任何模型都是對現實的簡化和比喻,我們對戰鬥體驗的建模用2個指標來逼近這一現實:在一個有限的時間t內損失生命比例p。t和p都小,量化了一場簡單/新手的戰鬥。t小p大,量化了一場容錯率低的戰鬥,從而很適合玩家體現自身操作水平。t大p小量化了一場檢驗玩家輸出是否達標的戰鬥,超時後怪物將秒殺玩家或根據輸出決定獎勵分配。t和p都大則是一場充滿史詩感的對決。

既然付費是獲得戰鬥優勢的一種途徑,那麼我們當然可以將付費體驗可操作化,給定付費額度可額外獲得多少屬性,使得:

遊戲數學建模工程手冊


分子位置為非付費玩家,分母位置為付費玩家。當付費額度是一個常數時,p越小,戰鬥優勢越明顯,付費體驗便越好。

以上例子表明,可操作性要求我們給出建模達成的量化方式、如何達成這個結果以及最後但並非最不重要的:結果是工程應用性質的。工程應用性質意味著建模結果是玩家容易感知、理解的(如上述的生命比例)。接下來提及的2個例子進一步闡述“工程應用性質”的含義。

有一種經濟上收益相關的建模方法,即在養成模組的某個階段發生突變,比如給的屬性更多但所需消耗更少從而改變玩家的收益感,並畫出折線圖來視覺化,有時被稱做收益拐點。這種設計沒有工程應用性質。玩家到達收益拐點需要花費時間、金錢成本,並且很難確保玩家記住拐點前的收益進而對比,我們從上帝視角一廂情願認為玩家會為此感到高興、引起興奮,而未能更“接地氣”的從感知有限遊戲資訊的玩家角度建模。與此相對的是另一種做收益差異的方法,將道具以不同養成模組分組,然後通過組間整體價格放縮做到養成模組之間不同的收益。通常而言,玩家很快接觸到這些養成模組,進而迅速的發現收益差距作為付費的決策依據。

比起泛泛而談的“為體驗服務”、“考慮走位和玩家操作水平”、“數值是調出來的”諸如此類的口號而言,可操作性描述了工程實現細節,如同程式設計師通過程式語言實現功能,數值策劃則通過數學工具來得到結果,進而考察結果的充分近似程度,這就是下一節我們要討論的。

充分近似


我所接受的工程訓練教導我要容許近似,有時候我能夠從這些理論中發現驚人的美,即使它是以近似為基礎的...我持續在之後的工作中運用這些不完全嚴謹的工程數學


——保羅·狄拉克


【充分近似】遊戲在商業上的成功與許多因素相關,遊戲數學建模的好壞作為其中一個因素可以合理的猜想是正相關的,儘管玩家感知遊戲裡數學計算的表現在敏感度上有待商榷、正相關強度甚至因果強度如何尚未能量化,但是我們仍然要有一些檢驗解析解可靠性和適用範圍的方法,畢竟等待玩家反饋的時間週期太長且已經帶來成本損失。自然的,這些方法是仿效工程和物理的:數值模擬實際遊戲

數值策劃出現在大約20年前,早期遊戲開發對數學計算的需求並不大,經過粗略計算後程式開發出AI,如果AI在操控單位、種族、陣營對抗時沒有明顯問題,那麼剩下的就留待版本更替解決,這種數值模擬現在仍然是檢驗解析解的有效方式。然而,隨著遊戲內容的增加,通常我們不能親自或等待開發全部遊戲功能,所以設定一個理想環境如將戰鬥的概率表現用期望計算或編寫程式碼模擬戰鬥是一個可選方案。由於涉及較多的推導、證明,以下僅舉一例,更多的例子將出現在【有用的模型】裡。

我們有,

遊戲數學建模工程手冊


該式在說如果單位生命和傷害能力都變化到k倍,則p的變化與k^2有關,記為p(k)。我們用p衡量付費額度或養成模組屬性量對玩家的影響,需要知道額外得到的屬性與k的關係。存在諸如防禦、閃避、暴擊、穿透等類生命和類傷害的屬性使得k的解析解計算時間複雜度較高,這迫使我們尋找近似解。

已知類生命和類傷害屬性只有2種處理:非負實數對映到[0,x]區間(如閃避率取值0%到100%、暴擊傷害提高300%);直接運算(如真實傷害是額外的傷害值不被免傷率抵消)。對於後者,根據具體運算規則,可以視為生命和傷害的線性疊加,對於前者,其取值範圍我們不會在不同角色間差距太大,因此我們可以說,

遊戲數學建模工程手冊


HP(·)是將類生命屬性等價為生命值的函式,DPS(·)同理。即全體屬性變化到k倍約等於原本的生存和傷害能力變化到k倍,於是p(k)≈1/k^2。這種近似是否足夠好呢?如圖所示:

遊戲數學建模工程手冊


解析解得出單位B以16.8%的生命為代價擊敗單位A,近似解為20.66%,比為81.31%,對用於評估屬性變化相比起標的單位有多大的戰鬥優勢,進而得出付費體驗和屬性量是否合適的判斷而言,該精度足以勝任。較低的時間複雜度得出較好的精度,我們稱建模是充分近似的。上述例子僅針對乘法傷害公式,因為只有乘法傷害公式才會將防禦值對映到[0,1]區間並和攻擊方屬性無關。

一來,編寫程式碼模擬亦或理想環境計算終究是對現實的簡化,二來有些解析解無法列出計算公式檢驗或編寫程式碼檢驗需要太多的時間。這就要求在實際遊戲裡進行工程實驗並收集資料來比對演算法預期,所謂實際遊戲不僅僅像普通玩家那樣進行遊戲,還需排除其他因素進行工程實驗,檢驗結果是否充分近似。比如存在閃爍、昏迷、放逐等等特殊的技能效果,如何建立這些效果對戰鬥的函式關係可查閱【技能建模:三種演算法的綜合】,我們選取已經做好戰鬥平衡但不同效果的各個角色互相對抗,排除基本屬性帶來的影響,從而確定技能效果建模的解析解可靠性。

道具的產出與規劃將影響玩家的養成情況,養成情況又與戰鬥強度關聯,進而影響PVE裡怪物強度的匹配。所以,一個能良好估計玩家戰鬥強度的建模方法尤為重要,這個方法我們將在【經濟建模:齊次方程組與樣條插值解】裡看到。換言之,實際遊戲理應驗證估計的玩家強度,存在偏差太遠時,應檢查養成是否充分,如果充分則檢查是否匹配經濟的產出和規劃。通常來說,玩家強度的估計錯誤往往是經濟規劃存在問題,使得玩家不能充分接近規劃的遊戲節奏,也就無法達到相應的強度。

【不好的建模】


我們力圖儘快證明自己錯了,只有這樣我們才能進步



——理查德·費曼


隨意新增、濫用引數和運演算法則


在工程應用領域總會存在理論滯後於實際現象和需求,這迫使物理學家和工程師從實驗資料裡建立經驗公式,比如根據探測到的地震波強度估計地震中心地帶距離探測點有多遠。要說這些經驗公式是強行湊出來的不為過,但只要它們是基於資料的、有一定預測價值的,我們就會使用它們直到理論得到足夠發展。

然而,一些數值策劃在公式上的使用則除了湊出來外,與工程或物理的經驗公式出發點毫無相似之處。除法傷害公式,一個生生湊出來的傷害計算方法:

遊戲數學建模工程手冊


變換為形如“攻擊*(1-免傷率)”:

遊戲數學建模工程手冊


而減法傷害公式為:

遊戲數學建模工程手冊


免傷率比起減法傷害公式新增了對方防禦的反向約束,這加劇了減法傷害公式本有的非線性特徵,使得攻擊、防禦的變化不能有效預測對方的受損情況,或根據目標損血比例逆運算出攻擊、防禦。解析解的帶入具體值當然可以做到,但面對複雜的戰鬥設計時,解析解的計算相當的繁瑣甚至無從下手(如增減屬性的技能可施加在任何角色上)。此外,它的防禦不夠直觀,減法傷害公式的玩家知道多少防禦就能抵消多少攻擊,乘法傷害公式則轉換為免傷率展示在介面。除法傷害公式不論在時間複雜度與可預測,還是玩家的易理解上沒有任何優勢。

除法傷害公式湊出來的思路不得而知,但從濫用運演算法則的現象上可一窺一二。這些運演算法則的新增可以出現在包括傷害公式的任何公式裡,它出現的理由僅僅是希望快速增長便新增多項式、指數或引數間相乘,希望抑制變化時便新增根號和除法,甚至還有使用三角函式來得到週期變化的,彷彿運演算法則不是描述現象間關係和推導得來,而是用來獲得虛假的操控感,這大大增加了模型的非線性特徵。

引數的濫用尤為值得指出,簡單的如升級經驗公式要用攜帶多個引數的多項式,而改變這些引數僅僅用來檢視公式計算結果是否滿足所需。複雜的則有在PVE怪物每個屬性上配以用來線性放縮的引數,原因在於實際戰鬥時常不滿足理論預測,調節這些引數更僅有依據屬性影響方向來大概逼近需求結果的作用——然後開啟遊戲再看看情況。設定所謂普通怪、精英怪的引數模板加劇了這點,因為模板是固定的對玩家角色造成傷害,而關卡策劃使用多少個這類怪物則有其設計考慮,據此,怪物的數量就大大影響了實際戰鬥表現,從而進一步依賴對應屬性的引數調節,如果其他因素諸如經濟建模不夠精確,更使得怪物的表現如同雲霧一般難以看清。

濫用戰力、價值


由於目的、定義和計算上的含糊,戰力這個概念被用於許多奇奇怪怪的處理。有一種方式是根據戰力計算出屬性、平衡,而屬性在平衡上的基本指標是“有限的時間t”、“100%生命值”,違反基本指標根本不可能得到正確的結果。當然,將各個屬性的戰力系數理解為某種投放比例,然後給某個養成模組戰力額度,以戰力額度的大小來決定養成模組的重要性並期待玩家對此進行判斷並非不可取,然而玩家還存在戰力能精確表達角色強度的要求,高戰力被低戰力擊敗是一件挫敗玩家信心和感到不滿的事情。此外,玩家互相看到的戰力往往是一個總值而不是每個養成模組的戰力細節,於是,用戰力額度決定養成模組的重要性和引導玩家判斷的真正效果就顯得可疑了。

還有一種更可疑的使用方法,用售賣價格除以戰力,並把這種計算結果叫做價效比。彷彿玩家花錢只是為了讓戰力數字上漲一般。正如上文所談論的玩家對戰力的實際感知和需求,這種處理方法是真的在面向玩家建模嗎?

價值也是一個被濫用的物件,它有時指售賣的價格,有時又代表道具、技能效果、屬性強度等之間的大小關係。這使得它甚至出現在和經濟無關的地方,比方說技能價值。一些情況下談論的技能價值是指一個養成模組攜帶了基本屬性和技能,那麼這個養成模組的售價會因技能的存在變得不同。另一些情況下卻指技能之間的平衡,用價值來衡量技能之間的強度。當它指代售賣價格時,或許其定義和計算還存在不少共通處,但當它指代某種含糊的平衡性時,則乾脆不知所云,建模方法也含混不清。

反推數值


任何一名瞭解統計迴歸的人都會對所謂的反推數值感到迷惑不解。排開一廂情願的目的:複製一款商業成功的遊戲數值就能確保數值乃至盈利上的可靠性。在統計學工具上如何實現則停留在excel趨勢線擬合上——普通最小二乘法。反推的人並不關心普通最小二乘法的假設和適用情況,自然也不懂得其他的迴歸分析。這種知識和技術上的匱乏招致了對實實在在困難的低估,採集一款遊戲的數值資料所耗費的大量時間甚至金錢,如果他願意付出代價,還要面臨這些問題:假設過強、模型預測、模型擴充套件。

假設過強是指適用條件太苛刻,現實情況極少滿足。普通最小二乘使用簡單的多項式擬合資料,這在常規統計和機器學習應用裡用於刻畫現象是很好的工具,現象背後真實的模型常常是未知的,現象背後的因素也未能全部納入,我們用方程來儘可能的描述它。然而不同於自然和社會現象,遊戲數學建模還沒有人能用一個多項式來做全部工作,反推數值彷彿在假設遊戲數值在各個模組的建模僅僅是簡單的多項式方程得出,無視其本身有著數學建模的原理和過程,不去構建它卻去擬合它無異於緣木求魚。

時間和金錢的有限決定了認同反推數值的人不可能對一款遊戲的數值全面測試、採集資料。當他使用有限的資料,卻要做總體推斷工作來進行模型預測時,excel的趨勢線擬合還遠不能勝任。在統計與機器學習的應用中,我們使用K折交叉驗證來檢驗模型的外推/泛化能力,這方面的知識足以讓人消化相當長時間。此外,模型的解釋變數未必對泛化有正面貢獻,這就涉及到稀疏估計的變數選擇問題。對於一名在統計與機器學習應用上乏可陳列的反推數值者來說,模型在預測未採集的後期數值變化方面和雙眼一抹黑相差無幾。

複製一款遊戲的數值就意味著要幾乎全面模仿它的系統規則,這一點對程式開發沒有多大困難。但對於廣泛存在的或大或小變動的需求以及克服上述反推數值的重重困難後的模型而言,則幾乎沒有模型擴充套件能力。要麼拿著這搖搖欲墜的模型繼續外推,要麼主觀修改模型引數來分段處理,或者:認真開始建模——那為什麼一開始不這麼做呢?

技能迴圈


不同於高度抽象的純粹數學,我們使用函式是為了建立、描述和預測現象。然而,很多時候這些現象的函式表示式難以直接得出,但是現象的變化卻容易用高階導數描述,這時,高階導數與現象存在簡潔的關係,而這便是微分方程的建模思路。

技能迴圈是其反例,一些數值策劃“勇敢”的直面繁多的技能,窮舉它們,然後納入一個有限的時間裡一字排開,或數值模擬或excel呈現。不論哪種方法他們都在焦頭爛額、疲於奔命的實測-調整-實測裡浪費大量時間,結果也往往不如人意。相反的,如果我們將技能的傷害、治療、能量消耗等均用每秒1個常數來描述,那麼情況就大大簡化了:一階導是一個常數,與技能表現是線性關係。以傷害技能為例,我們有:

遊戲數學建模工程手冊


tdps表示隨時間累積的傷害量,t為時間(預設單位秒),C表示每秒傷害是一個常數。一個技能的時間表現有施法、冷卻、間隔生效,其中普通攻擊是技能的特例:

遊戲數學建模工程手冊


atk是普通攻擊的每秒傷害,conjure為施法時間,cd為冷卻時間,x為技能的一次傷害量,I(·)為示性函式,滿足條件取1否則取0,該示性函式表示如果一個傷害技能的conjure不小於cd,那麼玩家無需發動普通攻擊,而普通攻擊的行為只能發生在cd期間,因此從秒傷角度看它實際秒傷僅為cd/(conjure+cd)的比例。給定其他引數,求出x就是我們的目標。這個式子闡述了一個事實:任何技能的施法和冷卻時間不能同時為0。這很容易理解,如果為0,那麼C是一個無窮大的量,角色將在玩家操作反應時間內消滅任何敵人。

正如前文所述,模型是對現實的簡化和比喻。真正的技能表現並非連續可導函式,而是高度離散的,平均為每秒傷害只是一種近似或平滑處理。更多的討論我們將在【技能建模:三種演算法的綜合】展開。

【有用的建模】


所有的模型都是錯的,但有些是有用的



——喬治·博克斯


減法傷害公式的近似與應用


傷害公式是一種函式或運算規則,旨在將生存與輸出屬性換算成具體的傷害量,一個好的傷害公式應當具有如下性質:

1、線性組合是可逆的。總傷害由不同強度單位的傷害線性組合而成,可以從總傷害逆運算每個單位的傷害進而知道它的攻擊力。其中N是第i個怪物的傷害,存在一個係數β滿足逆運算得到怪物的攻擊力a,可逆性便於根據要求的戰鬥結果計算出相應屬性。。

遊戲數學建模工程手冊


2、輸出型屬性與傷害結果是線性關係。這種線性關係可以是與傷害值線性變化,也可以是與傷害結果的一階導線性變化,如兵力損失的變化量。

本節旨在討論減法傷害公式的應用(下稱減法公式),由於非線性、不破防等性質,減法公式被認為只適用於沒有不同武器的不同攻速、BUFF改變攻速這樣的簡單戰鬥,或是不便於進行戰鬥平衡的處理,並且不難發現,減法公式不滿足上述“好”的傷害公式的性質。儘管存在這樣那樣的困難,我們將推導並證明,在一定前提條件下減法公式將具備上述性質,表現得如同乘法傷害公式,由於沒有乘法公式的免傷率換算——這會帶來對等級壓制的設計要求——進一步擴大簡單的防禦抵消等值攻擊的易理解性優勢。

第一步是解決這樣一個問題:給定任意攻擊和防禦值,若攻擊變化到k倍、防禦變化到j倍,傷害量變化到原來的多少?由於傷害量的變化與生存時間是線性相關的,所以解決該問題將直接影響模型的預測和控制力。誠然,帶入具體的攻擊和防禦不難得出解析解,但如果一個改變攻擊、防禦百分比的BUFF可能施加在任何單位身上,或是給定副本內玩家的總hp損失比求全體怪物的相應屬性時(只有乘法公式攻擊和傷害的關係滿足線性可加性),解析解的實用性是大打折扣甚至無從下手的。數值模擬經驗性的表明,在最高免傷率<0.8,初始免傷率<0.45的情況下,攻擊變化率與傷害變化率的關係是一個非初等函式:

遊戲數學建模工程手冊


rdps表示傷害的變化率,k為攻擊的變化率,rdam為受傷率,1.5是從數值模擬中得到的經驗分界點,在分界點分別使用這2個公式計算是充分近似的(由於不是在製造原子彈,我們可接受的誤差最多在20%左右)。我們首先證明第二個公式,它僅需基本的極限知識,其思路為,若k趨於∞,則rdps也趨於∞,兩者的比值是否仍然趨於∞呢?

遊戲數學建模工程手冊


a和b分別表示攻擊與防禦值,變換為:

遊戲數學建模工程手冊


因為k趨於∞,所以分母的b可以忽略,於是:

遊戲數學建模工程手冊


這正是我們需要的。不過,k是在漸近意義上與rdps線性相關,實際中k通常不會特別大,它有實用性嗎?幸運的是,數值模擬表明,拜非線性性質所賜,k無需太大就能收斂,而且加入暴擊、閃避等屬性,該式仍近似的相當不錯。

遊戲數學建模工程手冊


為什麼一個僅有攻擊和防禦的假設環境且漸近線性,仍然很好的近似到真實的存在暴擊、閃避等類生命/傷害屬性的遊戲環境中呢?其實不難理解,因為這些屬性生效規則不一樣但互相對抗,這使得近似解的誤差不會總朝著一個方向發散。

遺憾的是,在極限意義上防禦只會令傷害趨於無窮小,這使得生存時間趨於∞,即發散的,我們無法用同樣的方式找到防禦變化率與rdps的漸近關係。不過,第一個公式將為我們帶來有限範圍的近似解。考慮:

遊戲數學建模工程手冊


近似一個函式的方法是模仿它的0,1.....n階導數,這便是泰勒展開背後的直觀幾何。不過,如果直接對這個式子裡的k求導,它只會告訴我們dps’=k。用k近似效果非常的差,但根據第二個公式推匯出的k與rdps存在著與受傷率的關係,我們為什麼不嘗試工程數學上的粗暴處理呢?舍掉會推出dps’=k的引數,僅保留括號內的受傷率資訊,我們有:

遊戲數學建模工程手冊


對k求導得:

遊戲數學建模工程手冊


同除b:

遊戲數學建模工程手冊


顯然,1/(a/b)是一個不大的數字,我們忽略掉,於是僅剩1/k^2。左右兩邊同乘k^2,於是:

遊戲數學建模工程手冊


即dps變化到k的平方,這正是我們第一個公式已經給出的。數值模擬結果如圖所示:

遊戲數學建模工程手冊


讓我們進一步利用免傷率、受傷率在近似解裡的價值。

遊戲數學建模工程手冊


因為b/a是免傷率且為倒數關係,於是防禦變化到j倍是:

遊戲數學建模工程手冊


將防禦的變化近似為對方攻擊量的變化,然後逼近傷害量,這種二次近似誤差只會更大,我們用開方去平抑誤差:

遊戲數學建模工程手冊


接下來我們證明用開方平抑誤差的合理性,即我們只需證明誤差函式是非線性的增函式。我們首先證明誤差不是線性的,由於:

遊戲數學建模工程手冊


是在k趨於∞時漸近線性的,注意到不等式:

遊戲數學建模工程手冊


所以在k^2的近似下,誤差不可能是線性的,k^2>=k也意味著誤差不可能收斂到0,而是發散的,因此不可能是減函式。誤差函式不是線性減函式,則只能是非線性的增函式。由於我們不清楚誤差函式的表達形式,但對非線性進行根號逆運算會是一個不錯的逼近,如圖所示,數值模擬表明j在1+0.23內,以及j<1時再度開根運算可近似足夠充分:

遊戲數學建模工程手冊


遊戲數學建模工程手冊


j不能超過1.23是一個數值模擬經驗上界,同時也是理論分析支援的:j如果一直增大,那麼免傷率趨於100%,生存時間趨於∞。∞是發散的,我們無法近似一直在變大的數。

有了上述近似求解方法,我們可以得出減法公式下的戰鬥平衡和戰鬥優勢的估計。若一個單位的整體屬性提高m倍,那麼:

遊戲數學建模工程手冊


將m移到分母位置:

遊戲數學建模工程手冊


於是:

遊戲數學建模工程手冊

我們檢視數值模擬:

遊戲數學建模工程手冊


近似效果一般,超出我們容忍的20%左右誤差。不過,繼續數值模擬會發現近似解幾乎都在低估,所以,近似解可以作為下界,提高了m倍的單位至少能夠對抗的數量或至多損失的生命比例。在通常用來評估強度差異時,已經夠用了。

攻擊速度指間隔t秒攻擊1次,取倒數變成每秒攻擊n次稱為攻擊頻次。顯然,攻擊1次是1倍傷害,攻擊2次是2倍傷害,以此類推我們知道攻擊速度想要保持平衡,只需減法公式運算後面乘以相應攻速即可保證。然而根據這樣的理解,這不能適用在不同攻速的武器上,否則玩家會看到相同的攻擊值但不同攻速,這會給玩家帶來困惑。

我們知道,攻擊值是各個養成模組的加和:

遊戲數學建模工程手冊


s是養成模組的數量。加入攻速,我們有:

遊戲數學建模工程手冊


speedatk表示攻速,b為防禦值,dam為傷害量。我們已知k和rdps的關係是漸近線性的,那麼speedatk可以表示rdps提高到了等值倍數,求k是多少:

遊戲數學建模工程手冊


於是:

遊戲數學建模工程手冊

我們僅需武器模組依不同攻速保持平衡並皮膚展示攻擊值給玩家,其他養成模組在程式碼中仍乘以武器攻速(因為其他養成模組不會隨著攜帶不同武器而改變自己提供的攻擊值)。如果atk_1是武器模組,乘法分配律告訴我們:

遊戲數學建模工程手冊


已知rpds求k,數值模擬的經驗分界點是2:

遊戲數學建模工程手冊


即,一個武器的攻速小於2時,用武器攻擊乘攻速的開方,否則乘攻速和受傷率即可。實際中,speedatk在2的附近進行開方可能大於speedatk*ram,這是經驗公式的問題所在,可以自行根據具體攻速決定取哪個來保證攻速大的攻擊值也大,也可給予攻速大的在時間劣勢上的額外攻擊值獎勵。

戰力的認識與計算


在戰鬥建模裡,一個單位的強度是在它的敵人面前能生存多久、造成敵人多少比例的生命損失。不過,玩家面對眾多的屬性是不能直觀理解到單位強度的,此外,有一個明確的數字甚至進度看到在確確實實的成長是遊戲設計在獎勵反饋感上的基本法則。戰鬥力(下稱戰力)概念就在這種背景下誕生,一個好的戰力估計應當有如下性質:

1、線性的,便於玩家理解。
2、充分近似的,戰力能夠表達單位的真實強度。

基於這2個性質,有一些戰力計算方式是不可取的。一種簡單粗暴,直接將每個屬性的戰力系數當做這個屬性的單價或單價的中間係數。一種是打分數,給標準模板的每類屬性打分,用分數除以屬性值得出單個屬性的分值作為戰力系數,這相當於將戰力理解為玩家成長得有多標準。

目前已知的上述兩種方式或其他方式,均不具備第2點的性質要求,易出現戰力絕對差額大的,戰鬥結果卻是顛倒的,尤其是勝利方還剩餘大量生命值,這大大增加了玩家對單位強度如何的迷惑感。本節提出的方法將同時滿足這2個性質:

1、推導並證明,對傷害運算裡的各個屬性求偏導組成全微分加和,將偏導值作為戰力系數,充分近似是一階精度的。

2、推導並證明,在容易滿足的前提條件下可以將精度提升至近似二階、三階甚至更高階精度並仍然是線性的。

3、不在傷害運算裡的屬性戰力系數估計,如回合制的速度。

已知傷害運算F(a0,a1,...an)是一個多元函式,其中a表示具體屬性,在k處進行泰勒展開至一階,有:

遊戲數學建模工程手冊


f(1)(·)是F(·)對a的一階偏導表示式,h表示a和ak的差額,也叫步長,O(h)表示截斷誤差與步長有關。所謂k處,指我們選擇哪個單位/職業/角色作為攻擊方和被攻擊方,稱對標單位,它的具體屬性值就是k處,代入具體值很容易算出f(1),從而得到各個屬性的偏導值作為戰力系數,並將這些戰力系數同等的應用在其他單位/職業/角色身上,而其他單位的每個屬性值與對標單位之間存在差額,差額即步長,由於截斷誤差與步長有關,並且我們只取了一階線性項,顯然其精度是一階的。

線性性質已經滿足,充分近似是一階精度的,但除非步長充分小,否則我們的誤差以二次方的速度累積。在實際中存在著多個兵種、職業,無可避免的一些兵種、職業的各個屬性與對標單位的屬性差額很大,那麼保持線性來改進一階導的值,進而提高精度就被自然引出了。

我們將多個兵種、職業視為多個可展開點k1,k2....kn,n表示兵種/職業數,k1是對標單位。如果我們選取k2也作為展開點,一階展開為:

遊戲數學建模工程手冊


又有k1的展開點,其偏導表示式為:

遊戲數學建模工程手冊


而k2的偏導表示式為:

遊戲數學建模工程手冊


將兩者取均值,則:

遊戲數學建模工程手冊


如果我們將k2處的偏導視為是在k1處的展開,則有:

遊戲數學建模工程手冊


將其中的一階項代入取均值的式子中:

遊戲數學建模工程手冊



合併同類項:

遊戲數學建模工程手冊


而F的二階泰勒展開是:

遊戲數學建模工程手冊


顯然,我們在避免二階導的非線性處理下,通過加入另一個兵種/職業的一階導和對標單位的一階導取均值提高了精度,忽略混合偏導數項,則截斷誤差介於二階和三階,精度在一階和二階之間。比較精確解與估計間的誤差,如圖所示:

遊戲數學建模工程手冊


估計傷害的誤差從1.313下降到了0.234,受傷的誤差從0.781下降到了0.004。

既然考慮進新的單位可以將精度提高到近似二階,那麼再加一個單位是否能提高到近似三階呢?仿照龍格庫塔法,如果:

遊戲數學建模工程手冊


λ表示F在ki處偏導數的權重,即多個單位作為展開點處的一階導,通過加權平均得到一個更好的一階導。這個λ有無窮多解,所以一般而言取值為:

遊戲數學建模工程手冊


其中k2單位生存和擊殺時間必須介於k1和k3之間。精度改善如圖所示:

遊戲數學建模工程手冊


誤差列從上到下分別是三階、二階、一階估計後與精確解的誤差,三階的誤差是最小的。然而我們還能看到二階估計反而不如一階估計,其根本原因在於,我們的精度並不是嚴格二階、三階乃至更高階的。因為一個多元函式的泰勒展開還包含混合偏導項,我們卻使用應用在一元函式上的泰勒方法分析,忽略混合偏導,使得誤差並不總能縮小,根據多元泰勒展開的混合偏導表示式,可以知曉忽略帶來的誤差隨著步長呈指數級增長,指數等於選取的單位數。這提示我們,除非對標單位與其他所有單位間的屬性差額(步長)儘可能的小,否則誤差會很輕易的增大。顯然的,中位數是離其他所有資料點差額最小的值,如果我們將所有單位的生存與擊殺時間排序,時間在中位數位置的就是最佳對標單位,中位數附近的是最佳高階展開點。比起當下常見做法,隨意選取一個對標單位,如稻草人。泰勒展開的分析告訴我們,應當選取距離其他所有單位差額最小的。

接下來我們討論不在傷害函式裡的屬性,甚至沒有傷害概念的如女性向對拼衣著打扮的屬性如何估計其相應係數。事實上,這可以轉化為一個最小二乘問題。以回合制常見的速度值決定出手順序為例,每個單位都有不同的速度值,若速度值s滿足不等式:

遊戲數學建模工程手冊


那麼,出手順序滿足:

遊戲數學建模工程手冊


即不論計算函式如何,速度值大的就是出手靠前的,或將速度槽最快累積滿的。我們假設出手速度會影響單位的強度表現,那麼我們在求如下優化問題:

遊戲數學建模工程手冊


θ是我們需要估計的每1點速度值增加的戰力,tdps為累積傷害量,指在對標單位面前生存回合內總傷害值,b為截距,s為速度值,n為單位數。公式是最小二乘的優化目標函式,求出使得式子達到最小值的θ,這一點,excel趨勢線便能解決,如圖所示:

遊戲數學建模工程手冊


得出速度的戰力系數約為27,這是個令人驚訝的數字,完全與在傷害函式中的屬性戰力系數差距很遠。這個問題在於,不同單位的速度值、傷害量之間的量級可大可小,甚至不同遊戲之間也是如此,數字大的被認為影響更大,但實際單位之間強度並非如此。比方說,A比B強2倍,A的輸出為100點傷害,B為50,在另外的數學建模中A的輸出為20000,則B是10000,然而A保持是B的2倍強度,因此,我們需要回歸分析裡的一個數學處理方法——標準化。將速度值和累積傷害都標準化到均值為0,方差為1的正態分佈下。標準化公式為:

遊戲數學建模工程手冊


速度值減去其均值然後除以其標準差,累積傷害同理,標準化後估計出的係數如圖所示。

遊戲數學建模工程手冊


每1點速度提供的戰力系數為0.418,這便顯得合理多了。

標準化後的最小二乘估計還能應用在沒有傷害概念的遊戲裡。比方說一些女性向遊戲只通過衣服品質來比對高低,如果搭配品質不一則根據其具體的魅力、時尚之類的屬性值判斷。可以將衣服品質賦予數值,然後進行最小二乘估計。

技能建模:三種演算法的綜合


在所有戰鬥相關的建模中,我們面對的最複雜的情形之一便是技能。技能的設計充滿了想象力,這對數學計算髮起了挑戰,以當前遊戲數學建模的發展應用情況來看,尚未發現關於技能的儘可能抽象、統一的模型構建思路和方法,本手冊將在本節提出。

技能可以分為三大類加以討論:1)增減屬性;2)治療;3)常規。

我們從最簡單的增減屬性開始。在前文【可操作性】裡,我們將戰鬥平衡數學的描述為有限的時間t內對戰雙方付出100%的生命為代價。根據定義,永久或暫時的增減屬性顯然已經不平衡。因此,實際的做法是擴大對平衡的理解,設定增減屬性後的戰鬥優勢單位付出1>p>>0生命為代價,求滿足要求的增減屬性最大值為多少,P取值小於1但遠大於0。如75%生命為代價,讓增減屬性技能顯得有用,又不至於對平衡影響過大。那麼,最大值是增減屬性的技能的最高分配,超過最大值的部分用函式給出警告效果即可。

通過前文的鋪墊,我們有:

遊戲數學建模工程手冊


且:

遊戲數學建模工程手冊


我們給出p求k,HP和DPS均可消去,因而變成一個簡單的倒數後開方逆運算。以p=0.75為例,k可得(1/0.75)^0.5=1.154,優勢戰鬥單位增減屬性後整體屬性最大隻能是敵人的1.154倍,永久屬性最大增加15.4%,最大減少(1-1/1.154)=13.3%。

我們進一步分析它的界,由於增減屬性最大隻能給全屬性,並且一般而言只提供部分型別的屬性,因此我們可以肯定的說:理論上,增減屬性後,戰鬥優勢單位至多付出100%生命,至少付出75%,真實情況在兩值之間。

若屬性是暫時的,存在一個冷卻時間和持續時間。顯然當持續≥冷卻時,等價於永久擁有,當持續<冷卻時,冷卻減去持續的時間差裡沒有增減屬性影響,因而影響的佔比是一個加權平均:0*(冷卻-持續)/冷卻+屬性百分比*持續/冷卻。此外,還需指出的一點是,有些看似沒有冷卻和持續時間的技能比如光環、被動屬性增益,我們可以認為它們的冷卻時間等於持續時間,彷彿剛冷卻好立刻自動釋放,或理解為它們只有在戰鬥中有意義,戰鬥結束沒有意義等同沒有被施加效果,則冷卻時間=持續時間=標準戰鬥時間。

接下來,我們進入治療技能的演算法討論。考慮2個強度相當的單位,單位A只能治療自己,單位B攻擊單位A。無治療時,存在一個有限的時間t,單位B將殺死單位A,有治療時,A在t內累計恢復生命上限p,其中0<p<1。顯然的,單位A的生存時間t將延長t*p,在t*p的時間內單位A仍將繼續治療自己,繼續延長t*p*p,我們羅列出公式:

遊戲數學建模工程手冊


我們注意到這個熟悉的函式結構——無窮等比數列:

遊戲數學建模工程手冊


由於p<1,因此無窮等比數列收斂,可以用收斂公式求出t*。換言之,只要t內A單位的回血量小於生命上限,那麼A將被擊敗。所以,我們可以根據t*比t的倍數,來衡量治療技能的重要性程度,並用p/t得出每秒治療生命的百分比來計算出一個確切冷卻時間的治療技能一次性可治療的生命值。吸收傷害的護盾同理,它的實際效果根據持續時間和冷卻時間進行加權平均即可,超出p的部分稱呼為越界。

值得一提的是,另一種思路是將治療理解為傷害的負數,扣減後的結果和無窮等比數列的收斂公式解一樣。不過,無窮等比數列的角度可以讓我們知曉模型存在一個隱含假設:治療動作是連續不間斷的,實際的治療動作是高度離散的,收斂值事實上是一個上確界。

分類為常規的技能包含傷害技能,我們用一個簡單的微分方程描述了它:

遊戲數學建模工程手冊


tdps表示隨時間累積的傷害量,t為時間(預設單位秒),C表示相對於普攻秒傷的倍數是一個常數。其中:

遊戲數學建模工程手冊


即C由普攻部分和傷害技能部分組成。其中atk是普攻的秒傷,conjure為施法時間,cd為冷卻時間,x為技能的一次傷害量為普攻的x倍,I(·)為示性函式,滿足條件取1否則取0,示性函式表明一個傷害技能的conjure不小於cd,則無需發起普攻,且普攻行為只能發生在cd期間,於是從秒傷角度看實際秒傷僅為cd/(conjure+cd)的比例。此外,後半部分的值必須大於1,1是普攻是自身的1倍。

然而,在設計師的“傾力協助”下,常規技能並不僅僅是傷害的,還存在諸如閃爍、複製技能、隱身等非傷害效果,這種情況普遍到數學計算不可能無視,尤其一個技能或一個戰鬥單位既有傷害又攜帶這類技能效果時,x的計算結果不應和一個單純的傷害技能相同。於是,自然而然的提出了一個簡單的想法:能否將這類效果的強度ε等價為C的後半部分呢?我們將提出公理、推導及演算法幫助實現這一點。

首先是公理部分:

【公理一:非負性】任意非傷害效果,其強度不論多麼小,至少存在一個戰鬥單位的視角觀察下該技能強度是正面的,即ε>0。

換言之,設計師不會設計出絕對負面的技能,如果單位B攜帶的技能是負面的,則單位A看來對A是正面的。如果存在一個技能場對任意戰鬥單位負面的生效,則在對抗雙方的視角而言,在數學上抵消,等價於技能場不存在從而不違背公理前提。

【公理二:有界性】每秒傷害是一個有限值,存在一個建模規定下的最大值C,使得任意技能強度ε<C。C值是有限的但大於普攻,而普攻傷害是自身的1倍,即C>1。

建模會給定一個最高的每秒傷害值,且為表達技能強於普攻,技能的秒傷必須大於普攻的秒傷。

基於上述公理,我們可以推出如下定理:

【定理一:下確界是一個等於1的值】普攻傷害是自身的1倍,則任意戰鬥單位擁有的任意技能與普攻加和後大於1,從非負性可以推出1+ε>1。

即,只要有技能效果,這個戰鬥單位的強度就一定大於只有普攻的基礎屬性強度相當的另一戰鬥單位。

【定理二:任意技能強度的取值範圍是一個左右均開的實數區域】從C的公式定義、定理一、公理二可以顯而易見這一點:C>1+ε>1。

這是說,技能強度是有界的,並在一個可知的界裡,這個界的最值是由我們指定但絕對有限的。

基於上述共識和推導,我們可以開始細節性的證明存在一個依據強度大小排序的技能序列,從序列可以估計出這些技能效果的強度相當於多少C的後半部分。

讓我們先從昏迷開始,戰鬥平衡的甲乙,甲被乙施加t秒的昏迷效果,則甲對應的損失想了t秒的輸出量,問甲最大受損的每秒輸出量是多少?根據公理二,乙只能令甲最大損失C,即昏迷強度等於C,然而,基於下述共識和推導使得昏迷只能永遠接近C無法等於C:

【公理三:非零性】任意戰鬥單位在戰鬥中總是有機會打出輸出的,即C*>0,C星表示戰鬥單位經各類影響後平均的每秒輸出且根據公理二可推出C>=C*。

一個正常、自然、戰鬥平衡的戰鬥環境,不可能讓某一方完全沒有機會還以顏色導致C*=0,比如自始至終令對方昏迷,彷彿在攻擊一個不會還手的假人。於是,我們推出C>昏迷完成了第一個排序。

昏迷令對方無法移動、施法、普攻,由於C>1+ε,根據公理二C>ε,所以,昏迷>沉默,也就是說沉默無法阻止對方普攻打出傷害,作用範圍小於昏迷。同理的,沉默>定身。定身只能令對方無法移動,難以直接影響其輸出機會。沉默>繳械可由公理二推出,技能建模規定的最大值C必須大於普攻,於是,繳械這種只能影響普攻並少量影響需要特定武器才能釋放的技能,其強度一定小於廣泛影響技能的沉默。

定身>移動減速,因為從極限的角度考慮,減速至多和定身無法區別。昏迷>>閃爍,將閃爍從極限角度考慮,閃過去攻擊對方在對方反擊之前立刻閃爍躲開,反覆如此。這種令對方無法反擊的情況和昏迷無法區別,且因公理三的存在,閃爍不可能設計成這樣,故閃爍強度遠小於昏迷,由於無法限制對方移動,可排序為昏迷>沉默>定身>閃爍。類似的,移動加速的極限情況是閃爍但無法逾越障礙,所以閃爍>移動加速。

擊退和拉近可視為同一效果,且在趨於0的時間內令對方昏迷,故擊退>定身。一般而言,定身的持續時間往往比擊退長很多,所以依據持續和冷卻時間的計算後擊退的強度較為微弱——這符合直覺。

嘲諷>下確界,昏迷>無敵。因為嘲諷完全不能影響C值,但根據公理一和設計目的必然是一個正面效果,無敵無法限制對方移動,故小於昏迷。如此林林總總的技能效果不再一一列舉,需要指出的是一類較為特殊的技能效果,比如攻擊加速、技能暴擊等。這類從簡單的代數變換、期望上可以求得它們最大隻能等於C-1,其中1是普攻的傷害倍數。

目前為止,我們已經盡力證明了為數不少的技能效果雖然強度未知,但可以用不等式排列出強度大小的關係,而且,其上確界是單純傷害下的C值,下確界為1。那麼,我們可以估計這些技能效果的強度了,將C和1視為已知的2個資料點,根據插值基本定理,2個資料點只能進行線性估計,分為2種線性估計法:線性插值半對數模型

線性插值十分簡單,以次序的序號為自變數,C和1為已知的因變數,使用拉格朗日或牛頓插值法即可依序估計出上述技能效果的強度,其斜率表示我們認為技能排序每上升一個序號,技能強度以一個絕對增量變大。

半對數模型
是自變數為序號,但將C和1取對數,再線性插值的結果。該模型的斜率表示我們認為技能排序每提高一個序號,技能強度以一個百分比的增量變大。公式如下:

遊戲數學建模工程手冊


y表示多少倍於普攻秒傷的技能強度,已知的是C和1。β0為截距,β1為斜率,x為序號。兩邊隱式求導:

遊戲數學建模工程手冊


整理並依據鏈式法則:

遊戲數學建模工程手冊


由於x的步長或增量為1,所以:

遊戲數學建模工程手冊


這正是前文已告知的結論。實踐表明,如果技能效果數量較少,那麼線性插值和半對數模型的估計結果區別很小,除非技能效果很多,半對數模型下的非線性估計結果才值得采用。

我們知曉,以微分方程對技能建模是對真實情況的簡化和比喻,真實的技能釋放是離散的,而非微分方程隱含的連續性假設。此外,它無視了一個至關重要的事實,單位的生命值是有限的,承受的累積dps也是有限的,按照C的公式定義,如果一個技能冷卻時間很長,那麼計算出的x將相當的大,技能出手的那一刻會出現不樂見的秒殺對手,這脫離了設計師的目的。

基於插值定理,2個資料點只能線性插值,然而,如果我們用線性方程擬合,將得到完全一樣的結果,半對數模型同樣如此。換言之,從擬合的角度可以給出等價計算,而擬合本質是一種概率模型,它假設資料是隨機的,方程給出的是期望、平均意義上的擬合結果。

同樣的,設計出怎樣的技能可以視為隨機過程,產生的強度是隨機變數,這些隨機變數被證明在一個我們約束的界裡。既然是隨機變數,便總存在著非0的概率超出一般規律的值,在擬合應用中,我們稱呼為異常資料。擬合演算法怎樣對抗異常資料,是現代穩健迴歸的主要研究內容,如普通最小二乘法是不穩健的、均值是不穩健但有效的等等。穩健一詞由統計學大師博克斯在1953年的一篇探討均值和方差穩健性的文章中提出,他對穩健的解釋是真實的情況與假設的概率分佈存在偏差,或觀測資料存在諸多“異常”時,統計方法得出的結果仍然較為不錯。

異常資料是相對普遍的,這是穩健迴歸期望解決的。存在冷卻時間很長的技能這類“異常資料”也是相對普遍的,因此納入叫做崩潰點的概念加以解決。在穩健迴歸裡,崩潰點是指統計指標、方法能容忍總資料中百分之多少比例的異常資料不受其影響估計出好的結果、識別出資料裡的一般規律。

本手冊將崩潰點定義為:技能出手能打掉的最低生命值百分比。我們知道,戰鬥時間是有限的,並會給出一個強度相當的平衡戰鬥下的標準戰鬥時間。顯然,如果一個技能的冷卻時間佔標準戰鬥時間的較大比例,根據C的公式計算會讓技能傷害在普攻配合下打掉同樣比例的生命(而真實的情況還要更遭,因為存在非普攻的傷害技能)。因此,一個技能的冷卻時間如果大於等於最低生命值百分比*標準戰鬥時間,那麼我們稱呼該技能是“異常的”,或更平凡的說:一個大招技能。

自然的,最大崩潰點也需引入,它被定義為:我們容忍的技能出手打掉的最大生命值百分比,通常必須遠小於1。一旦有技能依據冷卻時間被判定為大招,我們從C的公式按照崩潰點和最大崩潰點給出的冷卻時間作為這個大招的計算引數得出結果,即這個大招的傷害能力被約束在了崩潰點和最大崩潰點的區間內,我們可以任選區間內的值作為大招最終的傷害能力,然後傷害能力除以技能的真實冷卻時間得出每秒傷害,這個每秒傷害作為評價眾多大招之間的強度是否差距太大的指標,由下列公式評判:

遊戲數學建模工程手冊


RSD為相對標準差,x槓為所有大招每秒傷害的均值,s為其標準差。根據美國醫學統計學會的建議,相對標準差不大於0.3那麼資料的離散程度是較低的。即:大招之間的強度差距不大。如果超過0.3,則說明這些不同冷卻時間的大招技能有個別的強度弱或強過大多數大招。一言以蔽之,RSD用來平衡大招之間的強度差異。

在上述討論中,我們得出了包括非傷害技能的C公式定義,:

遊戲數學建模工程手冊


技能的設計存在傷害效果,又攜帶非傷害效果,這隱含了一個前提:傷害效果和非傷害效果是不互斥的,同時出現的。那麼,不同技能之間可以不互斥嗎?

如果一個技能釋放後存在一定持續時間的給予對方殺傷,則這個技能不影響你釋放另外的技能,那麼2個技能的秒傷是加和的,這就是不互斥的數學定義。若存在1個或多個不互斥的傷害技能,則C的公式存在2個或多個x,解是不唯一的,我們引入自由度的概念加以解決。自由度來自統計學,它是指存在n個資料、變數,若我們已知其中的n-1個值,從已知的一階和二階統計量可以計算出剩下的1個,這1個的取值是不自由的,該資料、變數的自由度為n-1。同樣的,存在n個未知數x,則我們必須指定n-1個值,最後一個由計算得出。經驗表明,不互斥的技能一般是無需施法者引導的DEBUFF、昏迷等效果技能,這類技能的x最好給的比較低,如此直接傷害技能求出的x才能和不互斥技能少的其他單位差不了太遠,否則玩家視角看來較為不自然。

自由分配屬性點:最值問題


早期遊戲和現在的少部分遊戲裡有讓玩家自行分配屬性點的設計。這樣的設計不論出於估計玩家角色的強度令PVE戰鬥去匹配的目的,還是玩家試圖找到最好的加點方式,都可以歸結為一個數學目標:求約束條件下的最值。

已知傷害運算F(a0,a1,...an)是一個多元函式,n+1為屬性個數,a為屬性型別。顯然,可分配的屬性點總計為100%是一個約束條件且分配的屬性點必須>=0,因為玩家可以不分配某個屬性型別但不能扣減原有的。而這,是求約束條件下的多元函式最值問題,拉格朗日乘數法是這類問題的基本演算法。我方的傷害運算求最大值,而對方對我方的傷害運算是求最小值,一般來說,最好合並改寫為如下公式:

遊戲數學建模工程手冊


合併後的公式可一次性求得最值。需要略微說明的是我們設定的約束條件:

遊戲數學建模工程手冊


換言之,不論具體的總屬性點為多少,均可視為100%。任意具體點數互為線性縮放,不影響計算的最值結果,即對任意可分配點結論均成立,因為:

遊戲數學建模工程手冊


若存在一個k,使得:

遊戲數學建模工程手冊


那麼:

遊戲數學建模工程手冊


k是一個常數,在對F的各變數求偏導並消元解方程的過程中完全不影響結論,我們證明了設總分配點為100%得出的最值結果對具體的任意總分配點均成立。

經濟建模:齊次方程組與樣條插值解


如果戰鬥建模面對的最複雜情形是技能,那麼經濟建模面對的最複雜情形是其本身。與技能建模一樣,遊戲數學建模領域未見有關經濟建模抽象、統一的模型構建思路與方法,而是零散的分佈在諸如線性規劃、概率期望、產耗比、價值等概念裡。本節試圖提出基於聯立方程組的數學工具解決這一問題。

在經濟建模中,我們面對的最根本難題是通過產出和消耗得出玩家在各個養成模組的成長進度(下稱遊戲節奏),計算這一進度隨著產出、養成模組日漸複雜的規則而變得愈發複雜。然而,恰當的給出玩家的遊戲節奏,幾乎是戰鬥——經濟建模成敗的關鍵,因為它不僅預期控制了遊戲內容的損耗程度,也影響了PVE強度對標玩家各個階段強度的可靠性。事實上,許多遊戲數學建模存在的反覆除錯一個常見原因是計算出的遊戲節奏,無法和經濟的產出消耗相匹配,進而導致PVE戰鬥完全不清楚是否如預期那般工作。

建模思路的切入點是:若產出大於等於消耗,則玩家至少可以完成1個進度,並且進度之間有著關聯性。方程可以描述前半段,方程組則描述了後半段,我們寫出方程組:

遊戲數學建模工程手冊


不等式左邊的x表示產出,右邊的x表示消耗,a為各個產出消耗的線性縮放係數,n為養成模組數,m+1為進度節點數也是組內方程個數,整理為:

遊戲數學建模工程手冊


正負性無關緊要且可由x前面的a來負責,於是:

遊戲數學建模工程手冊


立刻觀察到,當不等式取0,形式與齊次方程組相同,齊次方程組形如:

遊戲數學建模工程手冊


此前寫出的2n個未知數x,隱含了廣義道具建模的概念,廣義道具建模是指所有養成道具看似不同,實則可以視為名叫養成道具的特例。不過,因為一些操作細節問題,我們規定1個方程組僅負責1個養成道具:

遊戲數學建模工程手冊


緊湊的寫為矩陣形式:

Ax=0

我們解釋為什麼不等式不取大於0的值。因為這使方程組變為非齊次的,它會帶來如下問題:

1、需要指定非0值b,這將增加遊戲節奏規劃的時間複雜度。

2、非齊次方程組的解由通解和特解線性組合而成,相對齊次方程組求解繁瑣。

3、值b可以理解為我們希望這個進度完成後盈餘多少道具,盈餘的道具會影響後續進度,帶來了複雜的遞推求解。

我們寫出了方程組,解釋了其字母的現實含義,但在1個方程組僅負責1個養成道具的設定下,很快會發現實踐上的困難:

1、若一個或多個養成模組的節點很多,如強化等級。我們要一一安排對應方程來聯立,規劃這些節奏的時間複雜度是較大和令人沮喪的。

2、存在唯一性定理告訴我們,當且僅當至少存在一個自由變數時,Ax=0有非平凡解。如果我們計算的是遊戲貨幣可以使用在2個以上的養成模組上,那麼有大於2個未知數,這種情形很好,它將一次性為我們解出貨幣產出值和這些模組的貨幣消耗值。然而,更多時候我們面對的是基於可控目的的1個道具用於1個養成模組,這意味著我們必須給出其中一個未知數的值,才能求出另一個未知數,比如給定產出求消耗,這違背了期望同時解出產出和消耗的初衷。

3、幾乎可以肯定,方程組個數一定會大於未知數個數,這種超定方程一般是無解或無窮多但沒有工程意義的解,x前面的係數a會決定具體是哪種情況。稍加討論是有用的,a的設定致使方程組無解暗含了一個事實:當產出和消耗曲線被確定,有且僅有唯一的遊戲節奏。換言之,我們既然給出的是遊戲節奏去求解產出和消耗,那麼實際上並不能人為設定a的值,或說只能設定產出的a值或消耗的a值,不能兩者都人為設定,否則很難存在匹配設定的解。

幸運的是,超定方程組存在唯一的最小二乘解,而最小二乘滿足“2”的已知自變數的要求,可以避免“1”的全部規劃進度而是設定關鍵節點從而降低時間複雜度,“3”帶來的麻煩也將不復存在。然而瞭解最小二乘擬合的人會立即注意到以下可能:

1、最小二乘是假設一個多項式方程描述了現象,次數是可選的,存在一定主觀性,通過給定的產出曲線形式來選擇多項式可以一定程度的消除主觀性。

2、真實的玩家養成很難是正態分佈的,尤其存在排名獎勵這類競爭設計時,長尾是幾乎肯定存在的,假設誤差是正態分佈的最小二乘對此是不穩健的。

3、遊戲節奏的關鍵節點一般不多,稀少的資料點難以交叉驗證擬合效果。

4、關鍵節點意味著我們要求玩家恰好是這樣的進度,最小二乘的原理是整體逼近,不一定經過節點,而是越過節點,如果從上方越過節點,那意味著計算出的消耗大於產出,致使關鍵節點的設定形同虛設。

樣條插值是一種綜合了曲線連續性和規避龍格現象的插值方法,我們使用它來解決齊次方程組和最小二乘的困境:

1、通過分段插值規避了龍格現象,演算法相對穩健。

2、一般使用三次多項式,經過了各領域工程的可靠性證明。

3、插值必定經過關鍵節點,只要產出是較少不確定性的(比如概率、排名是不確定的)。即因模型選擇的系統誤差一般小於因產出消耗規則帶來的誤差。

在講解計算細節前說明模型的基本假設是合適的。我們假設特定進度的獲取量等於消耗量,並且這兩個量不為0,,為0意味著線性無關,違反產出與消耗存在關聯的設定。另一不太引人注意的是模型假設了消耗量滿足的前提下,再獲取的資源是沒有意義的(就成長而言)。這種假設在交易系統的情形下存在偏差,一個自由或近似自由的交易系統遊戲,可以使用經濟學的比較優勢來設計產出,因該演算法需遊戲規則和經濟學理論的配合本手冊不予討論這個過於具體的應用。此外,最小二乘和樣條插值作為估計演算法還有一個關鍵假設:產出消耗曲線是單調增函式的——如果不是這樣,那麼稀少的資料點未必能捕捉到週期、一段增一段減的模式,這會帶來極大誤差。

在前文描述裡,我們隱含了模型求消耗而非求產出,產出由我們給定並彙總給模型,這裡說明為什麼不能反過來。原因在於工程實踐中,產出的規則較複雜、多樣、多途徑,如果產出是一個自由變數更容易應對,消耗規則的複雜無外乎大成功、成功、失敗的概率設計,它的多變性很低,更易被模型納入。

完成關鍵節點設定後,便可以彙總產出得到這些節點的累積產出量,依據齊次方程組:

Ax=0

我們得出節點的累積消耗量恰巧等於累積產出量,於是:

X0=X1

使用累積量是將某些每日常數的產出轉化為滿足演算法假設的單調增函式的必要選擇,常數為非負實數的積分形式是線性增函式。此時此刻,我們僅知道關鍵節點的進度,沒有規劃的進度產出和消耗是未知的。呼叫數學軟體或程式語言的樣條插值演算法求出函式表示式後,應用在未規劃的進度上可得出對應進度的累積消耗量,將順序靠後的進度減去靠前的進度便得到消耗矩陣X1的其他未知數。

【吉布斯震盪】在正式使用樣條插值的計算結果前會注意到,得出的消耗值有時比前面的消耗值低和高太多,經驗的說這種情形一般集中發生在前期進度裡。這種現象本手冊稱呼為吉布斯震盪。該術語來自物理學,由物理和數學家吉布斯試圖用傅立葉變換擬合矩形脈衝波時發現。這種現象是因為我們使用連續函式逼近實際是離散變化的現象時產生的不適配,我們的數學工具往往比較理想化,真實現象並不嚴格連續,微觀到如能量的傳遞以一個普朗克常數為間斷。遊戲裡的玩家成長也是離散的、突變的,因為:

1、養成進度是離散的,要麼達成要麼沒有,不存在中間過程。

2、進度之間消耗的最小間隔一般是較大的數字而非1,離散程度明顯。

3、兩個節奏間的設定過快或過緩,產出則過緩或過快,兩者的高階導數不夠接近。理論上可給出兩者較為接近的高階導數資訊,運用分段埃爾米特插值法,這會增加時間複雜度。

4、養成模組要麼開放要麼沒有,多數養成模組在前期集中開放,造成顯著離散,隨著後續未開放的養成模組變少,連續在逼近時會改善表現,這在玩家強度的樣條插值估計裡尤為值得注意,後文會討論這點。

解決經濟的吉布斯震盪有如下方法:

1、更換插值方法,使用樣條保凸插值法。這種方法比較新穎,工程界應用較少,數學軟體目前未見封裝,可以查閱相關論文自行程式設計實現。

2、更換插值方法,使用分段線性插值。不推薦,該方法在關鍵節點不緊湊時誤差難以接受。

3、對震盪處使用線性插值,從而保持消耗需求是不減的。

4、先對樣條插值結果升序排序,後對震盪處使用線性插值。經驗上,這種處理基本可以解決吉布斯震盪。

上文我們使用樣條插值作為齊次方程組的數值解法,較少的去設定遊戲節奏的節點以減輕時間複雜度進而提高工作效率。這種方法不僅用於解決幾乎所有有著進度概念的遊戲經濟建模,也可用於有戰鬥或類戰鬥玩法的遊戲:估計玩家特定階段的戰鬥屬性。

稍加說明為什麼討論經濟建模的演算法會涉及到戰鬥,因為廣義、抽象的說,經濟是戰鬥的一個線性變換或對映,存在一個規則T(x)使得經濟道具變換到戰鬥屬性所在的空間,這個規則或橋樑對遊戲而言就是玩家通過消耗道具達成進度得到的戰鬥屬性成長。一個有效的玩家戰鬥屬性估計表明瞭如下性質和事實:

1、遊戲節奏的規劃被正確的產出和消耗計算結果很好的實現了。

2、遊戲內容的損耗被正確的通過經濟控制了。

3、PVE和PVP對手的戰鬥屬性可以正確的匹配和計算,從而控制了戰鬥感受、難易、卡點等。

已知遊戲節奏若干節點的養成進度,若有進度提供戰鬥屬性,則可知該進度的玩家戰鬥屬性,未規劃進度的戰鬥屬性未知,應用樣條插值可估計出未知進度的戰鬥屬性。就戰鬥屬性的樣條插值解而言,它的吉布斯震盪比經濟建模的解在前期更為劇烈,因此,除上文所述方法解決外,還需考慮原則:

1、集中的新手引導在多少等級或階段結束?

2、多數產出模組的集中開放在多少等級或階段結束?

找出該等級令等級加一,然後不小於該等級的戰鬥屬性除以經驗係數2到3區間的任意實數抵消吉布斯震盪帶來的誤差。通常來說,吉布斯震盪產生的誤差和擬合脈衝波那樣趨向於一個常數,經驗發現是大體2到3,實測選取最合適的經驗係數。而成長為離散、突變導致的震盪需考慮到成長存在時間滯後性故等級加一,時間滯後性是說產出模組在X等級開放,玩家自然的行為是一邊獲取產出一邊獲取升級經驗導致升級,而不是X等級立即得到這些產出帶來的成長。

我們如何解釋樣條插值估計出的玩家戰鬥屬性?考慮一個事實,同樣等級的玩家戰鬥屬性不可能恰好一致,A強化了所有部位,B僅強化一部分,C則未感覺PVE有阻礙所以沒有強化。只要遊戲沒有強制規則的要求養成進度必須怎樣才能繼續升級(也沒有哪個遊戲這麼做),那麼一定存在隨機性使得不同玩家在相同等級下戰鬥屬性有所不同。我們稱估計結果是平均意義上的,同等級全體玩家平均起來就是我們的估計結果。隨機性或不確定性意味著,我們可以通過內部人員跑遊戲、收集線上真實玩家資料,檢驗估計結果的誤差。

然而,一般令升級模組所需時間遠小於其他養成模組以製造付費空間。這便出現長尾效應:接近最高等級的少部分玩家付費獲得更大的強度,同等級大部分玩家掙扎於免費產出緩慢提升。對於這種現象,我們用2次估計解決,第1次估計的最終節點是剛到最高階時對應的其他養成模組進度,第2次估計的最終節點是戰鬥建模投放的最大屬性。第1次估計我們稱為常規成長線,第2次估計稱為付費成長線。可以證明,任意付費額度下的戰鬥屬性是2個成長線的線性組合,因:

遊戲數學建模工程手冊


r表示付費額度,只可能取0和最大付費深度的閉區間任意實數。由於第1次估計基於免費玩家r=0的遊戲節奏設定,進而有:

遊戲數學建模工程手冊


換言之,付費額度帶來的戰鬥屬性F(·)變化是一個單調非減函式,假設不考慮折扣的1分錢買1分貨,則對於r的任意k倍取值,有:

遊戲數學建模工程手冊


k可以取值為負數在工程上對應遊戲裡的免費贈送付費貨幣。設u、v是非負實數,且u+v=1,則必定存在一個r使

遊戲數學建模工程手冊


等式成立,或說任意r是免費玩家和滿付費玩家強度的線性組合,u表明了付費玩家同時具有免費玩家獲得的成長屬性然後加上v倍的最大付費得到的屬性。讓我們證明這個等式,免費玩家成長的資源可以換算成相當於多少r,記為r*,免費玩家是付費情況的特例,r必定是r*的k倍、rmax的j倍,於是:

遊戲數學建模工程手冊


進而:

遊戲數學建模工程手冊


令u=k/2,v=j/2,我們有:

遊戲數學建模工程手冊


這就得出了我們想要的。接下來我們證明u+v=1,顯然:

遊戲數學建模工程手冊


又:

遊戲數學建模工程手冊


於是:

遊戲數學建模工程手冊


且:

遊戲數學建模工程手冊


代入:

遊戲數學建模工程手冊


於是u+v=1。對v>=0.5,在r*未知時值r的界為:

遊戲數學建模工程手冊


進而知道r的大體範圍。v<0.5時界為:

遊戲數學建模工程手冊


v接近0時,r也接近0。通過計算r*可改善v<0.5時的界,但一般過於繁瑣沒有必要,大體知道r更接近免費玩家即可。將任意付費額度玩家的戰鬥強度用免費和滿屬性玩家線性組合而成,這種建模思想有著如下好處:

1、理論上存在任意付費額度對應同等級(主要是接近或已是最高等級)無窮多戰鬥強度,線性組合可以很好的表示。

2、人為劃分付費玩家層次為超R、大R、中R、小R假設了靜態的付費額度,並假設不同層次各個養成模組的進度和付費投入,主觀性強,假設過於脆弱,把付費行為視為動態的變數更有可操作性,也降低了計算的時間複雜度。

我們會在【廣義PVE建模】裡看到成長線估計的實用性。

廣義PVE模型


戰鬥是眾多遊戲常見的內容,一場戰鬥有著怎樣的表現可以通過數學語言描述,而表現有多種形式:多人戰鬥、陷阱、藥瓶、護送NPC等等。傳統做法往往止步於討論1vs1,本節將說明這些看似不同的形式均可以統一的建模,這便是標題“廣義”一詞的含義。不僅如此,本節還提出了以擇取量化戰鬥感受的指標為核心,逆運算對抗單位相關屬性的思路,這一點是至關重要的,其餘的僅是技巧。

在【評估模型】裡,我們提出了可操作性的概念,它是指我們必須嘗試量化我們的關注物件,這不僅有利於他人可重複你的方法,也有利於納入數學的框架。廣義PVE模型使用戰鬥時間回合數玩家損失hp%、兵力損失%來數學化的表示戰鬥感受、戰鬥節奏、戰鬥難易、卡點等文字用語。本節不會過多涉及已經充分認識的1vs1,而是將注意力集中在如下戰鬥形式上:

  • 多人戰鬥:涵蓋1個角色對抗任意數量怪物、多個玩家角色對抗任意數量怪物、多兵力與多兵力戰鬥。
  • 陷阱與藥瓶:陷阱是一種特殊的怪物,因此它的數學處理略有不同,藥瓶可以視為等價的生命上限提高。
  • 非作戰NPC:NPC指對玩家友好的單位,護送不能戰鬥的NPC、需要保護的基地、障礙物等屬於這個範圍。
  • 作戰NPC:幫助玩家一同作戰的友好單位,這將影響怪物們的強度計算結果。

【多人戰鬥】許多遊戲設定讓玩家主要操縱1個角色,所以1vs1是一個得到廣泛應用的簡單模型,奇怪的是卻未見進一步引申1個角色同時對抗多個怪物,尤其是怪物強度不一時的分析。業界有一種通常做法是設定新手怪、普通怪、精英怪、BOSS怪的屬性係數模板,然後這些模板在1vs1的框架下計算,因此1個角色對抗多個怪物僅僅是多個1vs1的線性疊加。這種方式可行但具有如下弱點:

1、模板意味著1vs1的結果是固定的,總是相同的戰鬥時間、玩家損失hp%。於是再加入每個屬性可手動調節的偏移係數來解決這一問題,從而導致前文批判過的預期結果模糊及引數濫用。

2、需要人為彙總每個1vs1的戰鬥時間、玩家損失hp%。這不僅增加時間複雜度,還導致不同關卡使用同一怪物模板但不同數量時,關卡難度飄忽不定。

3、不利於快捷計算NPC存在的戰鬥形式。

本文並不將1個角色對抗多個怪物視為多個1vs1,而是將怪物們視為1個怪物,然後僅進行1次1vs1的計算,要做到這一點,我們必須從怪物角度建模而非玩家。我們用2個概念來修正“多個怪物視為1個怪物”時存在的一些與事實不符的情況。

第一個是叢集,叢集是指M個相同強度的怪物同時面對玩家,期望怪物們在生存時間內令玩家損失p%的生命值,每個怪物負責p%/M。不難發現,玩家會殺死怪物致使M叢集帶來的p%減少,真正的1vs1是不會因生命損失而衰減輸出能力的。作為修正這一模型缺陷的開始,我們注意到M叢集會損失的最大輸出比例不超過(M-1)/M,數字1表示最後一個怪物不存在輸出損失的問題,我們提前加上這個比例來對抗衰減,於是有:

遊戲數學建模工程手冊


即當M足夠大,我們認為提前加上會損失的比例然後分配給每個怪物,在漸進意義上等於M叢集平均每個怪物造成的玩家生命損失佔比,左端等式分子的1是我們要求M叢集令玩家損失的p%生命值比於自身是100%。證明這個等式成立,整理:

遊戲數學建模工程手冊


右端第一項顯然相等,而和的極限等於極限的和,於是對第二項應用洛必達法則,分子分母同時求導:

遊戲數學建模工程手冊


從而左右兩端趨於0,等式成立,右端第二項本質是誤差項。但M要求足夠大,是否符合實用性呢?與解析解對比如下:

遊戲數學建模工程手冊


圖表說明M無需特別大,誤差即可快速減小。解析解計算公式如下,M叢集的無陣亡輸出為M*x,但只能維持1/M比例的時間,x表示單個怪物的輸出強度佔總輸出的比例:

遊戲數學建模工程手冊


求滿足令玩家損失p/p=1的x,可整理為:

遊戲數學建模工程手冊


緊湊的:

遊戲數學建模工程手冊


遊戲數學建模工程手冊


分子分母同除M:

遊戲數學建模工程手冊


分母位置可使用首尾相加成1將求和轉化為相乘,於是:

遊戲數學建模工程手冊


儘管我們有解析解的計算公式,但使用近似解的理由是相當實際的:解析解理想的假設怪物是一個一個均勻時間被殺死。考慮到怪物不如玩家有效率的打出輸出、缺乏隨機屬性以及玩傢俱有AOE能力,高估怪物輸出的近似解反而能適應真實戰鬥。

叢集概念將1個角色對抗多個怪物轉化為1vs1。我們只需給定p然後除以M分配到每個怪物身上即可,這種分配僅適用於乘法傷害公式和前文的減法傷害近似公式,因為它們滿足線性可加性。波次則是另一個相似但不同的模型概念,它描述了關卡、副本怪物們分批次面對玩家,由於我們已經用叢集“打包”了特定批次的怪物,所以不存在怪物損失輸出的問題。如果批次怪物的強度相當,則簡單除以波次,否則可以讓戰鬥時間t和損失生命p按不同比例分配給不同批次的怪物,比例加和等於1。不難證明,從前文我們有:

遊戲數學建模工程手冊


分母位置是玩家強度,1表示強度相當則損失100%生命值。現在要求損失p,等式兩端同乘p:

遊戲數學建模工程手冊


存在u和v,使下式成立:

遊戲數學建模工程手冊


則u和v分別稱呼為生存力和威脅力,滿足:

遊戲數學建模工程手冊


其自由度為1,我們需給定其中一個值,通常給定u,u滿足:

遊戲數學建模工程手冊


hp*是怪物的生命值,我們知曉生命值和戰鬥時間t是線性關係,所以:

遊戲數學建模工程手冊


分母t是2個強度相當的角色對抗的戰鬥時間,t*由我們給定期望怪物在玩家面前生存多長時間,則威脅力:

遊戲數學建模工程手冊


已知u且hp已由樣條插值估計得到,則hp*可得:

遊戲數學建模工程手冊


已知v,設a為玩家攻擊力,則怪物攻擊力a*:

遊戲數學建模工程手冊


現在有N波次怪物,每波次怪物強度不同,但合起來滿足t*和p。我們用ki、ji分別表示第i波怪物負責t*、p的比例,那麼第i波怪物的ui、vi計算公式為:

遊戲數學建模工程手冊


到此,我們完善了將多個怪物視為1個怪物但僅需1次1vs1計算的建模。值得指出的是,我們無需關心hp和dps,因為它們在過程中是約掉的,僅用u和v來表示相對於hp和dps的線性縮放係數。另一個需要說明的是,在叢集建模中,我們假設M個相同強度的怪物同時面對玩家,實際中存在不同強度怪物同時面對玩家,這也會帶來怪物陣亡造成輸出能力損失,這種情形目前本文選擇作為誤差加以容忍,主要原因在於不同強度怪物陣亡的先後順序不同帶來的結果也是不同的,其排列組合之多難以計算,本文作者認為若視為一個均勻分佈求損失期望或許可以解決,但還需完善落地可行性。

在“多個玩家角色對抗任意數量怪物”裡,我們所需解決的是多角色問題。一個相當簡單的方法是:

遊戲數學建模工程手冊


即玩家數乘以100%生命比例即可。儘管角色可能存在職業、戰鬥能力的不一,但一般而言我們在對職業建模時是取平衡為目標的,所以平均而言損失hp為1。

上文我們填補了1對多和多對多的模型空白,由於本質是納入1次1vs1的計算框架中,所以我們並不能同樣方法的處理“多兵力與多兵力戰鬥”。多兵力戰鬥的明顯特點是雙方兵力在持續損失,兵力損失帶來了輸出損失,因此戰鬥時間或回合數基本不是線性變化的。我們想知道給定任意兵力,戰鬥多長時間、兵力損失多少比例。比起直接建模,對兵力變化建模反而更簡單,寫出微分方程組:


遊戲數學建模工程手冊


雙方在t時刻的兵力為x、y,x和y是關於t的函式,雙方損失兵力dx、dy與對方在t時刻的兵力及雙方的dps和hp有關。求解這個微分方程組,對第一個微分方程關於t求導:

遊戲數學建模工程手冊


把第二個微分方程代入消元,其中a=dpsy/hpx,b=dpsx/hpy:

遊戲數學建模工程手冊


整理成二階齊次微分方程的形式:

遊戲數學建模工程手冊


它存在通解,列出特徵方程:

遊戲數學建模工程手冊


於是x(t)的通解為:

遊戲數學建模工程手冊


對t求導並代回第一個微分方程:

遊戲數學建模工程手冊


遊戲數學建模工程手冊



整理出y(t):

遊戲數學建模工程手冊


聯立之:

遊戲數學建模工程手冊


聯立方程組可求出任意t時刻x和y的兵力。存在x、y、C1、C2、t共計5個未知數,我們必須給定其中3個。如果x為玩家,那麼我們用樣條插值已估算出t=0時的兵力,所以是已知條件,接著我們給定戰鬥時長t,令y(t=t)=0表示我們希望在時長t內玩家消滅對方全部兵力,即可消元求出C1和C2,然後令t=0、C1、C2代回第二個方程求出y(t=0),將t、C1、C2代入第一個方程可計算出玩家剩餘兵力來表達戰鬥的難易感受。類似的,我們也可以給定t、在t時刻x的剩餘兵力比例、y(t=t)=0求出滿足t且x剩餘兵力比例雙重條件的y(t=0)。

使用微分方程組建模隱含了一個連續性假設:雙方最小的完整戰力可以取任意非負實數。真實情況是1個單位具有特定生命值,在它生命值耗盡前不會喪失輸出能力。因此,為了令微分方程組的解可以很好的近似真實戰鬥,我們必須讓戰鬥過程“足夠連續”。數值模擬表明,任意單兵的輸出與生命之比不能大於0.2,否則微分方程的解不可用,如果在0.2附近,那麼解乘以0.9進行離散修正,如果遠小於0.2那麼解充分近似。這個前提是符合常識的,當輸出和生命之比高於0.2太多,那麼1個單位殺死另1個單位僅需很少的攻擊次數,少的攻擊次數意味著兵力隨t高度離散變化。這一前提對存在先後手機制的多兵力戰鬥尤其需嚴格遵守,而先後手從程式碼的數值模擬結果得知,並不是猜想的那樣先手會更多的保留兵力從而拉大與後手的優勢,事實上模擬證明,若輸出與生命之比遠小於0.2,那麼方程解除以0.9-1可充分近似,否則除以0.75-0.8修正。

【陷阱與藥瓶】陷阱的傷害與陷阱的生存時間無關,這是它有別於其他PVE戰鬥形式的一點。一般來說,我們可以在程式上設定邏輯,令陷阱總是以百分比對單位造成生命損失,甚至區分玩家和怪物造成的百分比。不過,如果沒有這種機制或者陷阱會在BOSS戰中出現,簡單的百分比則不便於應對,此時需要數學建模。該模型非常簡單:根據1次期望損失生命的值,通過傷害公式逆運算出陷阱的攻擊力即可。只是需要注意的是,陷阱還應區分針對玩家還是針對怪物,關卡設計有的陷阱是希望玩家加以利用,有的陷阱則是為玩家準備的。對怪物準備的陷阱還應指明針對的哪個M叢集,先除以M再逆運算。藥瓶恢復的生命比例h可以視為怪物需要面對的是n*1+h個玩家,等價於等比放大怪物的輸出,就可以滿足t*和p。

【非作戰NPC】一個障礙物、要保衛的基地、要護送的NPC。只要它們不能戰鬥都稱呼為非作戰NPC。通常情況下它們遭受來自怪物的攻擊,但我們僅需知曉怪物令玩家損失的生命p就能計算出非作戰NPC的生命值,非作戰NPC生存力u:

遊戲數學建模工程手冊


遊戲數學建模工程手冊


這是前文已經給出的演算法。由於p表示玩家在怪物面前損失的生命比例,那麼從:

遊戲數學建模工程手冊


可知怪物強度相當於p名玩家,則hp*與p的關係是線性的:

遊戲數學建模工程手冊


特別的,當p等於1,可視為非作戰NPC的受損來源是玩家,比如障礙物。

【作戰NPC】與非作戰NPC相同,我們僅需已知怪物令玩家損失的生命p。p不僅表達了損失生命的比例,也表達了相當於多少個玩家,因此給定作戰NPC相當於w個玩家即可,然後找到滿足以下式子的u、v:

遊戲數學建模工程手冊


一種方式是像怪物那樣給出u,然後計算v,但這將增加輔助列的個數,並且作戰NPC一般沒有那麼值得關注,所以推薦:

遊戲數學建模工程手冊


於是當作戰NPC被怪物針對攻擊時,怪物生存時間t*內,作戰NPC損失生命值p*隨p正比放大:

遊戲數學建模工程手冊


證明非常簡單:

遊戲數學建模工程手冊


遊戲數學建模工程手冊


兩者相除,於是:

遊戲數學建模工程手冊


遊戲數學建模工程手冊


令p*=p/w,證畢。

在上述內容裡,我們反覆使用了一個基本的模型:

遊戲數學建模工程手冊


不斷的變換為其他等價形式,讓我們從不同角度發現了它可以擴充套件的實用價值,並將等價形式賦予工程應用意義,如損失hp比例、相當於特定數量的玩家、相當於1名玩家角色多少比例的生存力等等。從這一點我們可以看到,數學運算的變換彷彿是換個角度看問題促成新的發現,這是本文致力於用數學語言闡述的重要原因之一。

【數學建模與遊戲開發】


在終極的分析中,一切知識都是歷史;


在抽象的意義下,一切科學都是數學;


在理性的世界裡,所有的判斷都是統計學


——C.R.勞


與數學在機械製造、化學、物理、機器學習的地位不同,遊戲開發的數學建模工作在如今業界的專業性、系統性非常低下。一種言論可以瞥見一二,“高中數學知識就夠了”,這種言論即便不是反智、反知識的,也是毫無益處的自我貶損,《法言》裡說“人必其自愛也,而後人愛諸;人必其自敬也,而後人敬諸。”

除了數值策劃專業、實踐能力的低下外,有時也會碰到這樣的遭遇:

本文作者曾使用中位數這個穩健指標計算生命與魔法瓶,當我向直屬上司說明這個思路時,他問道:“什麼是中位數?”“就是一組數值中間那個位置的數。”我回答。

該例說明一個專業而系統的數學建模工作者時常碰到這種知識體系上的溝通障礙,儘管中位數是一個高中數理統計會學習到的概念。很不幸,數值策劃專業性的低下加劇了這種糟糕的局面,使業界充斥著含混不清、不統一的關於在遊戲裡如何數學建模的用語,也令決策者想當然和自以為對數學建模的瞭解出發下達一些要麼含糊不清、要麼不便於數學化的需求。不能指望決策者具備相應的數學知識,然後正確的給出方向,所以很多時候依賴於數學建模的專業知識對需求進行吸收、理解、提煉以及糾正存在的問題,正如遊戲程式設計師那樣,轉化為自己掌握的程式語言(我們則用數學的形式),當程式需求存在矛盾,程式設計師需要糾正,同樣的,當需求不便於數學化、量化或使問題複雜化,專業的數值策劃理應加以糾正。舉例來說,在前文裡我們提及,付費體驗、戰鬥體驗等詞彙只能用於日常交流,對於數學建模則必須擇取指標加以量化,付費體驗我們使用了戰鬥優勢1-p來定義,戰鬥體驗我們使用了戰鬥時間t、損失生命比例p和剩餘兵力比例。換言之,數值策劃要有將數學與實際聯絡起來的實踐能力,並且不應活在認為某些指標有現實意義或對玩家而言利於感知的想當然裡,這一點在手冊前半段有著墨。

一個盈利上成功的遊戲,不等於其數學建模的巧妙、高超,反之穩定、精妙的建模也不能促進遊戲的盈利。玩家對遊戲裡的數值表現如何,他的感知或測量能力不是機械那般敏感,因此一些錯誤會被容忍。而且,即便一個專業和實踐力低下的數值策劃,往往不會犯充錢就會變得更強的方向性錯誤,更遑論遊戲產品近似一個模擬環境可以反覆除錯了。但為什麼提升數學建模的能力,習得更多的數學知識仍然對遊戲開發是有利的呢?

1】時間複雜度低、充分近似的建模,大大減少了遊戲開發的成本,至少在數值崗位這個工作分割槽上可以減少成本,尤其是縮短除錯,進而提高專案表現的穩定性。
2】好的建模儘管不能促進盈利,但有時能幫助發現潛在的程式開發錯誤或系統規則上的不完善。這類錯誤往往會表現得戰鬥、付費的體驗不符合預期,進而懷疑是數學建模的問題。本文作者碰到過多次這種情況,但每一次都證明模型是正確的,錯誤的產生來自程式碼邏輯、配置的引用資料以及系統規則的矛盾。
3】一個決策者若具有對數學建模正確的理解,如低時間複雜度、可操作性,那麼可以甄別數值策劃的優劣,從而促進團隊與專案的穩定發揮。

對數值策劃本身而言,也是有利的:

1】增加工作效率、穩健性。
2】數學作為萬金油,可以讓你找到更好的職業發展機會,或是領域內機遇的挖掘。
3】2019年一篇經濟學論文《Job Tasks,Time Allocation,and Wages》證明,在所有高技術工作內容中,處理資訊資料的高技術帶來的工資正面影響是最大的。

希望本手冊對業界廣大從事遊戲數學建模工作的人士有所幫助。


巴比倫派數值策劃Q群:813299364


相關文章