這個問題是不可迴避的 ...
本文轉至:http://bbs.chinaunix.net/thread-1692302-8-1.html這個問題是不可迴避的
(只作轉載, 不代表本站和博主同意文中觀點或證實文中信息)
再比如,傳說中的面向對象本該大顯神威的游戲領域——就說流行的WOW吧。
這個游戲有10個職業,10個種族,每個種族都有自己的幾個特有種族天賦(這個種族天賦還可能根據職業有所不同,比如血精靈);每個職業有幾十甚至上百種不同的技能/法術,這些技能有近戰技能,有遠程技能;有的技能會對敵方造成傷害或不良狀態,有的技能能給己方隊友加上好的狀態或治療隊友;而且很多這類技能還會根據目標的狀態切換不同的效果;有些技能是單體效果,有些技能是光環效果(又分為對地方造成光環效果還是對己方兩種,也可能兩者兼備),而另一些技能是地圖範圍效果(如烈焰風暴是一個圓形區域;冰錐術是一個錐形區域;特別的,順劈斬是在當前攻擊目標旁邊不超過5碼的另一個敵對目標——某個boss的順劈斬更強,它會從第一個目標傳遞幾十個目標,總傳遞距離可以達到誇張的幾百碼;並且這個傷害也是各有特色的:戰士的順劈斬是每個目標傷害固定,有些boss的則是同時挨打的人越多傷害越低,但還有個變態boss卻是被打的人越多傷害越高……);大多數技能還可以通過天賦雕文強化/改變的面目全非(比如插一個雕文,法師的火球就不會造成持續傷害但施法速度增加;點一個天賦,法師的冰冷減速效果就會降低對方受到的治療效果;點某個天賦,盜賊的某些技能攻擊就會延長自身提升攻擊速度這個狀態的持續時間,等等);還有很多技能是因為學習了某個專業或裝備/持有某個物品而得到(比如,學了採藥,就可以得到生命之血這個技能,每3分鐘可用,能夠在若幹秒內回覆你若幹生命值——這個技能和採藥技能等級掛鉤,但很可能接下來的某個版本,就會再和玩家的生命上限值掛鉤,以避免它像現在一樣,被玩家斥為廢柴技能);另外,不同等級的技能可能有施法時間甚至額外特效方面的差別;此外,每個技能會造成不同屬性的傷害/效果(神聖、暗影、元素、物理等等),甚至一個技能同時造成多種類型傷害效果,更有冰火球這樣根據目標抵抗力而智能選擇更大殺傷效果類型的變態魔法……
最後,最最重要的是,這所有職業上千個技能(或許加上NPC特有的一些技能,數目會達到幾千種)並不穩定,常常會因為某個技能或某些技能的組合過於強大/弱小而加以修改(比如加一個額外的負面狀態如無敵/聖療;甚至全面修改“抗性”“破甲”概念的定義)——玩過wow的都知道,這事幾乎每個月都有發生。
好吧,你打算怎麼設計這數千個技能/效果?
或者,你就這樣把這些概念用class這個筐一裝,然後到處開特例、特例都解決不了就搞23個模式使勁往一塊粘,管他整體結構如何,淌哪算哪?
扯淡。
有個故事說的好:
有人送幾個瞎子一條魚,瞎子們高興壞了,決定熬魚湯喝。魚湯熬好了,瞎子甲嘗了一口,真鮮啊;瞎子乙趕緊也喝一口,太鮮了,太好喝了。幾個瞎子一邊喝一邊贊美——忽然瞎子丙叫了起來:魚跳我腳上了,它不在鍋里!
眾瞎子大驚:這魚都沒放到鍋里,湯就鮮成這樣了;要是放進鍋里,還不得把我們都鮮死啊!
眾面向對象原教旨主義者把事情攪得一團糟,同樣也會大驚:天哪,用了面向對象都複雜成這樣,這要不用面向對象,這軟體就不能寫了吧!
暴雪在Diablo 2時代已經解決了: 法術/技能資料庫化
所謂資料庫化,其實等同於表格化,例如我的簡化方案:
法術ID 動畫效果 作用範圍 作用類型 屬性 特殊限制 強化類型 特殊設定
特殊設定可以是一段LUA代碼,比如可以在其中搜索、設置傷害類型,查詢順劈斬/治療鏈等技能的傳遞目標等等。
特殊限制,如驅散限定為只能作用於魔法性buf/debuf(根據職業不同,可能有進攻性驅散和防守性驅散之一,也可能同時具備——這就體現在可否驅散敵方/友方目標的debuf)
在這個方案下,釋放一個法術/技能,就成為一種查表運算——找到此法術ID,找到它的作用類型和傷害屬性,計算特殊設定(包括但不限於順劈斬模式的判斷、天賦加成和天賦效果、雕文加成和雕文效果等等)。
於是,到最後,整個法術體系被分為一組組的魔法buf/debuf、物理buf/debuf,這些buf/debuf會影響傷害公式中的某個因數或者造成傷害效果;而傷害效果又分為立即傷害/立即治療和持續傷害/持續治療;最後則是一套影響範圍判定機制。
舉例來說,騎士開聖盾,他同時得到一個buf和一個debuf。
buf是“無敵”,效果相當於設置傷害公式 a*(....) 前面的a因數為0(沒有無敵時此因數為1),於是所有傷害無效。
debuf則是“自律”,因為他的聖盾、聖療技能判斷條件里都有“有自律debuf,則不允許使用”的設定,於是禁止他在短時間內再次使用這些無賴技能。
敵方法師對他釋放寒冰箭,系統受理,但查詢騎士狀態,發現他處於無敵狀態,返回大大的兩個字“免疫”。
然後,有一個敵方牧師對他使用驅散,查詢牧師的驅散術發現,在驅散術的可驅散列表裡沒有聖盾術,於是提示無法驅散或驅散了另外的可驅散(魔法)效果。
敵方牧師迅速反應過來,再次對他使用強力驅散;查詢牧師強力驅散術,發現該牧師在不久前使用過強力驅散,提示無法施法。
等待3秒後,敵方牧師發現自己的強力驅散冷卻(cool down),再次使用強力驅散,查詢發現強力驅散可驅散聖盾術,於是成功移除騎士的無敵狀態。
現在,敵方法師再次對他釋放寒冰箭,騎士切換冰抗光環,系統查詢騎士狀態,發現冰抗光環,又查詢法師穿透等級,和暴擊等級,根據公式計算能否命中、能否造成全額傷害以及能否暴擊;然後提取法師和騎士雙方裝備、天賦數據代入公式計算傷害加成、減免數據,最後給出騎士受到的傷害數字(包括部分抵抗了多少)。
在暴雪設計師的整理之下,如上種種最終構成了幾個表格;只要查詢並代入相應的數據,即可計算出傷害/治療數值以及類型;特殊效果可以用存儲在資料庫中的LUA代碼補充完成。
最終的設計效果就好像內嵌了一個解釋器,這個解釋器會根據法術ID解釋執行資料庫內部的相關內容。
至此,暴雪就完成了整個游戲中各種技能的資料庫化,以至於給一個角色/物品添加/刪除一個/一些技能都易如反掌。
想想看,假如讓那些面向對象原教旨主義者來設計,會出現什麼情況:
定義一個基類叫技能;然後一個繼承類叫法術技能,另一個叫物理技能;然後神聖法術從法術技能繼承,疾病法術也從法術技能繼承;由於聖騎士一個技能同時具備物理和法術兩種效果,於是必須多重繼承神聖法術和物理技能;多重繼承太危險,於是不得不把神聖法術搞成介面類,引入介面繼承甚至帶實現的純虛函數等等高端概念;然後,活該槍斃的暴雪設計師又想出了讓某個技能同時對目標加上神聖持續傷害效果——於是不得不再加個繼承層次,使得神聖法術是神聖持續傷害法術的子集:僅立刻造成一次持續傷害的DOT(damage of time)技能……
那麼,點一個天賦,一個技能就會有dot,否則就沒有怎麼辦?
設計模式是靈丹妙藥,不是嗎 ^_^
等到把這所有幾千個技能全部搞定,起碼也是一個數萬個類、幾十層的恐怖繼承樹,並且會用完23個設計模式(甚至再發明幾個新模式出來,我也不會感到奇怪),精巧複雜到沒有任何人願意去碰它。
但,請註意,天殺的暴雪設計師,在最開始的設計方案里規定DOT不能暴擊;後來又添加約定說某某某職業的某個dot可以暴擊;另一個職業的某個dot在點天賦後可暴擊;至於死亡騎士,在他穿了T9套裝中的其中四件裝備時,他的某個瘟疫類型的dot可以暴擊——但另一個瘟疫dot永遠不能暴擊。
嗯嗯嗯,太好解決了——這不就是策略模式嗎?
好吧,你再填幾十幾百個類體系,然後把舊的幾十層繼承樹中的數萬個類一個個都策略化吧。反正不是我在維護……
哎呀不好,那個槍斃了幾百次都還沒死的暴雪設計師又出餿主意了,他要求:當死亡騎士點了邪惡系的某個天賦時,不光給他增加一個新的dot、並且在這個新dot的存在期間,還要保護他的兩個dot性疾病和1個debuf性疾病不被驅散!
繼續補充:在WLK裡面,那個腦袋都被子彈打成篩子了的暴雪設計師又跳出來了,用他滿是漏洞的腦子出了個該殺的主意:他要求添載入具概念,當玩家坐上傳具時,臨時刪除他的所有技能,替換為載具的技能;或者當他坐在特定載具的特定位置時,防止他受到任何傷害、並且允許他釋放自己的所有技能!
更該死的是,他要求,一些技能本來不允許在移動中施放;但現在,當玩家坐在載具上某個位置時,要臨時允許他移動施法!
還有,為了平衡某個野外戰場,他還要求,在某方人數較少時,臨時根據提高他們的生命值和所有技能的攻擊力和治療能力——這個改變必鬚根據進入戰場的人數實時進行;在一方連續在某個戰場失敗時,同樣要給他們一定補償!
嗯嗯,看看這些刁鑽需求吧,如果沒有面向對象,沒有以策略模式為首的28個設計模式(我有理由相信你們需要至少28個設計模式而不是23個)的英明領導,我們這些沒接觸過大項目、不懂面向對象的傻B們,就是哭的拿眼淚把長城溶解掉都沒辦法吧?——我當然知道搭建長城的材料極難溶與水。
可憐的瞎子,你們的魚湯很鮮吧?