當前位置: 華文問答 > 遊戲

像阿軻(荊軻),隱刺,小醜這種從背後暴擊在程式碼上是怎麽實作的?

2017-05-15遊戲

看了所有的回答,都把焦點放在了「如何判定在背後」,其實這只是一個初中算數的問題,那麽思考一個問題——這幾個人的攻擊恰好是近戰攻擊,我們是否允許設計一個英雄,他也有「任何傷害背後攻擊必爆」的特性,但是他的4個技能是:

1,向前丟出一個回力標,飛到一定距離後折返,類似LoL的輪子媽的Q,策劃要求「如果背後命中敵人則必爆」。

2,在身邊召喚雷電球順時針環繞自己,擊中敵人後會爆炸,策劃要求「如果從背後擊中敵人則必爆」。

3,飛出魚叉,抓住一個目標並拽回,目標被拽回的路徑上的敵人碰到目標都會受到傷害,策劃要求「如果目標被拽回時,從背後撞擊了路徑上的人,則此傷害必爆」。

4,大招:在遠處召喚8道水柱,水柱順時針螺旋向中心(即釋放技能時候角色的位置)移動,對碰到的敵人造成傷害,對碰到的友軍造成治療,策劃要求「如果是從正面碰到友軍則治療必爆,如果時從背後碰到敵人則傷害必爆。」

思考一個問題——以上四個需求為什麽不可以?那麽問題來了!—— 這4個傷害的「背後判定」,一定與「我」(釋放這個技能的人)的位置有關嗎 ?所以我想說,樓上的大多是紙上談兵,那麽作為一個實際幹出過數款上線並有幾款成績不錯的Moba遊戲的我就從最簡單的實作來談談這個在真實的Moba遊戲中是如何實作的。


在這個問題中,涉及到的數據以及他們的最基礎內容:

1,CharacterObj(角色物件),有一個內容面向(FaceDirection),為了編寫lua指令碼的策劃便於理解,我們通常使用0-359的整數,描述了一個角色面向的角度,這裏還要註意一點——在很多遊戲設計的需求下,面向的角度不等於角色移動的方向的角度,你可以根據需要把面向(FaceDirection)和移動角度(MoveDirection)做一個分家,但是這個問題下,我們關註的只是FaceDirection。

2,DamageInfo(傷害資訊),通常新手會認為這個是一個多余的環節,但是如果你真的理解了我的buff機制(你可以從知乎搜尋「如何設計一個易擴充套件的遊戲技能系統」),你會發現整個流程中這是一個必要的東西。首先我們來說DamageInfo通常包含的內容(與本次討論無關的內容就不再這裏列出了,根據專案的實際需求擴充套件這個結構就行了):

1)Damage: 通常在Moba中是int,如果你還會用到金木水火土等內容傷害,那麽可以把它定位Array,如果你是傳統頁遊,那int其實很難滿足你的需求。無論如何,你需要一個地方暫時記錄這次傷害的值。

2)isHit:boolean,是否命中,是否能夠命中並不影響造成的傷害,傷害管傷害(Damage)計算值,會影響最後命中的因素非常多,所以這裏只記錄當前傷害資訊能否命中。

3)isCritical:boolean,是否暴擊,同是否命中,你不應該因為暴擊了直接就把Damage進行運算,我們說DamageInfo這個資訊用於最後的傷害計算,所以最後實際算傷害的時候,會根據DamageInfo.damage和DamageInfo.isCritical得出一個合適的傷害數碼的。

4)degree:int,0-359,傷害來源的角度,這個角度就是當前問題的關鍵,由於遊戲中有太多的因素會產生傷害,所以每一個因素在產生傷害的時候都會有不同的賦值方式,因此這裏會涉及到另外一個課題——將傷害來源做個抽象歸類,合理的設計下應該是這樣的:



當你的遊戲依賴的邏輯物件是:

bulletObj:在Moba類遊戲中那些必定命中的、通常用於單體的技能,請記住,技能的效果未必是傷害,傷害只是效果之一,這才是對的抽象!

aoeObj:在Moba類遊戲中通常是一些範圍性技能。

buffObj:給角色添加buff的處理。

這3個邏輯物件的對應「效果」(確切的說是回呼點)的函數中,可能帶有產生傷害資訊的介面,由此,我們可以獲得這個DamageInfo,也正是在此時,根據遊戲的規則來賦值了這個DamageInfo.degree:

bulletObj的degree,通常等於這個bulletObj在命中時候的方向。之所以說是「通常」,因為遊戲策劃可以重新定義他的用法,下同。

aoeObj的degree,通常等於aoeObj.position到產生傷害資訊的物件角色的向量的角度。

buffObj的degree,通常是0,也有用buffObj.caster(釋放這個buff的角色)當前(buffObj邏輯回呼瞬間)的面向作為degree的,兩者都是科學的,取決於策劃設計需要。

實際上我們看開篇我命題設計的4個技能,他們的degree的確和「我與目標」的位置沒什麽關系,而是與「我」發出的aoe/bullet與目標的位置有關系。


也許我需要進一步的解釋一下好的傷害流程的抽象,才能讓你更明白DamageInfo的意義,那麽我們就接著說:


請註意,這個傷害流程適合於任何需要傷害邏輯的遊戲,在這裏我們穿插了對buffObj的回呼點的處理,把這些處理丟給指令碼也好,丟給其他程式邏輯程式碼段也好,這都OK,關鍵在於—— 整個傷害流程是一個變化DamageInfo值的過程,最後依賴於DamageInfo的數據,我們產生了真正的傷害 。事實上,很多類似「背後必爆」的處理,都是在這一段裏透過buff機制來實作的。

當你理解了這個流程的時候,我想你不難寫出這樣一個buffModel(用於建立一個添加在角色身上的buffObj),偽代碼如下:

buff.id = "crit_behind";

buff.visible = false;

buff.onHit = function(buffObj, target, damageInfo, designParam) {

if (math.abs((360 + damageInfo.degree - target.faceDirection) % 360) <= 60) {

//在邏輯的世界,命中的時候,2個點(傷害來源和挨打者)必然重合,所以我們只能認為如果2個人的面向是相向的,並且差距在一個可接受範圍內,那麽就是「背後攻擊」(因為來源會定義不同的方向,這是給來源留個活路,這裏涉及到一個邏輯架構能力)

damageInfo.isCritical = true;

}

return damageInfo;

}


就是這樣的簡單思路,很輕易的就能實作你來自任何渠道的傷害和你能想到的一切處理,比如說「來自正面的傷害會治療目標」這種,我相信聰明人看到這裏已經狠輕易就能知道怎麽做了。 所以說,這個問題的根本,並不是用一個數學公式解決2個點的方向問題,而是一個邏輯抽象問題——合理的遊戲邏輯業務框架該如何設計才是問題的根本