代码与游戏对象库的配置

时间:2010-06-23 18:18:23

标签: language-agnostic design-patterns data-structures

我正在开发一款小型在线游戏,需要存储大量(100多种)不同类型游戏对象的大量信息。

我正在尝试决定是通过代码生成此数据还是存储在某个配置文件中。

数据生成方法类似于(在java-ish伪代码中):

(within a set of functions executed once at program startup)
....
// create grass terrain
grass=new GameObject();
grass.inheritProperties(generic_terrain);
grass.set(NAME,grass);
grass.set(MOVEABLE,true);
grass.set(MOVECOST,10);
grass.set(IMAGE_INDEX,1);
....

而配置文件方法可能只使用XML类型的格式,例如

(within terrain.xml file)
....
<terrain name="grass">
    <inherit class="generic_terrain"/>
    <property key="NAME" value="grass"/>
    <property key="MOVABLE" value="true"/>
    <property key="MOVECOST" value="10"/>
    <property key="IMAGE_INDEX" value="1"/>
</terrain>
....

一些要点:

  • 此信息每次都是静态的 游戏游戏运行(即没有 执行期间改变)
  • 属性名称(NAME,MOVECOST等)是一个相对较小的列表,但可以随时间添加其他名称
  • 很安全 假设它只会得到 由开发团队改变(即 不需要配置 在构建之外进行管理 处理)。
  • 需要调整 在开发期间经常进行 出于游戏平衡的原因(例如,使单位更少/更强大)
  • 属性有一定数量的“继承”,即在上面的示例中,grass需要具有generic_terrain定义的所有标准属性以及一些新的添加/更改。

哪种方法最适合这种情况?更重要的是为什么?

5 个答案:

答案 0 :(得分:5)

就个人而言,我喜欢尽可能多地进行配置。这样做的原因是,在某些时候我可能想要以完全不同的方式重用我为游戏编写的代码。如果源代码中充斥着对实现特定细节的引用,那就变得更加困难了。

当您想要开始描述对象的行为以及它们的值时,会出现一个有趣的配置方法。考虑一个简单的例子,你有一个需要“捕捉”球对象的杯子对象。您可以表达它们:

<object name="ball">
    <property key="shape" value="circle"/>
    <property key="movable" value="true"/>
    <property key="speed" value="10"/>
</object>

<object name="cup">
    <property key="shape" value="rectangle"/>
    <property key="movable" value="true"/>
    <property key="speed" value="6"/>
    <property key="catches" value="ball"/>
</object>

这里的问题是,你仍然必须在代码中定义“捕获”的内容。如果您使用的是解释性语言,则可以执行以下操作:

<object name="cup">
    <property key="shape" value="rectangle"/>
    <property key="movable" value="true"/>
    <property key="speed" value="6"/>

    <oncollision>
      if (collided.getName() == "ball") {
        collided.destroy();
        points++;
      }
    </oncollision>
</object>

现在,您已经能够描述对象的行为以及 的内容。这里唯一的问题是,如果您不使用解释语言,则无法在运行时定义代码。这是Lua在游戏开发中如此受欢迎的原因之一。它既可以作为声明语言也可以作为程序语言使用,并且很容易嵌入到已编译的应用程序中。所以你可以表达这样的情况:

object {
  name='ball';
  movable=true;
  speed=10;
}

object {
  name='cup';
  movable=true;
  speed=6;
  oncollision=function(collided)      
     if collided:getName() == "ball" then
        collided:destroy();
        points++;
     end
  end;
}

答案 1 :(得分:2)

从代码中分离数据只是一个好主意。即使数据在执行期间是静态的,也不是在设计过程中。具有硬编码数据的游戏比从易于修改的配置文件收集数据的游戏灵活得多。

将数据保存在单独的文件中,例如xml,可以快速简单地更改各种值,您认为这很重要。

答案 2 :(得分:2)

这与语言无关。

如果您使用的是编译语言,请使用配置文件,这样每次调整时都不会强制重新编译。

如果您使用的语言不需要执行显式编译/链接过程,请在代码中执行此操作,这样您就不必处理解析和加载。 (但是在一个地方这样做,以便在将来某个时候需要完全更换功能)。

这里的基本理念是代码是数据,但有时代码作为数据很难修改;在这种情况下(例如,编译语言的情况),将其写入一种更容易修改的代码中。 (您的解释配置语言。)

答案 3 :(得分:2)

许多游戏引擎使用脚本语言的原因很多。 Lua是一个非常棒的,相当快速,轻量级的脚本引擎,已经在许多游戏中获得了巨大的成功。您可以轻松地使用解析器进行简单的配置设置并将其保留在该设置中,或者构建更多功能并让实际代码写入文件中。您在lua中的示例可能类似于:

grass = {
    NAME = "grass",
    MOVEABLE = true,
    MOVECOST = 10,
    IMAGE_INDEX = 1
}

setmetatable(grass, generic_terrain)

答案 4 :(得分:2)

如果您确实选择使用XML,至少尝试使用理智的架构。当它被设计为直接表示那些东西时,没有理由将自己的小模式(“对象”,“属性”,“键”,“值”)嵌入到XML中。怎么样:

<ball>
    <shape>circle</shape>
    <movable>true</movable>
    <speed>10</speed>
</ball>

<cup>
    <shape>rectangle</shape>
    <movable>true</movable>
    <speed>6</speed>
    <catches>ball</catches/>
</cup>