硬编码内容为什么不好?


41

我知道大多数游戏都将对话文本存储在文件中,但是我也看到一些基于文本的游戏实际上将内容(地图,选择,可能的玩家命令,故事文本)编程到了游戏代码中。

我可以想到一些原因,但是什至是文字游戏也将所有内容都保留在程序外部的文件中的主要原因是什么?

实现细节之间的区别不大,包括以流行的XML格式保存内容,解析内容,然后根据从XML文件创建的变量渲染地图/显示文本,以及完全放弃XML文件。它们都以输出到屏幕的字符串结尾。区别不只是符号吗?

有些游戏甚至在代码中包含图形(ASCII艺术?)。我知道这是不对的,我可以猜测出它不好的一些原因,但也不知道为什么这是主要原因。

将大多数内容包含在程序外部非常受欢迎。甚至矮人要塞也不使用实际的ASCII字符,而是将ASCII字符的图像加载到内存中。

我主要问这个问题,因为创建,解析和使用XML文件有点像PITA。您知道...与仅使每个唯一的地牢(内容)成为自己的类的懒惰选择相比。


9
基于文本的游戏会对很多内容进行硬编码,但是我认为这仅仅是因为它们的开发时间和较差的设计选择。矮人要塞也是如此。我个人已经使用了所有基于文本的游戏,并将内容从源代码移出并移入了数据库。它使我的生活变得如此轻松。
Glen Swan

7
i18n很难处理源代码中嵌入的内容。
pllee

5
不太确定这是特定于游戏开发的。将来考虑询问程序员SE或stackoverflow。
MichaelHouse

13
just making every unique dungeon (content) its own class.那让我颤抖。对我来说,将数据与逻辑分离是一个基本原则,令我惊讶的是仍然有开发人员违反它。
Lilienthal

4
无论您做出什么决定,都应意识到硬编码内容允许更多特殊情况。是否希望某个老板仅在午夜至7AM(实时)之间出现?硬编码比为怪物只在特定时间出现的通用方式容易得多。
user253751

Answers:


85

有几个原因。我只是要谈一些:

  1. 它使您的源代码一团糟。如果您有很多对话框(树),那么代码库的很大一部分就是与您的实际游戏代码无关的文本。
  2. 每次更改时,您都需要重新编译为单个字符。
  3. 对话框本身很难导航。我想尝试在整个源代码内部实现整个对话框树(更不用说几个对话框树)会导致一团糟的意大利面条和嵌套的ifs,switches等。从而导致易于出错,难以阅读和调试的代码。
  4. 如果您想让人们修改或扩展您的游戏,那么如果他们不必处理源代码来进行某些更改,那将容易得多。
  5. 如果您在团队中工作,以上几点尤为重要。您不希望您的编写者仅为了进入一个对话框就必须弄乱代码。
  6. 如果使用现有库,则解析XML或其他标准文件格式非常容易,因此以这种方式实现它的成本非常低,同时为您提供了很多优点,并且避免了上述问题以及更多其他问题。
  7. 正如@MiloPrice在下面指出的那样,如果您的文本位于外部文件中,则可以更轻松地对游戏进行本地化。您可以通过添加文件来添加语言,您的团队可以在不涉及源代码的情况下完成翻译工作(如果让人们翻译那些不应该看到您所有代码的人,这一点尤其重要-想想自由职业者,不属于您的团队的社区等)。

10
我不会说这会使您的代码变得一团糟。否则,无论内容与否,任何东西都可以看作是一团糟。您可以像代码一样以良好的结构来组织内容。但是,其他观点仍然很强。
Glen Swan

28
易于本地化/翻译是另一个很大的好处。
Milo P

2
@Christian:您可以有一个数据驱动程序,该程序将数据以可直接就地使用的格式嵌入程序中(例如,在C或C ++中,希望是const具有静态存储持续时间的大型数组)。这样可以节省在运行时加载/转换外部数据表示形式的所有代码和运行时内存成本。当然,将数据保持在外部的所有其他原因仍然适用。
R.,

2
就我个人而言,出于以下列举的相同原因,我更赞成采用更强大的方法:将大多数代码也转换为脚本语言。用C / C ++构建内核,嵌入Python或Lua之类的语言并向其中导出API。Don't Starve遵循这种方法,这是我见过的写得最好的游戏之一。过去和现在的许多其他游戏以及应用程序(很少有实用程序)也都可以做到这一点。我要说的是,总体而言,在小型项目和小型实用程序之外,繁琐的分层分离始终是您的朋友。
mechalynx


30

将游戏内容数据放入代码中意味着要查看该游戏内容数据的任何潜在变化或迭代,您必须重新编译游戏本身。这很不好,原因有两个:

  • 游戏编写的许多语言的编译时间都很长。在这方面,C ++特别糟糕,并且C ++是大型商业游戏的非常通用的语言。对于C#和Java这样的语言来说,这不是什么大问题,但是仍然不如能够将游戏数据存储在外部文件中那样快,可以在游戏实际运行以查看更改时对其进行热重装。

  • 许多游戏是由通常由非技术开发人员(设计师和美术师)组成的团队开发的。非技术人员不仅不希望重新编译游戏或使用“繁琐的程序员工具”来迭代其内容,而且可能希望将仅对程序员公开的源代码最小化(因为拥有源代码的机会,泄漏源代码的人就会越来越少(无论是否偶然)。

我认为您高估了从文本或XML文件加载数据的复杂性。大多数时候,您应该使用库来执行此操作,这使得解析XML / JSON /任何内容的过程变得更加容易。是的,编写一个由数据驱动的关卡加载系统要花一些前期费用,但与代表每个关卡的大量独特类相比,从长远来看,通常它可以为您节省很多时间。

较小或较简单的游戏可能不会从数据驱动方法的长期投资中获得太多收益,因此,除非开发人员正在使用支持该方法的现有框架/引擎,否则他们可能更有效地简单地将数据编码为游戏代码。

当然,有很多原因导致任何给定游戏都可以选择将其数据放入(或不放入)外部文件中的原因。全部列出都是不可行的。在某种程度上,它们通常会归结为无需重建游戏即可提供的额外迭代速度或灵活性。


我认为编译时间并不那么重要,但是作为开发人员,我们始终追求“简洁的代码”……这是一个很好的理由,可以将事物本身分开……内容应该是内容而不是代码!
战争

4
@Wardy编译时间在C ++中非常重要。由于项目的规模,模板的积极使用甚至开发人员的懒惰(包括不必要的标题),我使用的解决方案的构建时间都超过了15分钟。而且我敢肯定大型商业游戏就是这种情况。
concept3d 2014年

1
@ concept3d:我希望我的项目是15分钟。在专用的构建服务器上进行干净的构建大约需要50分钟。
Mooing Duck 2014年

获得源代码的人数越少,遭受C ++造成的脑部损害的人数也就越少。:P
Sarge Borsch

我认为有些人可能会错过热装的要点-没有人会在乎是否需要30秒来重新编译游戏,美术师不想重启游戏,他们想要键盘快捷键,因此可以测试不同的动画和动态纹理。实际上,这是他们最想要的事情之一。看到事物在游戏外部的外观是一回事,但在游戏中看到它们才是重要的。
Wolfdawn 2014年

7

和往常一样,这取决于。但是首先,我想指出,硬编码本身并不坏。

在一些简单的游戏中,我有硬编码的内容,特别是对话框文本,而世界并没有结束。我们程序员喜欢抽象的事物,但是请记住,您所做的每一层抽象都会使您的程序更复杂,更难以理解。

如果您的游戏足够简单,可以对其中的某些内容进行硬编码,那么我一定会出于简单考虑。

但是,这并没有真正扩大规模。当然,将内容放入外部资源的最常见原因是简化团队合作,因为一个人或团队可以专注于编写游戏,而另一个人或团队则可以专注于创建和完善内容。

但是,在程序和内容之间划清界限并不总是那么简单。可以说纹​​理是100%的内容。但是程序生成的纹理呢?对话文字可以视为100%的内容;但是当对话框根据您先前的操作而更改时该怎么办?脚本或着色器等其他可能被视为程序一部分的其他元素也可以视为游戏内容的一部分。是否应该对其进行硬编码?应该将它们作为外部资源加载吗?

但是请记住,您在游戏中支持的每种类型的内容都必须具有与之相关的加载和解释代码,因此通常,如果有疑问,我建议您对内容进行硬编码,并仅在您使用时将其带到外部资源中。确实需要这种灵活性(不是在您认为自己可能需要时,而是在实际需要时)

最后,将数据存储在资源文件中的一个优点是,您可以仅在需要时加载它们(因此可能会加快游戏加载时间),而在不再需要时卸载它们(因此可以让您拥有更多内容)超出内存容量)。(Nitpickers的一角:可以将资源DLL视为外部资源)


7
“但是请记住,您所做的每一层抽象都将使您的程序更加复杂并且更难以理解。” 我不得不不同意,抽象可以使程序更简单,当然也应该使它更易于理解。
NPSF3000

1
@ NPSF3000抽象增加复杂性,但可以消除比其增加的更多复杂性。
user253751

2
@immibis,因此在实现抽象之后,项目复杂性的总和低于之前。
NPSF3000

3
@ NPSF3000:我的意思是,您不应仅仅因为可以就可以创建抽象。有时,对数据进行硬编码会更简单,更易理解且更容易。我经常看到游戏沿着软件编码的道路发展,我感到很遗憾。还请记住,添加抽象总是比删除它们容易,因此我坚决主张仅在需要时才添加抽象。
熊猫睡衣2014年

@PandaPajama做某事“只是因为你能做到”很可能会引起问题,无论那是什么。这并不意味着某些事情本来就是复杂的,这是我关注的重点。另外,是什么让您认为添加抽象比删除抽象更容易?我会不以为然-延迟添加抽象可能意味着大量的重构,但是我无法立即想到删除不必要的抽象会很复杂的情况。从XML更改为硬编码字符串应该很简单。
NPSF3000

3

存储在文本文件中的一个重要原因是可重用性。创建一个可以从文本文件读取地图,对话框和其他资源的文本游戏框架,使您可以将框架重用于其他游戏。除文字游戏外,这是《使命召唤》等大型预算游戏每年发行新游戏的方式。

另一个原因是可移植性。您可以针对Web,PC,Mac,Android等使用相同的文件。您要做的就是为这些不同的平台模拟框架,而大部分游戏数据都保持不变。

当超越基于文本的游戏时,将脚本和数据存储在文件中会减少重新编译的时间,并使您可以创建一个界面来更轻松地操作数据。


1
当然,拥有大部分可重复使用的东西往往会迫使您避免执行已有规则之外的任何“特殊”操作。我绝对不提倡对大型游戏进行硬编码,但是当您制作原型或编写实验性游戏时,此功能非常有用-它为您提供了更大的灵活性。当然,它带有价格,因此通常在游戏玩法可行后重构所有内容通常是个好主意。游戏性是最难的部分-确保您可以进行测试,而无需深入了解建筑地狱:D通常,在获得具体知识后,更容易找到一般形式。
Lu安

3

为了更快地进行更改,它以吨为单位加快了更大产量的开发。

您无需教大家学习如何进入和编辑源代码以进行简单的更改。通过将其拖出实际的代码,更多的人有机会去闲逛​​,更容易找到可以使用的选项,并且微调游戏各个部分的整个过程所花费的时间要少得多。甚至问答也可以帮助您。


3

我不敢相信还没有人提到这一点,但是一个很大的原因是使本地化变得更加容易。如果您需要支持英语,法语,德语,西班牙语,葡萄牙语,意大利语,俄语,中文以及您要使用的任何其他语言,则硬编码要求您为每种语言提供单独的代码隐藏。这也意味着,如果您需要删除某些内容(阅读:审查制度),则需要更改代码本身来避免它,而不是说“只用这种被动攻击性横幅替换该肛门探测小游戏,以图形方式说明发生了什么情况”。对于消费者来说,这也是相当不友好的,因为很可能他们需要重新启动游戏以更改语言,因为您需要加载其他库。最后,

另一方面,如果您使用的是外部资源,则支持不同的语言仅意味着加载不同的资源文件。这可以在游戏运行时轻松完成。这意味着您可以拥有一个代码库,从而极大地简化了开发。这也意味着您可以轻松添加对其他语言的发行后支持。最后,这意味着您可以让用户选择不安装某些语言(这项功能在游戏中并不经常发生,但仍然可以实现)以节省磁盘空间和带宽。


3

我认为一个关键词是关注点分离

如果您的代码不包含文本,则代码的复杂度将降低。编写代码的程序员不必考虑特定的文本,而可以专注于代码。

他不必考虑本地化。进行本地化的人不必担心代码。


3

我认为成为“白手起家”的家伙太容易了,热烈推荐使用外部文本资源文件。

为什么?因为这里有一个选择是关于平衡每个解决方案的成本/问题/优势。

当使用外部文件时...好吧,我想其他答案足以很好地说明其好处。但是费用呢?您必须定义一个有效的形式主义,构建一个解释器,同意一种文件格式,更糟糕的是,构建另一个应用程序-一个编辑器-。如果您是一个由50位编码人员组成的团队来构建一个大型项目,那么这是0.00%的问题。但是,如果你是一个人:你就陷入了僵局。

同样,我并没有低估外部资源的巨大灵活性优势:对我来说,数据驱动编程似乎是视频游戏的必经之路。但是,我们不要忘记成本。

另一方面,将文本包含在代码中允许快速创建原型,因此应该在第一时间首选它。然后,随着项目的成熟,我的建议是分析建模对话框所需的数据类型(情绪/历史状态/ ...)。然后,在某个时候,您决定某些类/规则/文件格式,然后进行处理,从而允许其他人从内容中编辑/解耦代码,等等。或对于具有简单对话框的游戏(Mario ...),您只是认为代价太高,并且只保留了一些字符串/行为硬编码。
您的来电。

(关于本地化的说明:只是一个哈希表,所以这是一个独立且易于解决的问题。)


但是,如果您将文本放入代码中,其中某些事情仍然适用。您仍然需要某种格式,导航树的方式,等等。考虑到这一点,实现外部内容源的任何额外成本似乎都相对较低,特别是因为存在成熟的库和编辑器来解析,编写,编辑和创建这些文件。根据对话框的复杂程度,您甚至可能没有专业的编辑器而仅使用标准的文本编辑器就逃脱了。
基督教徒

1
当然:也许我还不够清楚,我的意思是只有经过几次迭代,您才能知道对话框的形状(从一条直线到一棵复杂的树或状态机)。在第一步中,几个(最简单的)ifs和一些硬编码的字符串就可以了。然后,当您可以明确预测需求时,在评估每种解决方案的成本/收益后做出选择。
GameAlchemist

我在当前的单人游戏项目中使用的中间立场是,在编译之前就具有从解析文件生成的硬编码内容。在很多情况下,这将是世界上最糟糕的解决方案,但是对于我所需要的它实际上是相当不错的。
glenatron 2014年

2

我猜许可也可能是代码中不包含内容的原因。

例如,

  • 您的代码可能是FLOSS,但是您根本不想许可您的内容(也许您想发布游戏代码,以便其他人可以使用它来创建具有不同内容的类似游戏)
  • 你的代码可能是FLOSS,但要使用知识共享许可协议的内容(如软件许可证不工作的重大内容,反之亦然)
  • 您的代码可能是专有的,但是您正在重用免费内容
  • 您的代码可能是专有的,但您想根据自由/自由许可发布自己的内容
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.