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