在游戏开发中有用的编程设计模式有哪些?[关闭]


129

我有几本关于“设计模式”的书,并且阅读了一些文章,但是无法直观地指出哪种编程设计模式对游戏开发有用。

例如,我有一本名为《 ActionScript 3》(带有设计模式)的书,其中详细介绍了几种设计模式,例如“模型视图控制器”,“单例”,“工厂”,“命令”等。

作为对此不熟悉的人,我无法弄清楚其中哪一个有用,或者实际上,如果其中任何一个是我应该学习并尝试使用的设计模式。也许还有我什至不知道的其他针对游戏编程的设计模式?

如果您有在游戏开发中使用某种设计模式的经验,我很想听听。如果有理由说明使用它的原因,代码示例或在线资源也将非常有帮助。目前,我对ActionScript 3和C ++实现最感兴趣,但是一定可以从任何语言的经验和示例中受益。

谢谢!


“也许还有我什至不知道的其他针对游戏程序的设计模式?” -不,这些模式是通用的,它们更多地用于扩展您所使用语言的功能。它们与您的申请主题无关。
Kylotan's

3
@Kylotan从我有限的角度来看,由于每种设计模式都旨在以有效的方式解决特定的问题,因此从本质上讲,在给定特定问题集的情况下,某些设计模式会比其他设计模式有用,也就是说,在这种情况下,这些问题是游戏开发所特有的。当然有一些准则,或者根据您的经验,您发现自己比其他人更频繁地使用某些设计模式?
jcurrie33

任何人都熄灭,并学会1000种不同的设计模式之前,请仔细阅读
BlueRaja -丹尼Pflughoeft

@ BlueRaja-DannyPflughoeft Secon链接无效。您能重新发送吗
Emadpres 2015年

Answers:


163

现在给出一些不太建议的回应。不要将这些作为实施建议,更多地作为可能使用的示例。

  • 构建器:基于数据一次将一个组件的基于组件的实体设置为一个
  • 工厂方法:基于从文件中读取的字符串创建NPC或GUI小部件
  • 原型:存储一个具有初始属性的通用“ Elf”字符,并通过克隆来创建Elf实例。
  • 辛格尔顿(Singleton):这个空间故意留为空白。
  • 适配器:通过将其包装在看起来像您现有代码的层中来合并可选的第三方库。对于DLL非常有用。
  • 合成:制作可渲染对象的场景图,或使用小部件树制作GUI
  • 外观:通过提供更简单的界面来简化以后的生活,从而简化了复杂的第三方库。
  • Flyweight:以几乎透明的方式将NPC的共享方面(例如模型,纹理,动画)与各个方面(例如位置,健康状况)分开存储
  • 代理:在客户端上创建代表服务器上更大,更复杂的类的小类,并通过网络转发请求。
  • 责任链:将输入作为处理程序链进行处理,例如。全局键(例如,用于屏幕截图),然后是GUI(例如,在文本框被聚焦或菜单打开的情况下),然后是游戏(例如,用于移动角色)
  • 命令:将游戏功能封装为命令,可以将其键入控制台,进行存储和重播,甚至编写脚本来帮助测试游戏
  • 中介程序:将游戏实体实现为在不同组件上运行的小型中介程序类(例如,从运行状况组件读取以将数据传递给AI组件)
  • 观察者:让角色的可渲染表示侦听逻辑表示中的事件,以便在必要时更改视觉表示,而游戏逻辑无需了解任何有关渲染代码的知识
  • 状态:将NPC AI存储为多个状态之一,例如。进攻,徘徊,逃跑。每个人都可以拥有自己的update()方法以及所需的其他任何数据(例如,存储正在攻击或逃离哪个角色,在其徘徊的区域等)
  • 策略:根据您所处的地形,在不同的启发式搜索之间进行切换,或者甚至使用相同的A *框架进行寻路和更通用的规划
  • 模板方法:建立通用的“战斗”例程,并具有各种钩子函数来处理每个步骤,例如。减少弹药,计算命中几率,解决命中或未命中,计算伤害,每种攻击技能将以自己的特定方式实施这些方法

由于缺乏灵感而遗漏了一些模式。


有关单例的非常启发性的讨论可以在这里找到:misko.hevery.com/2008/08/25/root-cause-of-singletons
Andrew Wang 2010年

+1为策略模式。我已将其用于上述确切目的(插入了不同的A *启发式方法)。
Mike Strobel 2010年

1
感谢您的回答,这些声音比起我到处都听到的通常的“
单音

大量示例。尽管单例模式(变相全局状态)的慢性虐待,有合法的用途:当它代表一个资源,其中,你其实只(或希望)之一。这可能类似于包装硬件(例如键盘/鼠标)或包装非可重入的库(这种情况会发生,并且并非所有语言都具有神奇的同步关键字)。
charstar 2011年

11
我仍然不会使用单例来获取硬件资源-您认为以后只会增加1个的项往往会越来越多,就像视频卡和显示器随着时间的流逝所做的那样。同样,在某些API下,您需要阅读2个操纵杆才能理解1个游戏手柄。因此,我想说的是,如果您只需要某种东西,只需实例化一个,就不要实施可能不必要的任意限制。
Kylotan

59

我写了关于该主题的书:游戏编程模式。那里的章节可能对您有所帮助。


2
+1我希望有人链接到该链接,我看到作者链接了!那里的组件模式描述非常有帮助,我喜欢您尝试使用完整的代码示例进行演示。
CodexArcanum 2010年

2
是的-我记得几年前读过您的链接。您应该完成这些文章!
onedayitwillmake 2011年

2
现在这本书完成了:)
dusan 2014年

1
很棒的资源帮助我将现有的编程知识转化为游戏编程。感谢您编写!

对游戏编程模式的这种解释实际上以一种软件设计模式书没有真正做到的方式帮助我理解了“设计模式”!这部分是游戏开发的力量(用一种能与我交谈的语言编写的具体示例,可以使我总体上更好地发展自己的游戏),但是在很大程度上,这是因为写作是如此出色。
Kzqai

19

布兰登·艾希(Brandon Eich)在“ 编码员的工作”中提出的一个很好的想法是,模式是黑客和变通办法:[模式]显示语言的某种缺陷。这些模式不是免费的。没有免费的午餐。因此,我们应该寻找能添加正确位的语言来发展。

作为游戏程序员而不是编译器设计师,我们很少有选择来发展我们使用的语言的选择,但是我们可以学习发展自己的风格以更好地适应我们的语言和要求。模式是其中的一部分,但是不使用模式是另一部分,尤其是因为正如Brandon所说,模式很少会在没有明显的性能,内存或代码敏捷性成本的情况下消失。MVC并不是游戏中很多事情的好模式。Singleton是la脚的C ++静态初始化规则的解决方法,您可能无论如何都不应该这样做。Factory简化了复杂的对象创建-也许您的对象从一开始就应该更简单。流行模式是我们需要时可以使用的工具 要管理复杂的东西,而不是工具,我们一开始就应该使用它们来构建复杂的东西。

好的(游戏)代码可能会使用模式,也可能不会。如果确实使用模式,那么很好-它们是一种很好的交流工具,可以在不依赖语言的高度向其他程序员解释代码结构。如果您认为不使用模式就更好的代码,请不要为它而烦恼-可能会。


4
是的,在原始书中明确指出的一件事(但经常被忽略)是,如果它是为C而不是C ++ / Smalltalk编写的,则它们可能已经包含了“继承”模式,并且出于同样的原因,有些语言可能包含一些已经内置GoF的模式。
Kylotan

13
在原书经常被忽略的另一件事情(原原书的亚历山大,不四人帮)是模式是一个工具沟通,而不是执行。它们使设计人员可以在更高层次上交流实现,并且因为它们是重复出现的而被识别,而不一定是因为应尽可能使用它们。

1
但是,仅具有术语可以帮助您对问题进行推理,并识别何时该方法是一种好的解决方案。最好的模式通常是由熟练和有经验的工人随着时间的流逝而完善的,而没有这些经过整理的示例,技术水平较低的工人自己不会发现相同的模式。
Kylotan's

我同意拥有很好的术语,并且模式定义的部分原因在于它是针对某些问题的很好的重复解决方案。不幸的是,技术欠佳的工人往往会发现主要是Singleton,并将其应用于每个问题,即使尚未出现问题。

感谢您的回复;读完设计模式即可解决软件设计所产生的问题,我感到很轻松。我认为整个大型软件的结构应该从头到尾全面考虑,然后再开始编写任何代码。您不能总是一次实现一次功能,有时您必须考虑每个特定功能,并检查它是否不会与软件的全局结构混淆,或者只是妨碍软件如何适应表现。将任务分配给几个程序员有时可能会产生矛盾……
jokoon

7

当然,正如其他人所说,所有模式在正确的情况下都是有用的,学习如何使用它们的一部分就是学习何时使用它们。但是,Daniel Sanchez-Crespo Dalmau 撰写的出色的《游戏编程中核心技术和算法》一书列出了六个编程模式和六个可用性模式,这些模式在游戏编程中特别有用。

程式设计:

  • 辛格尔顿:我不像很多人那样讨厌这个人。它可用于单人播放器或键盘阅读器之类的东西。
  • 工厂:使您可以有效地创建和销毁对象。
  • 策略:让您优雅地更改AI策略。
  • 空间索引:帮助对空间数据集执行查询。
  • 复合:设置有用的对象层次结构。
  • Flyweight:通过泛化诸如相同敌人之类的东西来释放记忆。

可用性:

  • 盾牌:防止意外激活戏剧性动作。
  • 状态:世界/ UI状态的视觉提示。
  • 自动模式取消:使游戏更加直观。
  • 磁性:自动定位,单位选择简单。
  • 重点:消除分散注意力的UI元素。
  • 进度:普遍有用。

当然,这本书会详细介绍这些内容。


感谢您的输入!我不知道那本书,但是由于您的帖子,现在将对其进行研究。再次感谢!
jcurrie33 2010年

2
键盘阅读器的Singleton正是我要问的情况-您真的可以不只是在主要功能的早期将其设置为全局指针吗?您是否曾经意外地实例化了两个键盘阅读器?

请不要讨厌单身人士。它做两件事很差。全球访问和团结。开发人员经常认为全局访问==单例。有一个非常比几个问题需要一个真正的单身人士,并可能多了一些当用单解决是更优雅。
deft_code 2010年

7

实体系统是一种很好的模式。这不是完全正确的设计模式,因为它不是严格的OOP。但是,您可以将其与OOP混合使用。

一些好的链接(从顶部开始介绍):


3
“这不是完全正确的设计模式,因为它不是很严格的OOP。” 设计模式与OOP无关。如果有的话,OOP本身就是一种设计模式。设计模式不仅出现在OOP之外,而且完全出现在软件开发之外。

OOP design patterns通常显示类/对象之间的关系和相互作用。还有许多其他设计模式。OOP是一组概念,而不是一种模式。Design pattern也是一个概念
topright 2010年

6
不用谈论语义,您不应该对我给出的响应的有用性进行评分吗?
2010年

6

他们全部。除了辛格尔顿。[/轻浮]


您能否说出您在游戏开发中经常使用的一种或两种设计模式,出于什么原因?作为设计模式的初学者,“所有模式”并不是特别有用的响应。不过,谢谢您的回应。
jcurrie33

5
问“您使用了什么模式?” 就像问“您使用了什么变量名?” 它归结为个人风格,要求和领域。在某个时候,您可能会使用曾经命名的任何模式。您可能会使用更多尚未命名的名称,甚至可能发明一些新名称。

@ jcurrie33:对不起,我只是忍不住先挖了单身人士。;)
Kylotan 2010年

6

不是真正关于模式,而是关于它们背后的基本原理。在“设计模式:可重用的面向对象软件的元素”(1995年)中,由四人组成的小组(Gamma,Erich,Richard Helm,Ralph Johnson和John Vlissides)仅建议了两个面向对象设计的原则:(1)编程接口而不是实现,并且(2)主张对象组成胜于类继承。

这两个原则在游戏开发的许多任务中非常有帮助。例如,许多游戏程序员已经使用了深层次的类层次结构来表示游戏实体。还有一种基于合成的方法 -基于组件的游戏对象。文章介绍了这种方法。甚至更多的链接。这是一个装饰器模式的例子。


游戏设计中使用的组件更像是有状态策略模式-自然地表示为C / C ++ / Java / C#外部的闭包以及内部的组件对象。装饰器模式更像是代理。它的所有权和数据流与我们在谈论游戏中的组件系统时通常所说的相反。

组件还需要彼此对话,引入诸如Mediator,Observer和Composer之类的模式。“基于组件的游戏”本身就是一种复合设计模式。
CodexArcanum 2010年

@CodexArcanum,观察员,明确但并非总是调解员(可以使用责任链代替)。仅当GameObject(由GameObjectComponent组成)是GameObjectComponent本身(非必需)时才是Composer。
topright 2010年

6

奇异递归模板模式可避免虚方法和性能损失可能来自虚函数的调用非常有用。

当您实际上不需要具有要使用的接口的基类类型的容器,但是您希望具有类似命名的行为和接口时,这可能是适当的模式。

例如,在为多个平台或引擎(dx vs. opengl)编译类时,可以在编译时知道类型差异的情况下使用此方法。


我一直讨厌os抽象层是虚拟的。并不是说您将永远不需要两个操作系统抽象层。使用CRTP更好。
deft_code 2010年

也许我才刚老,但我什至不会为CR / DX / OpenGL或平台接口使用CRTP。编译太慢-我只用typedef。当您想在类之间共享接口和实现但没有其他关系时,CRTP非常有用,而不是只希望选择一个结构或另一个结构时。

4

经过多年的发展,对我来说非常有用的设计模式被我称为“经纪人定义集”。如何用GOF术语来概括它似乎是有争议的,但是我在StackOverflow上写的有关此问题的详细信息。

核心概念是建立模型的某些属性(例如生物的种类),以便该属性的每个可能值都有一个对应的定义对象(每个值一个共享的对象),用于指定其行为,并且可以通过中央代理(在GOF方面可以是注册中心,工厂或两者)访问这些代理。在我的用法中,通常也可以通过标量键访问它们,以促进用于运行时态射影的弱绑定。


我根本看不到这是一个单例,在讨论轻量级模式时,“注册表”一词是多余的。这只是举重。

我从SO线程的理解是,由于将定义设置为类,因此人们将Singleton视为其中的一部分。就Registry而言,我看不出它可以与Factory替换或组合时如何成为冗余。
混乱

-1,在某种程度上,模式是关于快速沟通的,这可能是我所见过的最大的失败。我真的不能认真对待这个描述。

耶稣,请原谅我没有为您做足够的饼干。您是否也将否决“实体系统”答案,因为它不能立即用GOF术语概括?
混乱

1
某种程度的“曲奇切割器”(或者至少在语义上清晰),正是必须使用哪些模式。众所周知,“ flyweight”和“ singleton”等术语相互排斥。第一个是在多个实例之间自动共享数据。第二个是关于只有一个实例。我并不是说您的设计选择是没有用的甚至是不好的,但是将“足够接近”的模式名称拼凑在一起只会使每个人更加困惑。(请不要亲自
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.