RPG对话引擎/结构

时间:2009-12-03 14:22:46

标签: data-structures

我一直对RPG(角色扮演游戏)中涉及的数据结构感兴趣。特别是,我对基于对话和事件的行为感到好奇。

例如:如果我在游戏中的 x 点接近NPC,项目 y 并且任务 z ,我将如何工作NPC需要说什么?分支对话和响应玩家输入似乎与定义脚本一样微不足道,并且用户输入使脚本阅读器跳转到脚本中的特定行,该行具有相应的响应行集(非常类似于选择自己的冒险)

然而,如果玩家拥有某些物品,并且完成某些任务似乎真的会破坏这个基于脚本的模型,那么将逻辑联系起来。

我正在寻找关于如何处理所有这些对话和逻辑的想法(不一定是编程语言示例),并将其分离出来,这样就可以非常轻松地添加新的分支内容,而无需深入研究过多的代码。 / p>

这真是一个悬而未决的问题。我不相信有一个单一的解决方案,但是用一些想法来推动这个问题是件好事。作为一名设计师而非程序员,我总是对分离内容和代码的方式感兴趣。

8 个答案:

答案 0 :(得分:19)

  

例如:如果我接近一个NPC   在游戏中指向x,项目为y和   任务z,我将如何解决问题   全国人大需要说什么?分枝   对话并回应玩家   输入似乎与拥有a一样微不足道   定义的脚本和用户输入原因   脚本阅读器跳转到   脚本中的特定行,即   有一套相应的回应   线(很像选择你自己的   冒险)

     

但是,如果有的话,用逻辑来解决问题   玩家有某些物品,并且   完成某些任务似乎   真的毁了这个基于脚本的模型。

完全没有。您只需将条件因素纳入数据。

假设你有对话列表,编号为1到400或者像选择你自己的冒险书中的例子。我假设每个对话可能包含NPC所说的文本,然后是播放器可用的回复列表。

因此,下一步是在那里添加条件,只需在每个响应中附加条件即可。最简单的方法是使用脚本语言执行此操作,因此,如果此响应可供播放器使用,则返回True的简短代码,如果不是,则返回False。

例如。 (XML格式,但可以是任何东西)

<dialogue id='1'>
  <text>
    Couldst thou venture forth and kill me 10 rats, perchance?
  </text>
  <response condition="True" nextDialogue='2'>
    Verily! Naught could be better than slaying thy verminous foes. Ten ratty
    carcasses shall I bring unto thee.
  </text>
  <response condition="rats_left_in_world() < 10" nextDialogue='3'>
    Nay, brother! Had thou but ten rats remaining, my sword would be thine,
    but tis not to be.
  </response>
</dialogue>

在您的脚本语言中,您需要一个'rats_left_in_world'函数,您可以调用该函数来检索有问题的值。

如果您没有脚本语言怎么办?好吧,你可以让程序员代码成为你对话中每种情况的个别条件 - 有点单调乏味,如果你的对话是预先写好的话,并不是那么困难。然后在对话脚本中按名称引用条件。

更高级的方案,仍然不需要脚本语言,可能会为每个条件使用标记,如下所示:

<response>
  <condition type='min_level' value='50'/>
  Sadly squire, my time is too valuable for the likes of thee. Get thyself a
  farm hand or stable boy to do thy bidding!
</response>

您可以根据需要在其中添加任意数量的条件,只要可以使用一个或两个值轻松指定它们。如果满足所有条件,则响应可用。

答案 1 :(得分:6)

有趣的是,这里似乎缺少一个核心理念。我们正在讨论与执行任务的程序员有关。实际上,上面的代码示例与代码相关联,而不是内容。

在游戏开发中,我们的程序员希望赋予内容开发人员权力。他们不会(这非常重要)看代码。期。你不时会得到一位技术艺术家或技术设计师,他们很棒,不介意;但是,大多数内容作者在技术上并不倾向。

我理解这个问题是为了你自己的启发;但是,应该指出的是,在行业中,当我们解决这些类型的问题时,我们的最终用户(利用我们正在开发的技术的人)不是工程师。

像这样的系统(分支对话)需要在工具中使用相对直观的表示。例如,可以使用Unreal的Kismet可视化脚本系统。

本质上,数据结构(很可能是分支树,因为它易于表示/调试/等)将由程序员精心制作,代表脚本中的对象的节点也是如此。系统能够链接到世界对象(很可能也是由可视化脚本中的节点代表)等,然后制作完整的小猫可以将一些优雅的代码链接在一起。

毕竟,设计师实际上能够在可视化脚本语言中构建对话分支的直观表示。这可能是地图遇到的特定情况。当然,你可以在程序上产生这些;但是,这更像是程序员的愿望,而不是设计师的愿望。

想到我会添加一些知识和洞察力。

编辑:注意到有一个XML示例。我不确定其他设计师/艺术家/等等。感受到它;但是,那些与我一起工作的人对于触摸文本文件的想法感到畏缩。

答案 2 :(得分:5)

我敢说,大多数现代游戏(无论是角色扮演游戏,动作游戏,基本卡片/棋盘游戏之上的任何游戏)通常都包含几个组件:显示引擎,核心数据结构,以及通常的辅助脚本引擎。一段时间流行的例子(可能仍然是;我多年来甚至没有和游戏开发者交谈)是Lua。

您正在谈论的决策(事件,会话分支等)通常由辅助脚本引擎处理,因为脚本语言更灵活,通常更容易为游戏设计者使用。同样,大多数真实的故事驱动或游戏驱动逻辑实际上都会在这里发生,它可以相对容易地换出和更改。 (至少,与运行完整版本的所有代码相比!)

主要游戏引擎结合了与世界相关的数据结构(几何等),与玩家相关的数据结构和其他所需的角色,以及驱动遭遇的脚本,并使用全部用于显示最终的集成环境。

答案 3 :(得分:4)

您当然可以使用脚本语言来处理对话。基本上,脚本可能如下所示:

ShowMessage("Hello " + hero.name + ", how can I help you?")
choices = { "Open the door for me", "Tell me about yourself", "Nevermind" }
chosen = ShowChoices(choices)
if chosen == 0
    if hero.inventory["gold key"] > 0
        ShowMessage("You have the key! I'll open the door for you!")
        isGateOpen = true
    else
        ShowMessage("I'm sorry, but you need the gold key")
    end if
else if chosen == 1
    if isGateOpen
        ShowMessage("I'm the gate keeper, and the gate is open")
    else
        ShowMessage("I'm the gate keeper and you need gold key to pass")
    end if
else
    ShowMessage("Okay, tell me if you need anything")
end if

这对大多数游戏来说都没问题。脚本语言可以很简单,您可以编写更复杂的逻辑分支。您的引擎将具有一些暴露于脚本语言的世界的表示。在此示例中,这表示英雄的名称和清单中的项目,但您可以公开任何您喜欢的内容。您还可以定义脚本可以调用的函数来执行诸如显示消息或播放某些声音效果之类的操作。您需要跟踪脚本之间共享的一些全局数据,例如门是打开还是完成任务(可能是地图和任务类的一部分)。

在某些游戏中,脚本编写可能会变得乏味,特别是如果对话更具动态性并且取决于许多条件(例如,角色情绪和统计数据,npc知识,天气,项目等)。这里可以存储您的对话树采用某种格式,可以轻松指定前提条件和结果。我不知道这是不是这样做的,但我曾经问过question about storing game logic in XML files。我发现这种方法对我的游戏有效(对话在很大程度上取决于很多因素)。特别是,在未来,我可以轻松地创建一个简单的对话编辑器,它不需要太多脚本,并允许您使用图形用户界面简单地定义对话和分支。

答案 4 :(得分:2)

我最近不得不为此开发一些东西,并选择了一个非常基本的文本文件结构。您可以在以下位置查看生成的代码和文本格式:

https://github.com/scottbw/dialoguejs

在编写程序的复杂性和非程序员编辑的简易性之间存在权衡。

我选择了一个非常简单的对话解决方案,并以辅助脚本语言分别处理相关游戏事件的触发。

最终,我可能会添加一些方法,将“阶段方向”添加到文本对话格式,用于触发辅助脚本引擎中的事件,但同样不需要在对话文件本身中放置任何类似代码的内容。< / p>

答案 5 :(得分:2)

这是一个很好的问题。我必须为客户解决几次问题。我们从与您的XML结构非常相似的XML结构开始,现在我们使用JSON。您可以在此处查看示例:http://www.branchtrack.com/projects/on029pq6.jsonhttps://dl.dropboxusercontent.com/u/11433463/branchtrack/on029pq6.json(为了便于阅读而美化它)。

完全披露:上面的链接是在BranchTrack中生成的,这是一个用于分支对话的在线编辑器,我是CEO。随意提问。

答案 6 :(得分:1)

我最近在制作Chat Mapper时解决了这样的问题。我所做的是以图形方式将对话框绘制为树中的节点,然后每个节点都有一个条件和一个与之关联的脚本。当您遍历树并命中节点时,检查条件以查看该节点是否有效,如果是,则执行与该节点关联的脚本。这是一个相当简单的想法,但似乎从我们的测试中运作良好。我们正在为脚本使用.NET Lua解释器。

答案 7 :(得分:1)

对于我的解决方案,我开发了一个自定义文本文件格式,每个节点包含七行文本。每一行可以是一个跨步列表或只是一个文本行。每个节点都有一个位置编号。数字的最后一位是一个类型,因此有10种不同类型的节点,例如新问题,确认,基于先前结果的重复操作等。

每个对话框激活都以对数据存储的选择查询开始,该查询的结果可以与跨步列表的成员进行比较,以匹配相应的节点。这比if / then更残酷,但它使文本配置文件更小,因为除了stride分隔符之外你不需要任何语法。我使用通配符系统来允许选择查询结果能够插入到NPC的语音中。

最后有一些API挂钩允许自定义脚本接口,以防简单的配置文件不够用。我计划在nodejs中创建一个web应用程序gui,以允许人们可视化地编写配置文件:D