看了《游戏设计模式》后觉得受益匪浅,写一点笔记与关于自制游戏引擎的构想
《游戏设计模式》英文版原名,Game Programming Patterns
Web版阅读地址(中文):https://gpp.tkchu.me/
(英文)http://gameprogrammingpatterns.com/contents.html
1.常用GOF设计模式
1.1 命令模式(Command Pattern)
定义:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化; 对请求排队或记录请求日志,以及支持可撤销的操作。
游戏引擎中的运用:将命令数据化,就是封装为对象,这样命令可以放入队列或者栈中,可以简单重复,撤消,再利用等。比如在输入模块上使用命令模式,可以实现重放,撤消等操作。
1.2 享元模式(Flyweight Pattern)
定义:以共享的方式通过利用已存在的实例,降低系统的性能消耗
游戏引擎中的运用:各种资源(3d模型,声音,图片等)使用享元模式,使用同种资源的实例中,其资源都是同一份。
1.3观察者模式(Observer Pattern)
定义:行为和对象的解耦,也就是对象的行为产生一个事件,由事件来控制其行为。
游戏引擎中的运用:很广泛,但是下文中的事件队列模式对游戏引擎来说更加合适,具体原因后述。
1.4原型模式(Prototype Pattern)
定义:通过对象的封装建立原型,然后通过拷贝原型来实例化游戏对象,
游戏引擎中的运用:几乎都存在,比如先将角色必要的建模,矩阵,AI等封装到一个类中,然后通过类来直接实例化对象。
1.5 单例模式(Singleton Pattern)
定义:一个类中只有一个实例
游戏引擎中的运用:单例实质就是全局变量,全局变量的缺点自不必说,主要是在多线程下或者团队开发中,部分类必须只能存在一个,通过单例模式可以保证访问的对象都是同一个。通常来说场景管理,游戏管理,日志和资源管理系统会采用单例模式
1.6 状态模式(State)
定义:根据状态决定行为,通过状态的迁移来管理类的功能
游戏引擎中的运用:非常广泛,有限状态机(FSM)几乎在游戏开发中无处不在。
2. 序列模式
2.1 双缓冲(Double Buffer)
定义:通过双缓冲来保证同一桢内的一致性
游戏引擎中的运用:序列模式中的设计模式基本上是实时(Runtime)游戏引擎的必不可少的部分,例如常见的底层API的渲染就是采用双缓冲模式,在背面缓存上完成了每桢的绘制后再转到前缓存上表现出来
2.2 游戏循环 (Game Loop)
定义:通过时间间隔来循环游戏的处理部分
游戏引擎中的运用:同样基本是必用
2.3 更新方法(Update Method)
定义:在每个更新周期内通过每次更新一点点来模拟游戏
游戏引擎中的运用:同样基本是必用,基本上通过游戏循环来更新
3. 行为模式
3.1 字节码(Bytecode)
3.2 子类沙箱(Subclass Sandbox)
3.3 类型对象(Type Object)
行为模式中的方法几乎贯穿整个游戏引擎中,字节码用于脚本处理,
子类沙箱则是常见的面向对象思想中基类>子类的继承与多态实现
类型对象模式则是通过类型区别对象,类型对象模式的运用就是上文的享元模式、原型模式等。
4. 解耦模式
4.1 组件(Component)
定义:功能的模块化,将类解耦并保证其原来特性
游戏引擎中的运用:Unity的ECS架构(实体-组件-系统)就是组件模式的一种实现,传统的继承法对于需要团队开发的游戏来过于臃肿,而组件模式在自由度上和团队开发上都更加方便。
4.2 事件队列(Event Queue)
定义:类与类之间通过消息来传递信息,通过消息的发送和处理进行时间上的解耦
游戏引擎中的运用:事件队列可以说是观察者模式的异步实现法,在游戏引擎中被广泛运用,WindosAPI的消息机制就是源于此,命令模式,观察者模式和事件队列都解耦了发送者和接收者,而事件队列还在此之上解耦了时间。
4.3 服务定位器(Service Locator)
定义:可以说是更加复杂的单例模式,在运用时获取对象而不是运行前赋值。
游戏引擎中的运用:Unity的GetComponent(),就是采用此方法。本方法目前还有不明的地方之后再补。
5. 优化模式
5.1 数据局部性(Data Locality)
对CPU缓存的一种优化方法,使用连续的数组来加强CPU的命中
5.2 脏标识(Dirty Flag)
通过标记数据是否被更改过来决定是否执行,脏标识本身会增加代码复杂度,通常只有在当前任务具有昂贵的开销时才会采用此方法。
5.3 对象池(Object Pool)
放弃单独释放和分配内存,而是通过调用已存在池中的对象来节省性能消耗
5.4 空间区分(Spatial Partition)
通过空间的区分来定位对象,从而减少计算量
自己基于Directx,制作过一个小型的Runtime游戏引擎,其中UI和粒子采用了库,其他部分完全自己实现,而在目前阅读了后《游戏设计模式》后,打算今后对引擎进行以下更新:
- 基于组件和事件队列模式重构引擎(目前是继承式)
- 游戏引擎使用Lua脚本来完成部分处理
- 优化上达成对象池,数据局部性,空间区分。