怎麼理解遊戲開發中的「Data-Driven Design」?

數據驅動設計又有哪些表現形式呢?是不是經常和組件-實體系統搭配呢?


ECS是遊戲開發中最典型的數據驅動,我先舉一個最簡單的最實在的例子:

我有一個TimeExpiredSystem,他關心所有帶有TimeExpireData這個component的entities(至於這些entity還帶有什麼其他的component,這個跟我TimeExpiredSystem沒有半毛錢關係,所以你究竟還有多少個其他component,他們是什麼component都行,我只關心你有沒有TimeExpiredData這個Component,有你這個entity就會被我抓住,否則當我沒看見),TimeExpiredData中只有一個屬性(或者更通俗的叫數值)expireTime,他就是過期時間。TimeExpiredSystem中的邏輯偽代碼:

var now = Date.Now();

for (var entity in Entities) do

if (entity.TimeExpireData.expireTime &<= now) then

entity.dispose();

end

end

當你把這個TimeExpiredSystem添加到你的工程中去,然後給對應的entity加上TimeExpireData這個component之後,這些對應的entity都是會過期的(到時間會被銷毀),你可以給一個任務添加這個,任務到時候就自動銷毀了;你可以給活動添加這個,那麼活動到時間就銷毀了;你也可以給一件裝備添加這個,那麼裝備到時間就銷毀了。這個才是標準的數據驅動模式,他與策劃配置表等(或者更確切的應該叫做「數值驅動」模式)完全不是一個概念級的東西,策劃配的表無非是一些數據源而已,不論你怎麼設計的程序,只要你有無法用演算法獲得的數值(我覺得這裡叫「數值」比「數據」更不容易導致混淆)就可以讓策劃配表(配表也好,用腳本也好,用什麼方式無非是為了得到一些數值),這跟Data-Driven基本不沾邊。

數據驅動模式(ECS)和傳統的OOP模式是有絕對不同的!OOPer喜歡把ECS的思路往OOP上硬套,但實際上骨子裡的區別在於:

OOP:我是什麼。

ECS:我有什麼。

只有一個字的差距,但天壤之別。如果一定要用教科書級別的說法的話,這叫做「組合優於繼承」,詳細可以參考這個wiki:Composition over inheritance。


這麼想像:假如說你要做一款遊戲,首先你有一個遊戲引擎(不管是自己寫的還是買買買的),然後你準備好數據、模型、貼圖、聲音等等各種資源。一種方法是我們寫代碼去調用各種資源,組合在一起(當然少不了使用各種中間件來偷懶);還有一種辦法就是寫很少甚至不寫代碼,然後通過各種配置文件,讓遊戲引擎去讀取這些「數據」。

根據個人淺薄理解,後者的好處在於方便復用,譬如設計好的關卡腳本、改改地圖改改怪物,就一個新關卡;或者說策劃有一些新需求之後,可以在原來的基礎上做修改。但是壞處是,這個的工作量會大一些,而且更看引擎的功能強大與否(因為其實你所有需要的東西都必須是引擎已經實現、而且是可以通過「配置」修改的)。前一種方法相當於定製性強一些,而且性能上會好優化一些……如果你把前者所有功能都抽象、封裝好,其實就變成一個支持data driven的東西了

我覺得u3d是一個比較清晰的data-driven的例子,引擎把所有功能都封裝好,然後用戶在編輯器里妥妥拽拽、其實就是用GUI的方式來修改數據;它選擇的GameObject Component這種組件化的架構也非常適合data driven, 每個對象需要什麼功能就掛載什麼組件,通過修改組件的參數來描述這個物體的行為、屬性等~


數據驅動是遊戲開發的常用套路。

  • 最常見的,策劃配資源、配數值,運營配活動。

  • 高級點的,將複雜的邏輯處理配置化、配表化,這樣很容易寫出靈活魯棒的設計。可以用在複雜的流程跳轉、AI設計、公式計算、獎勵判定等。

數據驅動其實很簡單,每個開發者都能掌握,但注意不要濫用。

數據驅動和 Entity Component System 被當成是常見搭配,通過配置 ECS,確實能實現一些像 @錢康來提到的「零代碼」編程,但我認為這其實更接近模塊化設計,數據僅僅是模塊的載體罷了。


怎麼理解遊戲開發中的「Data-Driven Design」?

簡單而言,就是在設計中,把「數據」和其處理過程分離開,

這和設計模式中的封裝變化其實是一樣的,

因為數據實體總是在變化,而同一類數據的處理方式卻是不變的。

數據驅動設計又有哪些表現形式呢?

在遊戲程序中,「數據驅動」包括但不限於:

  • 各種配置表,以上答案都有提到。

  • 各種圖像資源, 比如各種貼圖動畫等。
  • 空間狀態信息,比如Unity3D中,一個對象的位置狀態等等。
  • 遊戲腳本,比如魔獸世界插件。

是不是經常和組件-實體系統搭配呢?

組件-實體系統,

可以說是 腳本集+實體信息,

這二者相加才能稱為一個可供遊戲引擎處理的 數據實體


舉個簡單例子:任務

要實現100個任務,用u3d的設計思想來做就是寫100個組件(官方設計思路,未必實用);但用傳統設計方法,就是一個任務系統支持一些任務類型,任務類型通過數據進行配置。所以簡單的說,數據驅動就是配置驅動。

從語言層次上來說,c#和lua一樣,對於c++來說是一種腳本,前者更容易將數據和邏輯結合的很好,但後者如果這麼結合就是hardcoding了,因此需要將數據部分剝離,變成所謂的數據驅動。

數據驅動其實很好,程序和數據分離,但靈活度肯定沒有腳本開的那麼高


以下都是胡說,我不懂unitiy 不懂c# 也不懂 java~ 數據驅動完全沒聽說過

unity的開發語言是c#,c#是java沒有血緣關係的親兄妹(額 可能C#遺傳了點不錯的基因)

,而數據驅動在java開發里已經是老概念了,後面還有玄幻莫測的領域驅動,也叫ddd,說白了就是面向對象的語言特性在工業生產中的合理轉化,然後再加上點作料

所以呢unity強調數據驅動只是因為語言和java很像而已


近幾年遊戲行業這麼火熱,技術上發展最快的是什麼,引擎。就手游而言,國內一般2d用Cocos2dx,3D用Unity,當然還有自研引擎,Cocosdx是面向對象的思維,而Unity3d是組件思維,二者差別很大,表現在做遊戲的流程上,Cocos2d更新傳統的軟體開發,Unity3d更能突出設計。而開發遊戲過程中,設計才是最重要,設計的很大一部分體現在數據上,這就要求引擎能對數據管理更友好,更方便,Cocos2dx在這方面落後Unity3d太多,個人覺得以後遊戲引擎在數據管理方面往配置化,模塊化發展,也就是DDD了。跑題了


如果給你一套樂高積木,裡面除了那些固定的方塊外,還有許多其他的配件,比如齒輪、傳動軸、輪胎、螺旋槳、傳動帶甚至電動機和開關、燈泡,那麼你就可以光用這些配件,搭建出很不錯的玩具飛機、汽車、甚至是機器人。這些樂高的配件,就是所謂的「組件」,你搭建一個機械玩具所用到的方案,就是「數據」。你可以不去修改這些配件,僅僅是拼裝,就是「數據驅動」編程。

回到編程領域,所謂的組件,一定是要自己本身具備一定功能的,並且和其他組件要有能配合的介面。而這一切,都需要組件本身具備完備的代碼封裝性,所以數據驅動中的組件,本身也是要編碼實現的。然而,我們針對性去做的組件,只能解決某些特定的問題,一定會存在範圍以外的需求,所以我們只能追加開發新類型的組件。所以數據驅動編程本身並不複雜,關鍵是要實現這種活動,背後要對需求領域有深刻理解和模型抽象的能力。能不能做出一套你的業務領域的樂高配件,正是你在業務領域和編程技巧上的能力體現。


github搜索entitas csharp,不理解理論的話就先看看具體實現來理解


推薦閱讀:

類似傳送門的效果怎麼在引擎內實現?如下圖所示,通過一個門可以看到另一個空間?
聚爆的扭曲刀光是怎麼實現的?
為什麼IT行業二本院校找實習這麼難?
怎樣看待越來越多cocos2dx程序員轉unity3d,unity是否是大勢所趨?
Unity 項目中怎樣正確的使用 Lua?

TAG:遊戲開發 | 編程 | 遊戲引擎 | Unity遊戲引擎 | 設計模式 |