Unity-如何创建对话树?

时间:2018-07-13 23:31:51

标签: unity3d dialog composite

因此,我为该程序设置了一个简单的对话树,我想在统一编辑器中显示一个问题和两个选项,如果单击一个选项,则可以转到树的另一级或叶子。我想使用复合设计模式来制作单独的级别实例,每个实例针对一个问题和两个选项使用不同的参数,并将它们一起添加到列表中。我所坚持的是如何从第一级开始并根据按下的按钮遍历树。似乎无论我做什么,它都只显示添加到列表中的最后一级参数。我能想到的最好的办法是在按钮单击事件期间添加某种移位列表功能。如果有人可以提出一些想法,我将不胜感激。谢谢。

public class Level : MonoBehaviour {

  bool button1Pressed;
  bool button2Pressed;

 private void Start()
 {


     Level Level1 = new Level("Hello", "Hi", "Shut Up");
     Level leaf1 = new Level("Don't be Rude");

     Level Level2 = new Level("What you Doing?", "Not Much", "None of your Business");
     Level leaf2 = new Level("Well Excuuuuse Me");

     Level Level3 = new Level("Can I do that too?", "Sure", "Go Away");
     Level leaf3 = new Level("Fine. Be a Jerk");

     Level Level4 = new Level("This is boring, can we do something else?", "Why not?", "You're boring");
     Level leaf4 = new Level("I'll go be boring somewhere else");

     Level Level5 = new Level("You want ice cream?", "Sounds Good", "I'm allergic");
     Level leaf5 = new Level("ok.......");
     Level leaf = new Level("I Want Chocolate");      

     Level1.add(Level1);
     Level1.add(leaf1);

     Level2.add(Level3);
     Level2.add(leaf2);

     Level3.add(Level4);
     Level3.add(leaf3);

     Level4.add(Level5);
     Level4.add(leaf4);

     Level5.add(leaf5);
     Level5.add(leaf);

 }

 public static Text Textbox;
 public static Button Button1;
 public static Button Button2;

     public string OptionA;
     public string OptionB;
     public string Question;

     public string Leaf;

     private List<Level> levels;

     public Level(string question, string optionA, string optionB)
     {
         this.Question = question;
         this.OptionA = optionA;
         this.OptionB = optionB;

     GameObject.FindGameObjectWithTag("Level").GetComponentInChildren<Text>().text = Question;
     GameObject.FindGameObjectWithTag("OptionA").GetComponentInChildren<Text>().text = OptionA;
     GameObject.FindGameObjectWithTag("OptionB").GetComponentInChildren<Text>().text = OptionB;

     levels = new List<Level>();

     }

     public Level(string leaf)
     {
         this.Leaf = leaf;
         Textbox.text = leaf;
     }

     public void add(Level lvl)
     {
         levels.Add(lvl);
     }

     public List<Level> getLevels()
     {
         return levels;
     }

 public void Button1Pressed()
 {

 }
 public void Button2Pressed()
 {

 }

}

public class Initializer : MonoBehaviour {

public Text Textbox;
public Button Button1;
public Button Button2;

void Awake()
{
    Level.Textbox = this.Textbox;
    Level.Button1 = this.Button1;
    Level.Button2 = this.Button2;
}
}

2 个答案:

答案 0 :(得分:1)

简短答案:所有节点都知道其父级和子级。


有几种方法可以解决此问题。我将解释使用带有多个节点类的树结构的方法。首先,我们可以像您概述的那样检查与玩家的互动:

  • 做出对话选择(说)
  • 观察对话框的响应(侦听)

我们还需要考虑一些重要条件:

  • 用户终止的对话
  • AI终止了对话

根据这个大纲,我们可以使用一些类来构建树。我已经摘录了一些示例,但尚未对其进行测试。希望它传达了这个想法,您可以构建自己的解决方案。对您来说,使单个Node类仅知道它是哪种类型也可能更有用。另一个改进是使用接口或某种方式来概括父子关系,从而允许使用更复杂的树结构。

class ChoiceNode
{
    public ChoiceNode(ResponseNode myParent)
    {
        parent = myParent;
    }

    ResponseNode parent = null;
    List<ResponseNode> children = new List<ResponseNode>;
    bool canSayGoodbye = true;
}

class ResponseNode
{
    public ResponseNode(ChoiceNode myParent, string myMessage)
    {
        parent = myParent;
        parent.children.Add(this);
        response = myMessage;
    }

    ChoiceNode parent;
    ChoiceNode child;
    string response;
}

我们现在应该能够通过简单地枚举ResponseNode.children来使用显示对话框选择的方法。然后,每当做出对话框选择时,我们都希望显示ResponseNode.response,然后移至ResponseNode.child以查找下一组对话框选择。当parent == null时,我们位于根分支。当child == null时,我们显示一些终止文本。

我希望这会有所帮助,并给您一些想法。

Drawing of tree data structure

答案 1 :(得分:0)

好吧,我试图理解代码的逻辑,但是有些事情我不理解,也许最好是解释一下“ Unity对话树”。

第一: 我们需要创建一个Tree对象。如果只需要二叉树,则只需要树变量:

public class BinaryTree{
  private string root;
  private BinaryTree left;
  private BinaryTree right
  getters/setters
}

该对象甚至不必是Unity组件。 根是“对话框” 左边是“ optionA” 右边是“ optionB” 如果您不需要多个答案,则只需选择left = right。 如果您需要识别多个答案的方法,建议您创建一个像这样的对象:

public class Tree{
  private Dictionary<string,string> root;
  private List<Tree> next;
  getters/setters
}

root再次是您的对话框。一个键(标识您的答案)和一个值,即实际的对话框。 接下来是树列表(您可以通过在下一个循环中并通过检查字典的键来确定答案)。

现在,在Start方法中,您需要创建一个新的Tree对象并设置下一个对象。 例子

Start(){
  BinaryTree bn = new BinaryTree();
  bn.Root = "Is this a question?";
  BinaryTree left = new BinaryTree();
  left.Root = "Nope";
  bn.Left = left;
  BinaryTree right = new BinaryTree();
  right.Root = "Yes it is...";
  bn.Right = right;
}

与Tree版本几乎相同:

Start(){
  Tree bn = new Tree();
  bn.Root = new Dictionary<string, string>();
  bn.Root.Add("key1", "Do you need something?");
  bn.Next = new List<Tree>();
  Tree answer1 = new Tree();
  answer1.Root = new Dictionary<string, string>();
  answer1.Root.Add("key2", "Yes");
  bn.Next.Add();
  ... iterate...
}

当然,这只是一个基本示例。初始化的最佳方法是将对话框添加到数组并进行迭代。 无论如何。

现在,您可以(例如)创建一个按钮。在“开始”中,您可以将其文本值初始化为您的根目录。在PointerDown / Clicked方法中,您可以排列可能的答案键的数组,例如,您可以决定为多个答案生成多个按钮(或者仅对BinaryTree使用2个静态按钮答案),然后根据回答根值(或左/右值)。每个应答按钮都应在PointerDown / Clicked方法中发送用户选择的键值(或左/右对象)(实际上是将在主问题按钮中显示的下一个值)。 当然,再次单击“问题按钮”应该显示下一个答案(也许您可以决定在对象中添加bool问题变量...或者您可以决定只使用左侧的问题...或者也许您可以决定下一个列表中是否只有1个值,那么该值就是一个问题,应该只在主按钮文本值中显示。)

如果下一个为空,那么您当然可以结束对话。

有多种方法可以做到这一点。