【游戏编程扯淡精粹】游戏编程设计模式
【游戲編程扯淡精粹】游戲編程設(shè)計模式
本文最初寫于2018/9/4
毛星云 RIP
如何練習(xí)設(shè)計模式
- 基本盤:長期維護(hù)一個大型工程,持續(xù)積累
- 維護(hù)一個設(shè)計模式表格,日常查找使用
- 多學(xué)幾門編程語言和編程范式,看不同的語言如何更好地解決問題
- 開發(fā)DSL和框架/架構(gòu)在高維度解決問題,直接干掉設(shè)計模式,減少業(yè)務(wù)邏輯層的代碼量
所以我們只能通過復(fù)雜的程序來學(xué)習(xí)設(shè)計模式。
你不管看別人的程序也好,自己寫程序練習(xí)也好,那必須要復(fù)雜,復(fù)雜到你不用設(shè)計模式就做不下去,這才能起到學(xué)習(xí)設(shè)計模式的作用。
維護(hù)一個表格
- 設(shè)計模式名稱
- 適用情形/案例
- 代碼示例
- 詳細(xì)描述
實際使用的時候,是從當(dāng)前情景匹配適用情形去找到適合的設(shè)計模式
資源鏈接
【游戲設(shè)計模式】之四 《游戲編程模式》全書內(nèi)容提煉總結(jié) - 知乎
miloyip/graphvizuml: 使用 Graphviz 繪畫 UML 圖
并發(fā)設(shè)計模式
Active object - Wikipedia
Balking pattern - Wikipedia
Guarded suspension - Wikipedia
Reactor pattern - Wikipedia
編程語言和設(shè)計模式
Design Patterns in Dynamic Languages // Python
Channel (programming) - Wikipedia // GO
Hygienic macro - Wikipedia // Scheme
設(shè)計模式問答
工廠模式(factory Method)的本質(zhì)是什么?為什么引入工廠模式? - 知乎
工廠就是封裝復(fù)雜創(chuàng)建流程,非必要不要濫用設(shè)計模式,短平快實現(xiàn)需求
UML
UML方案
我選擇的三種UML方案:
- Graphviz
- draw.io
- Microsoft Viso
Graphviz的方案比較輕量,適合程序員,可以用Git進(jìn)行版本管理,但是有學(xué)習(xí)門檻
常見UML
| 類圖 | 類OOP設(shè)計 |
| 順序圖 | 時序,前后端交互 |
| 狀態(tài)圖 | 狀態(tài)機 |
| 活動圖 | 多線程fork/join流程 |
我個人最常用的是順序圖和狀態(tài)圖,比源碼和文字描述的表現(xiàn)力更強
經(jīng)典設(shè)計模式
經(jīng)典設(shè)計模式主要適用于C++,C#語言的OOP編程范式
設(shè)計模式的目標(biāo)
目標(biāo)是得到高擴展性的代碼
在應(yīng)對頻繁需求變更和迭代的過程中能夠:
- 快速實現(xiàn)新需求
- 容易理解,容易調(diào)試
- 擴展代碼,而不是修改代碼
設(shè)計模式的原則
- 面向接口
- 接口細(xì)粒度,調(diào)用功能是面向接口的
- 單一職責(zé)
- 避免繼承一個類
組件模式 & 橋接模式
參考:
- Unity的MonoBehaviour和Component
- Ogre的OgreRoot和Plugin
橋接模式將抽象類和抽象類的組件進(jìn)行分離。從而達(dá)到抽象類和抽象類中的組件可以獨立的變化。
適配器模式
參考:
- 生活中的轉(zhuǎn)接口
- 將list封裝為stack
適用情形,兩頭的代碼已經(jīng)都別人寫好了,我來對接時,寫一個適配器進(jìn)行轉(zhuǎn)接
適配器模式的作用是將一個類的接口轉(zhuǎn)換成客戶所需要的接口。適配器器模式分為類適配器和對象適配器。
類適配器
采用多繼承的方式,將目標(biāo)接口和要適配的類進(jìn)行集成。調(diào)用的時候,采用多態(tài)的機制,調(diào)用要適配的類實現(xiàn)即可。
對象適配器
對象適配的核心思想是客戶端需要調(diào)用某種方法,而Adaptee沒有該方法,為了使客戶端能夠使用Adaptee類,需
要提供一個包裝(Wrapper)類Adapter。對象適配器與類適配器不同的地方是,適配器和被適配者不是繼承的關(guān)
系,而是組合的關(guān)系。
命令模式 & 解釋器模式
參考:
- Lua的vmloop
- Unity的Coroutine機制
可以將Coroutine機制封裝一下,把一個命令包裝成一個Coroutine,再把Coroutine串聯(lián)在一起
命令模式是將一個請求封裝為一個對象,從而使你可用不同的請求對造成不同的行為結(jié)果。
工廠模式
主要是因為ctor是特殊函數(shù),不支持虛函數(shù)
所以包裝成工廠函數(shù),就可以使用一般的多態(tài)機制,更加靈活
簡單工廠模式
一個工廠生產(chǎn)多種產(chǎn)品,告訴產(chǎn)品的類型,工廠就會生產(chǎn)對應(yīng)的產(chǎn)品。如果新增產(chǎn)品的種類,那么需要更改工廠的源代碼。
class Factory { public:Product* createProduct(productType type) {switch (type) {case TypeA:return new ProductA();case TypeB:return new ProductB();case TypeC:return new ProductC();default:return nullptr;}} };工廠方法模式
工廠方法模式的核心思想是:建立一個工廠基類。當(dāng)我們想生產(chǎn)一種產(chǎn)品的時候,我們繼承工廠基類,派生出生產(chǎn)
對應(yīng)產(chǎn)品的派生類。使用派生出的工廠生產(chǎn)對應(yīng)的產(chǎn)品。
抽象工廠模式
抽象工廠模式允許生產(chǎn)不同種類的產(chǎn)品。從而有應(yīng)對了工廠模式只能生產(chǎn)單一種類產(chǎn)品的問題。
建造者模式
當(dāng)需求的特點是流程的步驟類型相同(有一條步驟類型明確的流水線),但是步驟的具體卻是不一樣的。每種工人,在實現(xiàn)某一步驟是不一樣的。指揮者調(diào)用建造者,來通過每種步驟的不一樣,來表現(xiàn)出不同的產(chǎn)品。
案例:
- Ogre的Resource類
代理模式
代理(Proxy)這個詞在具體領(lǐng)域,比如網(wǎng)絡(luò),可能有非常多的概念
生活中的中介可以看作代理,中介會幫你完成你本身完成不了的工作
你只需要與中介對接,向中介提出請求,中介去執(zhí)行,并將結(jié)果返回給你,你不需要知道中介是怎么做的
編程中,可以看作是Client-Server模型,Proxy Server做了一個抽象隔離,讓Client使用簡單的接口完成復(fù)雜的任務(wù)
為其他對象提供一種代理以控制對這個對象的訪問。這樣實現(xiàn)了接口和實現(xiàn)的分離。
原型模式
案例:
- RPG游戲的怪物類型機制
本質(zhì)是數(shù)據(jù)驅(qū)動地去構(gòu)造一個類型
一般的RPG需要制作大量的換皮怪來應(yīng)對玩家的等級和裝備成長
可以通過功能模塊的組合來拼裝出一個新的怪物類型,不需要編寫代碼
核心思想是通過使用拷貝構(gòu)造函數(shù),來對自身進(jìn)行拷貝,生成一個新的對象,來進(jìn)行對象的創(chuàng)建。
裝飾器模式
參考:
- Python的裝飾器
裝飾模式能夠?qū)崿F(xiàn)動態(tài)的為對象添加功能,是從一個對象外部來給對象添加功能。在不必改變原類文件和使用繼承
的情況下,動態(tài)地擴展一個對象的功能。
單例模式
參考:
- Ogre的OgreSingleton
責(zé)任鏈模式
一種fallback處理機制
案例:
- 查找路徑,比如lua require查找模塊機制
- 游戲事件處理責(zé)任鏈,遍歷事件處理器,直到事件被處理
組合模式
案例:
- 文件系統(tǒng)的文件樹
文件和目錄都繼承自節(jié)點
刪除文件就是刪除節(jié)點,刪除目錄是刪除子樹
外觀模式
就是包裝類
比如游戲引擎對圖形接口和物理引擎都會重新包裝一遍,因為原始的接口集合太復(fù)雜太難用了
享元模式
案例:對象緩存或者對象池
就是復(fù)用內(nèi)存和對象
享元模式是為了應(yīng)對大量細(xì)粒度對象重復(fù)的問題。程序中存在大量細(xì)粒度的對象,每次要使用時都必須創(chuàng)建一個新的對象,既影響了運行效率又增加了內(nèi)存消耗。享元模式和對象池的區(qū)別,享元模式的享元池存儲的是種類,一個種類只有一個實例,所有對象共享這一個實例。而對象池中可能存再多個實例。
策略模式
從多個alternative中選擇一個
策略模式定義了一系列的算法,并將每一個算法封裝起來,而且使它們還可以相互替換。策略模式讓算法的變化不
會影響到使用算法的客戶。
迭代器模式
C++/C#自帶,這已經(jīng)不是設(shè)計模式了
游戲設(shè)計模式
沙箱模式
原始的沙箱模式?jīng)]有實踐意義
沙箱這個概念需要了解:
- 腳本執(zhí)行網(wǎng)絡(luò)代碼需要沙箱隔離,參考Lua沙箱
- 引擎開發(fā)過程中,分離出引擎層,提供一個沙箱環(huán)境用來編寫Demo
這個沙箱機制ZeloEngine已經(jīng)實現(xiàn),Demo全部在Lua腳本沙箱中編寫運行,可以動態(tài)切換,開發(fā)Demo不會導(dǎo)致頻繁編譯引擎
【ZeloEngine】沙箱機制_游戲編程扯淡精粹-CSDN博客
臟標(biāo)記模式
案例分析:
- UI臟矩形優(yōu)化
- UI界面View沒有更新,就不需要重新計算View
- transform樹更新計算臟標(biāo)記優(yōu)化
- transform節(jié)點更新只影響節(jié)點的子樹,不影響其他節(jié)點不需要更新
transform樹的臟標(biāo)記更新ZeloEngine已經(jīng)實現(xiàn)
需要框架,內(nèi)容太多,建議單獨查
事件隊列
參考:
- 饑荒的StateGraph和EntityScript
其他設(shè)計模式
控制反轉(zhuǎn) & 依賴注入
典型案例是Java Spring框架
我并不了解Spring,這里只作為案例
控制反轉(zhuǎn)+依賴注入,可以理解為一種基于配置和類反射的工廠模式
下面是一個Spring的配置文件,spellChecker被注入textEditor的屬性中,運行時會解析xml,去構(gòu)造對象
偽代碼:textureEditor.spellChecker = new me.leehao.SpellChecker(...)
spellChecker是一個接口,具體是什么類由xml配置來選擇,這就是依賴注入
這么做的好處是:
MVVM
參考:
- WPF
Combinator
WIP
總結(jié)
以上是生活随笔為你收集整理的【游戏编程扯淡精粹】游戏编程设计模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: gpio_desc()的分析
- 下一篇: 老版本微信平台服务器部署步骤(没那么坑版