为什么将实体配置放在脚本之外?


11

我见过很多在脚本文件中定义实体组件的游戏,但是当它们配置每个实体并指定其具有的组件时,它们会使用其他文件格式(例如XML)。他们为什么这样做?

我主要是想看看其他人对此的依据是什么。我还在脚本之外配置了我的实体(尽管我选择了JSON而不是XML)。我这样做的原因是使我更容易实现保存游戏,还因为我认为这种配置可以更好地组织为XML或JSON之类的东西。


// @ 克里斯托弗·拉森的答案: 太长了,无法发表评论

我担心您可能偏离了问题的主题。您所描述的问题与基于层次的实体更相关;在我提到的问题中,我提到我在谈论基于组件的实体。

这是我想问的一个例子。以下是配置实体的两种替代方法:通过脚本和通过外部JSON文件。我的问题是,为什么有那么多人喜欢在脚本之外配置实体?

基础实体类:

class Entity:
    def __init__(self, name):
        pass
    def addComponent(self, comp):
        pass

脚本方法:

orc = Entity('Orc')
orc.addComponent(PositionComponent(3.4, 7.9))

JSON方法:

{
    "name" : "Orc",
    "components":
    {
        "PositionComponent": {
            "x" : 3.4,
            "y" : 7.9
        }
    }
}

我已经说明了使用这种方法的原因,包括技术上和组织上的原因。我想知道为什么这么多其他人(根据我所看到的)使用它。

Answers:


13

我想到的主要优点是,它允许非程序员编辑/管理配置,而无需他们触摸任何游戏脚本。


这可以通过简单地拥有两个文件(.h然后是.cpp的等效文件)来实现。我确实想知道谁会愿意创建一个对象(除了说这个什么都不做看起来像花瓶,那个什么都不做看起来像黄油),又不想在其中添加一些逻辑(例如如果有人从花瓶中的花朵上盖了花粉,请吸引蝴蝶)。可读性很好,这是我为什么要这样做的想法之一,但是我再次提出,JSON,Lua表和XML的非程序员对人类可读性的等级都差不多。
詹姆斯

2
Glest是一款使用xml修改的游戏。许多非程序员为此制作了mod。使用xml / json比使用脚本绝对更容易实现。
威尔

6

我通常使用配置文件而不是脚本的原因之一是:

检查脚本是否正确(例如指定所有值)的唯一方法是运行脚本。

编写代码以允许脚本配置值意味着编写代码以创建脚本的骨架对象以填充值,然后验证脚本是否这样做。它的代码和错误代码比从平面配置文件加载的代码和buggier代码更多,通常使用支持某种验证机制的库。


5
早在主流软件开发更好的时候,这就是所谓的“最省力原则”如今,我们必须意识到选择最强大的解决方案而不是最不强大的解决方案的原因。原因是该语言的功能越弱,使用该语言存储的数据就可以做得越多。

1
@Joe实际上很好地描述了我也使用这种方法的原因之一。最初,我尝试在脚本中配置实体,但是发现很难实现保存游戏(无法跟踪组件之间的关系)。使用外部配置文件对我有很大帮助。
Paul Manta

实际上,我认为这是相反的方式,如果您已经在使用脚本接口,那么现在还必须为配置文件提供一种数据验证方法,而不是使用已经定义的脚本接口为您完成此操作。
詹姆斯

2

实体配置可以只是特定实体的序列化。这使您可以与保存游戏大致相同的方式处理游戏编辑和修改工具的输出。特别是,对于您无法预测游戏保存期间给定实体处于哪个状态的游戏(例如,由于其AI或因为它们最初是部分程序生成的),能够转储整个实体非常有用定义实体“是”(而不是实体“做什么”)作为要保存的字节流的数据。


1

您描述的模式是数据驱动系统的实现。

数据驱动系统通常用于游戏开发中,因为它们允许将内容的定义封装在源外部。然后可以轻松地修改此外部表示(甚至通过监视修改的应用程序实时更新)来更改实体的行为方式。

一旦在外部定义了数据,设计人员如何与之交互就具有各种各样的可能性,从直接编辑文本文件(ugh!)到复杂的UI,这些UI以合理,一致甚至验证的正确性指导设计人员的选择(从游戏平衡的观点)方式。

如果将数据直接嵌入代码中,则任何更改都将需要重新构建应用程序,这对于大型项目而言既耗时,又需要部署二进制文件(例如,新的二进制文件必须部署到并安装在二进制文件上)。服务器)。

让我们以“ orc”等立体实体为例。

实现我们的orc的一种方法是用代码编写一个完整的描述,以描述orc的所有特征和逻辑。

  • maxhealth = 10
  • 伤害=每秒3伤害
  • 失控=真
  • 当健康= 10时失控
  • 进取=真

当我们实例化兽人时,它们的所有值都被完全相同地初始化(或者可能是静态的)。出现的问题是,一些设计师会说:“我们需要针对新手领域的另一种兽人,这种兽人的健康状况较差,永远不会逃跑并且不具有侵略性。这将使新玩家习惯于在没有新手的情况下进行战斗。在学习战斗系统时增加了难度和困惑”。

太好了,现在您需要一个不同的类,或者(也许我们正在向前看)调整在“新手”区域中创建兽人的“工厂”中输入的值。因此,我们进行更改,部署新的二进制文件。只是让游戏测试者回来说新的健康值太低,因为我们一击就杀死了兽人。

如果我们的系统是数据驱动的(并且进行修改时支持重新加载的应用程序有加分),那么满足设计人员和游戏测试人员需要的修改就是简单的数据更改,而无需重新编译/部署。这使设计人员感到高兴,因为他们不必为等待代码更改而苦恼,也使程序员感到高兴,因为我们一直在修改源代码以调整值。

将数据驱动的系统发挥到极致,可以通过对数据的简单更改来实现从游戏级别,咒语甚至任务等所有内容,而无需更改代码。最后,它是关于轻松创建,调整和迭代游戏内容。


2
脚本也是由大多数定义数据
威尔

1
-1。问题不是关于数据驱动与硬编码,而是关于动态脚本与静态声明。

@Christopher我在OP中添加了很长的回复。请检查一下。
Paul Manta

0

在您的示例中,您实际上已经在使用两种脚本语言。从长远来看,这是我可以说的效果更好的方式,但是我建议您统一使用的脚本语言。如果您提供的脚本示例是在Lua中完成的,而不是Json,那么我会说使用Lua的表来构建您的对象。语法实际上是相似的,并允许您支持一个用于公开组件的接口。

谈到人们为什么选择通常先以XML进行操作然后再以逻辑脚本进行操作的原因,是当您说出来时这才有意义。这是我在数据中定义的对象,什么是好的数据存储格式?它几乎总是XML(尽管我也使用JSON;)。然后,当他们想要添加逻辑时,可以将其编码或放入脚本文件中。

它的想法没有错,但在我看来,人们只是不打算下一步。查看任何完整的语言,c / c ++ / c#。您可以用一种语言定义对象及其逻辑,为什么不在脚本接口中做同样的事情呢?这就像说我们考虑一下时应该使用XML定义类以及使用c#定义方法一样。也许较早的游戏脚本语言功能不够强大,并且它仍只是坚持下去。

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.