这篇文章和上一张的任务系统相对独立但也不完全分离。很容易想象到,一个NPC的对话系统包括以下几个部分:

  • 没有任务时候的闲聊对话
  • 有任务但还没有接取时候的前置对话
  • 有任务并且接取之后的任务中对话
  • 有任务并且任务完成了之后的对话

我这里用了一个数据库来存所有对话,每一段对话有三个属性:对话ID,对话NPC,对话状态,对话内容。

在Dialogs数据库下,我建立了两个表,分别存储NPC的对话和玩家的对话。对话状态用于区分上面四种对话,当两个人物进行交互的时候会以下面流程进行对话加载:

以防有人没有看过我上一个关于人物系统的博客,这里说一下上面的几种任务状态的意义:任务还未接取的时候,任务数据库会把该任务状态设为0,脚本如果检测到0会存入内存。任务已经接取但是还没完成的时候,任务数据库会把该任务状态设为2,脚本如果检测到2会比未接取更高一级的将对话存入内存。任务已经完成但是没有进行结算对话的时候,任务数据库会把该任务设为3,这是最高一级的对话,会最优先存入内存。

再说一下每个任务是怎么对应上每一条对话的:

如上图所示,任务ID和对话ID是一一对应的,对于对话来说还分为三种状态的对话,用对话状态标示,和任务状态也是一一对应的。

为了节省空间,用于加载对话的List的泛型只是string类的,那如何存储对话ID呢?因为每一次加载的对话ID都是一样的,所以List的首元素用于存ID就行。

除了用于对应每种任务,不同的对话状态在进行完对话之后还有不同的处理方式。

  • 对于任务前置对话来说,对话结束后会弹出是否接受任务的弹窗,如果选择了是,那么对话状态为0的对话的状态会被设为1,即永远不可读。
  • 对于任务进行中对话来说,任务对话结束后无论如何不会改变对话状态,因为玩家可能在进行任务过程中无限次询问NPC关于任务的信息。
  • 对于任务结算对话来说,任务对话结束后会把对话状态为3的对话设为1,即永远不可读。

对话系统一些内容需要和任务系统紧密关联,下面先说对话结束之后弹出的两个框:接受和放弃

由于刚开始的设计失误,除了日常对话之外的三类对话都会产生接受与放弃选择框。所以下面对这三个类型进行分类讨论:

玩家最早拥有选择空间的时间是听完NPC描述任务完毕之后,这时候存储对话的List中只剩下一个元素,就是该对话的ID。如果要接受任务,可以利用这个ID去修改任务数据库中任务的状态并将这些对话都设成已读;如果不接受任务,则不需要做任何修改。

接受任务之后,如果玩家不能完成任务,那他们需要有放弃任务的权利(虽然就拓扑结构来说,可能这些玩家一定要做完这个任务才能继续推进主线),这个时候他们去找NPC,NPC说完话之后弹出的接受与放弃选择框的行为就和上述不同了,如果在这时选择确定,一般来说都是代表“OK,我能继续做下去”,如果是这样就不需要做过多动作。如果选择的是放弃,那就比较麻烦,因为第一阶段会更改任务状态和对话状态,所以这个时候需要把两者改回来

最后任务结算时的对话判断就很简单了,只要你完成了,在对话加载的一瞬间就可以立马标记你完成了任务,毕竟谁会拒绝任务完成后的奖励呢。

对话系统的介绍就到此为止,后续代码会在项目完成后发布到我的github上,欢迎评论进行交流。