设计用于存储多人游戏的各种要求和统计数据的表格

时间:2009-08-18 08:32:39

标签: database database-design

原始问题:

您好,

我正在创建一个非常简单的爱好项目 - 基于浏览器的多人游戏。我坚持设计用于存储任务/技能要求信息的表格。

现在,我按照以下方式设计了表格:

  • 用户(有关用户的基本信息)
  • stat (各种统计数据)
  • user_stats (将每个用户与统计信息相关联)

另一个例子:

  • 怪物(关于npc敌人的基本信息)
  • table monster_stats (将怪物与统计数据相关联,使用上面相同的统计表)

那些是简单的案例。我必须承认,我在设计不同事物的要求时遇到困难,例如任务。示例任务A可能只有最低字符等级要求(并且易于实现) - 但另一个,任务B有许多其他要求(完成任务,获得技能,拥有特定项目等) - 什么是好方法设计用于存储此类信息的表格?

以类似的方式 - 什么是存储技能要求信息的有效方式? (特定角色等级,最低等级)。

我将非常感谢有关创建数据库驱动游戏的任何帮助或信息。

编辑:

感谢您的回答,但我希望收到更多。由于我在设计一个相当复杂的数据库布局时遇到了一些问题,我正在为这个问题开始最大的赏金。

我希望收到文章/代码片段的链接/与设计用于存储游戏数据的数据库的最佳实践相关的任何内容(这种信息的一个很好的例子可以在buildingbrowsergames.com上获得)。

如果有任何帮助,我将不胜感激。

13 个答案:

答案 0 :(得分:24)

答案 1 :(得分:12)

<强>更新

根据评论判断,看起来很多人都有XML问题。我知道现在抨击它很酷,它确实有问题,但在这种情况下我认为它有效。我选择它的另一个原因是有大量的库可以解析它,这样可以让生活更轻松。

另一个关键概念是信息真的是非关系。所以是的,您可以将数据存储在一堆具有大量连接的不同表中的任何特定示例中,但这很痛苦。但如果我不断给你一个不同的例子,我打赌你必须无限修改你的设计广告。我不认为添加表和修改复杂的SQL语句非常有趣。因此,@ scheibk的评论已被投票,这有点令人沮丧。

原帖:

我认为在数据库中存储任务信息时可能遇到的问题是它不是真正的关系(也就是说,它并不是很容易适合表格)。这可能就是您在设计数据表时遇到问题的原因。

另一方面,如果您将任务信息直接放入代码中,这意味着您必须编辑代码并在每次添加任务时重新编译。跛。

所以,如果我是你,我可能会考虑将我的任务信息存储在XML文件或类似的东西中。我知道这是几乎任何事情的通用解决方案,但在这种情况下,这对我来说是正确的。 XML实际上是用于存储非关系和/或分层数据,就像你需要为你的任务存储的东西一样。

总结:您可以提出自己的架构,创建XML文件,然后以某种方式在运行时加载它(甚至将XML存储在数据库中)。

示例XML:

<quests>
    <quest name="Return Ring to Mordor">
        <characterReqs>
            <level>60</level>
            <finishedQuests>
                <quest name="Get Double Cheeseburger" />
                <quest name="Go to Vegas for the Weekend" />
            </finishedQuests>
            <skills>
                <skill name="nunchuks" />
                <skill name="plundering" />
            </skills>
            <items>
                <item name="genie's lamp" />
                <item name="noise cancelling headphones for robin williams' voice />
            </items>
        </characterReqs>
        <steps>
            <step number="1">Get to Mordor</step>
            <step number="2">Throw Ring into Lava</step>
            <step number="3">...</step>
            <step number="4">Profit</step>
        </steps>
    </quest>
</quests>

答案 2 :(得分:5)

听起来您已经为一般的面向对象设计(OOD)原则做好了准备。我将故意忽略上下文(游戏,MMO等),因为这与你如何进行设计过程无关。我给你的链接没有什么比解释哪些条款最有助于自己查找,IMO;我会把它们用粗体。

在OOD中,数据库架构直接来自您的系统设计,而不是相反。您的设计将告诉您基础对象类是什么以及哪些属性可以存在于同一个表中( 1:1关系与对象相对应)与制作映射表(与< strong> 1:n 或 n:m 关系 - 例如,一个用户有多个统计信息,因此它是1:n)。事实上,如果你正确地完成了OOD,你将无法做出关于最终数据库布局的决定。

执行任何OO映射的“正确”方法是作为称为“数据库规范化”的多步骤过程学习的。其基础就像我描述的那样:找到对象关系的“arity”(1:1,1:n,...)并制作映射表对于1:n和n:m。对于1:n,你最终得到两个表,“base”表和“base_subobjects”表(例如你的“users”和“user_stats”就是一个很好的例子),带有“外键”(基础对象的Id)作为子对象映射表中的列。对于n:m,最终得到三个表:“base”,“subobjects”和“base_subobjects_map”,其中地图有一列用于基本Id,另一列用于子对象Id。在您的N个任务示例中,这可能是必要的,每个任务都有M个要求(因此需求条件可以在任务之间共享)。

这是你需要知道的85%。其余的是如何处理继承,我建议你跳过,除非你是自虐。现在,在你开始编写内容之前,先弄清楚你希望它如何工作,剩下的就是蛋糕了。

答案 3 :(得分:4)

@Shea Daniel的answer中的主题是正确的:任务的规范是非关系,还包括逻辑作为数据

使用XML或Lua是示例,但更一般的想法是开发自己的Domain-Specific Language来编码任务。这里有一些关于这个概念的文章,与游戏设计有关:

您可以将给定任务的代码块存储到数据库中的TEXT字段中,但是使用SQL查询其中的特定部分您将没有太大的灵活性。例如,考虑到角色目前拥有的技能,哪些任务对他开放?如果任务先决条件在TEXT字段中的DSL中进行编码,则在SQL中查询将不容易。

您可以尝试以关系方式对各个先决条件进行编码,但很快就会失控。关系和面向对象只是不能很好地融合在一起。您可以尝试以这种方式对其进行建模:

Chars <--- CharAttributes --> AllAttributes <-- QuestPrereqs --> Quests

然后执行LEFT JOIN查找角色属性中没有先决条件的任何任务。这是伪代码:

SELECT quest_id
FROM QuestPrereqs
 JOIN AllAttributes
 LEFT JOIN CharAttributes
GROUP BY quest_id
HAVING COUNT(AllAttributes) = COUNT(CharAttributes);

但问题在于,现在你必须对角色的每个方面进行建模,这可能是一个先决条件(统计,技能,等级,所有权,完成的任务)作为某种抽象的“属性“适合这种结构。

这解决了跟踪任务先决条件的问题,但它给你留下了另一个问题:角色以非关系方式建模,本质上是一个实体 - 属性 - 值架构,它打破了一堆关系规则并使其他类型查询难以置信。

答案 4 :(得分:3)

与您的数据库设计没有直接关系,但几周后又提出类似的问题class diagram examples for an RPG

我相信你可以找到有用的东西:)

答案 5 :(得分:3)

关于你的基本结构,你可以(根据你游戏的性质)考虑推动玩家角色和非玩家角色之间的表达收敛,这样任何一个自然运行相同的代码都不会不得不担心这种区别。这表明,不是拥有usermonster表,而是拥有代表PC和NPC共有的所有内容的character表,然后使用user表来获取唯一的信息到PC和/或用户帐户。 user表将具有character_id外键,您可以通过存在与其对应的user行来告诉玩家字符行。

为了在像你这样的模型中表示任务,我的方式如下:

quest_model
===============
id
name ['Quest for the Holy Grail', 'You Killed My Father', etc.]
etc.

quest_model_req_type
===============
id
name ['Minimum Level', 'Skill', 'Equipment', etc.]
etc.

quest_model_req
===============
id
quest_id
quest_model_req_type_id
value [10 (for Minimum Level), 'Horseback Riding' (for Skill), etc.]

quest
===============
id
quest_model_id
user_id
status
etc.

所以quest_model是任务结构的核心定义;每个quest_model可以有0..n关联的quest_model_req行,这些行是特定于该任务模型的要求。每个quest_model_req都与quest_model_req_type相关联,quest_model_req定义了一般要求类型:达到最低等级,拥有技能,拥有一件装备,等等。 value还有一个value,用于配置此特定任务的要求;例如,最低级别类型要求的quest可能为20,这意味着您必须至少达到20级。

然后,quest表是玩家正在或正在进行的任务的单个实例quest_modelusercharacter(或者status相关联,如果您希望NPC能够执行任务!),并且{{1}} 1}}表示任务进展的位置,以及其他任何跟踪结果都有用。

这是一个简单的结构,当然,必须建立以满足特定游戏的需求,但它应该说明我建议的方向。

哦,自从其他人投入他们的证书以来,我的是我已经成为一个业余的,面向公众的项目16年的业余爱好者游戏开发者。

答案 6 :(得分:3)

答案 7 :(得分:2)

我会从面向对象的角度来看待这个问题,而不是以数据为中心的观点。看起来你可能有很多(可能很复杂的)对象 - 我建议先把它们建模(用它们的关系),然后依靠ORM来保持持久性。

答案 8 :(得分:1)

当您遇到以数据为中心的问题时,数据库就是您的朋友。你到目前为止所做的事情似乎非常正确。

另一方面,您提到的其他问题似乎是以行为为中心的。在这种情况下,面向对象的分析和解决方案将更好地工作。

例如: 使用specificQuest子类创建任务类。每个孩子都应该实施bool HasRequirements(Player player)方法。

答案 9 :(得分:1)

另一种选择是某种规则引擎(Drools,例如,如果您使用的是Java)。

答案 10 :(得分:1)

如果我正在为这种情况设计数据库,我可能会这样做:

Quest
    [quest properties like name and description]
    reqItemsID
    reqSkillsID
    reqPlayerTypesID
RequiredItems
    ID
    item
RequiredSkills
    ID
    skill
RequiredPlayerTypes
    ID
    type

在这里,ID到各个表的地图然后你检索该ID下的所有条目,以获得所需项目,技能,你有什么。如果允许动态创建项目,那么您应该映射到包含所有可能项目的另一个表。

要记住的另一件事是规范化。有一篇很长的文章here,但我已经将前三个级别或多或少压缩到以下几个级别:

  • 第一范式表示没有数据库条目,其中特定字段中包含多个项目
  • 第二范式表示如果您有复合主键,则所有其他字段完全依赖于整个键,而不仅仅是每个表中的部分键
  • 第三范例是您没有依赖于任何表中其他非关键字段的非关键字段

[免责声明:我对SQL数据库的经验很少,对这个领域不熟悉。我只是希望我有所帮助。]

答案 11 :(得分:1)

我做了类似的事情,我的一般解决方案是使用大量的元数据。我松散地使用这个术语来表示任何时候我需要新数据来做出给定的决定(允许任务,允许使用项目等)我会创建一个新属性。这基本上只是一个具有任意数量的值和描述的表。然后每个字符都有这些类型属性的列表。

Ex:杀戮,等级,访问地区等列表

这对你的开发过程有两个作用:

1)每次游戏中都有一个事件,你需要有一个很大的旧开关块来检查所有这些属性类型,以查看是否需要更新某些内容

2)每当您需要一些数据时,请在添加新数据之前检查所有属性表。

我发现这对于一个有机增长的游戏来说是一个很好的快速发展策略(并没有提前在纸上完全计划) - 但它的一个很大的局限是你过去/现在的内容(等级/事件等)会与未来属性不兼容 - 即该地图不会为您提供区域徽章,因为编码时没有区域徽章。这当然要求您在将新属性添加到系统时更新过去的内容。

答案 12 :(得分:1)

只需要一些小点供您考虑:

1)总是尽量让你的“获得任务”要求变得简单......并且“完成任务”要求变得复杂..

第1部分可以通过“尝试按层次顺序进行任务”来完成:
例如:

QuestA :(杀死恶魔)(任务请求:Lvl1)
 QuestA.1:在森林中保存“unkown”以获取一些信息..(quest req:QuestA)
 QuestA.2:制作水晶之剑......等等。(任务请求:QuestA.1 ==完成)
 QuestA.3:......等..(任务请求:QuestA.2 ==完成)
 QuestA.4:......等..(任务请求:QuestA.3 ==完成)
等......  QuestB(找到丢失的坟墓)(任务请求:(QuestA.statues ==完成))
 QuestC(去恶魔大卖场)(Quest req:(QuestA.statues == Done&amp;&amp; player.level == 10)
等....

这样可以节省大量的数据字段/表格关节。

其他想法:
如果您使用上述系统,您可以在名为“enableQuests”的任务表中添加额外的奖励字段,并添加需要启用的任务名称。
逻辑上..你有一个“启用”字段分配给每个任务..

2)您的工艺问题的次要解决方案,创建制作配方,包含存储在其中的待制作项目制作要求的项目。 所以当玩家试图制作一件物品时......他需要先购买食谱......然后尝试制作...... 这种项目描述的一个简单例子是:
ItemName:“死者的传说之剑”
Craftevel req。 :75
所需物品:
Item_1:死者之刃
Item_2:被诅咒的印章
item_3:死者的圣宝石 等...

当他按下“工艺”动作时,你可以解析它并与他的库存/工艺盒进行比较......

所以你的Crafting DB只有1个字段(如果你想添加一个精心设计的LvL req,则为2个,尽管它已经包含在配方中。

其他想法:
这些项目可以在表格中以xml格式存储..这样可以更容易解析...

3)类似的XML系统可以应用于你的任务系统......以实现任务结束要求..