您的位置:首页 > 编程语言

应该将游戏玩法与引擎代码分离

2012-10-07 08:55 218 查看
[作者在本文中讨论的话题是“将游戏玩法与代码分离”,使游戏玩法“与引擎无关”,并解释了为什么大家应采用这种方法。]



我曾在三款不同的游戏引擎上开发过游戏,开发出来的游戏都不具备有趣的游戏玩法,而且和引擎在源代码中互相缠结。在Unity引擎中,所有游戏对象都继承自MonoBehaviour,使游戏对象能够充分利用Unity引擎(从而在在游戏和引擎之间形成了一个硬链接。)

最近,我摒弃了这种方法,转而采取更好的“分离关注”方法。我将游戏玩法和引擎彻底分离。到目前为止,我觉得这种方法很好用,因此将来开发大部分游戏我都会采用这种方法。

今天我讨论的话题是将游戏玩法与引擎代码分离,以及为什么我建议其他人作出这样的改变。

为什么?

为什么我希望将游戏玩法与游戏的其他部分分离?以下为几点原因:

不同的游戏,游戏玩法代码差别大。虽然不同游戏的其他系统,如渲染、音效、动画和输入系统等存在很多相似之处(如:《战地3》和《极品飞车16:亡命天涯》使用的是同一个引擎,但它们的游戏玩法却大相径庭)

游戏玩法代码对游戏的其他系统拥有不同程度的所有权。大部分游戏中的代码被分为游戏玩法代码和引擎代码两部分。这两部分需要采用不同的技术组合,这就是为什么它们自身都存在着特殊性。游戏玩法代码开发团队的规模通常和引擎代码开发团队的规模相似。

策划人员专注于游戏玩法,而且他们必须这么做。设计师不应该关心描影或某个输入代码。将游戏玩法代码与其他代码分离简化了策划人员的工作,避免将游戏玩法代码和引擎代码混合在一起。

允许针对游戏玩法代码进行单元测试。由于测试套件是专门针对游戏玩法的,因此维护起来更为简单和容易。

“找到乐趣”是游戏开发所面临的最困难、也是最重要的部分。通过分离游戏玩法代码和引擎代码,开发人员能够完全专注于游戏玩法代码的开发,而无需担心其他与引擎相关的事项。由于处理的代码更少,开发人员在开发过程中能够更快地作出修改以及形成新的点子。

如何做?

我们目前在游戏开发中使用Unity引擎和C#语言。我们将游戏玩法分离出来,放在它自身的数据库(a .dll)中。这个数据库不涉及Unity引擎且和引擎毫无关联。在理论上,我们能够将Unity引擎换成XNA引擎或另外一个能够和a .NET数据库通信的引擎。

这样,游戏引擎将“包含”这个数据库,并将这个数据库用于游戏世界的模拟。在Unity引擎中,这就和把.dll 数据库拖到项目中一样简单,而且你能够访问所有的公共数据。

一种方法是通过接口从游戏引擎访问数据库。这能最好地分离关注,并且彻底地将游戏引擎与游戏玩法分离。

我在开发第一款游戏的时候采用过这种方法,但是后来就再也没有使用过。我强烈推荐大型游戏和团队通过接口完成所有通信。

我已经在一个XNA项目中采用过这项技术,过程非常简单,只需在游戏玩法的.dll数据库中添加一个引用,然后开始对其进行编码。

脚本语言

通常通过脚本语言完成分离。游戏中的某些行为通过像Lua这样的脚本语言展现在游戏策划人员面前。我在许多项目中采用过这种分离方法,而且分离得很成功。我以前有讨论过为什么我认为应将C#语言作为脚本语言。

将游戏玩法分离出来是常规脚本语言分离的一种延伸。我们不是把游戏引擎的某些功能提供给策划人员和游戏玩法程序员,我们是让策划人员和游戏玩法开发人员创建游戏世界,引擎开发人员使用这个世界。

这种方法使两个团队得到了解放,自游戏的基础工作一开始就能够全速地工作。两个团队都设定了自身必须完成的功能,并且能够通过一个简单、明确定义的接口进行通信。策划人员能够专注于有趣游戏玩法的开发,而引擎编码人员能够与美工紧密合作,使游戏的外观和感觉符合他们的想法。

像Unity和Unreal这样的游戏引擎,所有的游戏玩法代码均通过脚本语言(Unreal引擎脚本和C#代码 vs引擎的C/C++代码)实现。然而,我现在讨论的是可以进一步推进这种方法,我们甚至可以在这些脚本语言中创建一个独立于引擎代码的数据库。这样的话,我们在游戏中会有三个区域:

1.游戏玩法特有的代码(如:玩家船只和鱼雷)

2.此款游戏特有的引擎代码(如初步输入然后将输入的内容整理成漂亮的格式传给游戏玩法的特定代码或描影)

3.引擎代码(对于Unity引擎和Unreal引擎,指的是我们通常不会使用的C++代码)

缺陷

我发现,这种方法确实存在一些缺陷。那些游戏引擎和游戏玩法紧密关联的游戏可能会有大量的重复数据。由于游戏玩法代码察觉不到引擎,因此像转换这样的数据结构必须在游戏代码中复制。这增加了内存和进程的使用,因为数据结构转换了。

另外一个缺陷是,游戏引擎的一些有用特色无法应用到游戏玩法中。Unity引擎的两个非常有用的关键特色是触发器和协程(coroutines)。同样的,如果游戏玩法要求使用这些特色,必须复制代码。(想要了解这些问题的解决方法,请阅读下方的未来计划部分)

两个世界

实际上,游戏世界有两个实例。一个是游戏玩法实例,另一个是引擎/渲染实例。对于复杂的游戏,这种分离方法很好,因为这样引擎代码开发人员能将游戏世界存储在他们自己的优化数据结构下。

由于游戏玩法代码和渲染/输入代码之间存在着明显的区别,这种分离同时还简化了游戏引擎多线程的过程。一个大型的项目经过多年的开发之后,我在这个项目上采用了这种分离方法。虽然实施起来很痛苦,但是一旦完成分离,各个团队的速度都得到了大幅提高。

单元测试

我在我的上一个贴子里谈到了单元测试,单元测试是将游戏玩法分离出来的主要好处之一。你可以轻松地对游戏玩法自身进行单元测试,并且还能使用特定的测试套件确保游戏玩法的“正确性”。如果单元测试只是针对游戏玩法,那么测试会更加简单,而且还能获得更高的代码覆盖率。

未来我关注的一个领域是将游戏设计文档转化成一整套针对游戏玩法的单元测试。游戏玩法团队对游戏玩法代码及相关的测试套件拥有完全的所有权。

未来计划

未来我计划对好几个区域进行实验,目前时机还不够成熟。第一个是解决游戏玩法和游戏引擎之间的重复数据的问题。我的想法是,要解决这个问题,就必须将游戏玩法引用到游戏引擎数据结构中适当的地方。

对于Unity3D引擎,可能只需要将UnityEngine.dll数据库包含进去。这样,空间数据结构(Vector3、Quaternion等)就能直接用于游戏玩法。这可能会打破游戏玩法和游戏引擎之间的一些抽象化,但是如果处理得当的话,我认为会增加许多价值。

至于Unity引擎,我将在游戏玩法中创建MonoBehaviour实体,同时还将观察这种方法是否有用,以及它对打破游戏玩法和游戏引擎之间的一些抽象化作用如何.

正如我在单元测试部分所提到的,我将会寻找方法将游戏策划转化为一整套单元测试。我想利用领域特定语言(DSL)进行实验,使游戏策划人员的策划过程尽可能简单。

过去,我已经对流畅的游戏策划进行了实验,这是我感兴趣的另外一个领域。

结论

您对将游戏玩法和其他游戏代码分离有什么看法?您是否已经通过脚本语言实现了这种分离?您是否觉得允许游戏玩法开发人员独***作整个游戏玩法模型以及让引擎代码开发人员通过接口使用世界具有额外的价值?

本文来自: 81813.com游戏潮媒体(www.81813.com) 转载请注明出处:http://n1.81813.com/fenxi/12132011/021051355.shtml
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: