Unity学习-对话

目录

Model 数据结构:

System

Viewer


自己做的对话系统,使用QFrameworks框架

Model 数据结构:

对话数据:

[
    {
        "TreeId": "0",
        "NodeId": "0",
        "TextData": "",
        "DefaultNextTreeId": "0",
        "DefaultNextNodeId": "0"
    },
    {
        "TreeId": "0",
        "NodeId": "1",
        "TextData": "#商人|你好,我是一名商人",
        "DefaultNextTreeId": "0",
        "DefaultNextNodeId": "0"
    },
    {
        "TreeId": "1",
        "NodeId": "1",
        "TextData": "第一句话xxxxxxxxxxxxxxxxxx|#人名1|变更人名xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|测试无选项转入下一个节点",
        "DefaultNextTreeId": "1",
        "DefaultNextNodeId": "2"
    },
    {
        "TreeId": "1",
        "NodeId": "2",
        "TextData": "已转入节点xxxxxxxxxxxxxxxxxx|显示3个选项xxxxxxxxxxxxxxxxxx",
        "DefaultNextTreeId": "0",
        "DefaultNextNodeId": "0"
    },
    {
        "TreeId": "1",
        "NodeId": "3",
        "TextData": "选项1xxxxxxxxxxxxxxxxxx|#|清空人名xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|测试测试测试测试",
        "DefaultNextTreeId": "0",
        "DefaultNextNodeId": "0"
    },
    {
        "TreeId": "1",
        "NodeId": "4",
        "TextData": "选项2xxxxxxxxxxxxxxxxxx|#人名2|变化人名xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|以按钮结束对话",
        "DefaultNextTreeId": "0",
        "DefaultNextNodeId": "0"
    },
    {
        "TreeId": "1",
        "NodeId": "5",
        "TextData": "选项3xxxxxxxxxxxxxxxxxx|未变化人名|文字结束后自动结束对话",
        "DefaultNextTreeId": "0",
        "DefaultNextNodeId": "0"
    }
]
[
    {
        "TreeId": "0",
        "NodeId": "1",
        "AimTreeId": "1",
        "AimNodeId": "1",
        "Title": "开始测试",
        "Index": "0"
    },
    {
        "TreeId": "1",
        "NodeId": "2",
        "AimTreeId": "1",
        "AimNodeId": "3",
        "Title": "选项1",
        "Index": "0"
    },
    {
        "TreeId": "1",
        "NodeId": "2",
        "AimTreeId": "1",
        "AimNodeId": "4",
        "Title": "选项2",
        "Index": "1"
    },
    {
        "TreeId": "1",
        "NodeId": "2",
        "AimTreeId": "1",
        "AimNodeId": "5",
        "Title": "选项3",
        "Index": "2"
    },
    {
        "TreeId": "1",
        "NodeId": "3",
        "AimTreeId": "1",
        "AimNodeId": "2",
        "Title": "返回选择",
        "Index": "0"
    },
    {
        "TreeId": "1",
        "NodeId": "4",
        "AimTreeId": "0",
        "AimNodeId": "0",
        "Title": "结束对话",
        "Index": "0"
    },
    {
        "TreeId": "1",
        "NodeId": "4",
        "AimTreeId": "1",
        "AimNodeId": "2",
        "Title": "返回选择",
        "Index": "1"
    }
]

 刚开始使用的json结构,node和agent分成了两个列表,最近改了xml的

<root>
<ConversationTree TreeId="0" >
	
	<Node NodeId="0" TextData="" DefaultNextTreeId="0" DefaultNextNodeId="0">
		
	</Node>
	
	<Node NodeId="1" TextData="#商人|你好,我是一名商人" DefaultNextTreeId="0" DefaultNextNodeId="0">
		<ChildAgent TargetTreeId="0" TargetNodeId="0" Title="离开" />
		<ChildAgent TargetTreeId="1" TargetNodeId="1" Title="开始测试" />
	</Node>
	
</ConversationTree>

<ConversationTree TreeId="1" >
	
	<Node NodeId="1" TextData="第一句话|#人名1|变更人名|测试无选项转入下一个节点" DefaultNextTreeId="1" DefaultNextNodeId="2">
		
	</Node>
	
	<Node NodeId="2" TextData="已转入节点|显示3个选项" DefaultNextTreeId="0" DefaultNextNodeId="0">
		<ChildAgent TargetTreeId="1" TargetNodeId="5" Title="选项3" />
		<ChildAgent TargetTreeId="1" TargetNodeId="4" Title="选项2" />
		<ChildAgent TargetTreeId="1" TargetNodeId="3" Title="选项1" />
		
	</Node>
	
	<Node NodeId="3" TextData="选项1|#|清空人名|测试测试测试测试" DefaultNextTreeId="0" DefaultNextNodeId="0">
		<ChildAgent TargetTreeId="1" TargetNodeId="2" Title="返回选择" />
		
	</Node>
	
	<Node NodeId="4" TextData="选项2|#人名2|变化人名|以按钮结束对话" DefaultNextTreeId="0" DefaultNextNodeId="0">
		<ChildAgent TargetTreeId="1" TargetNodeId="2" Title="返回选择" />
		<ChildAgent TargetTreeId="0" TargetNodeId="0" Title="离开" />
	</Node>
	
	<Node NodeId="5" TextData="选项3|未变化人名|文字结束后自动结束对话" DefaultNextTreeId="0" DefaultNextNodeId="0">
		
	</Node>
	
	
</ConversationTree>

<ConversationTree TreeId="2" >
	
	<Node NodeId="1" TextData="#商人|我的店铺刚被怪物摧毁了|如果你可以帮我收集修复的木材,我可以支付你报酬并且店铺商品也会有优惠" DefaultNextTreeId="1" DefaultNextNodeId="2">
		<ChildAgent TargetTreeId="2" TargetNodeId="2" Title="那些怪物来自哪里?" />
	</Node>
	
	<Node NodeId="2" TextData="#商人|那是一群哥布林,它们的营地就在东边的山洞深处" DefaultNextTreeId="0" DefaultNextNodeId="0">
		<ChildAgent TargetTreeId="2" TargetNodeId="3" Title="我可以帮你收集木材" />
		<ChildAgent TargetTreeId="0" TargetNodeId="0" Title="我还有其他事" />
	</Node>
	
	<Node NodeId="3" TextData="#商人|多谢,此处向西有一片树林,那里会有足够的木材" DefaultNextTreeId="0" DefaultNextNodeId="0">
		
	</Node>
	
	<Node NodeId="4" TextData="#商人|多谢您的帮助xxxxxxx" DefaultNextTreeId="0" DefaultNextNodeId="0">
		
	</Node>
	
	<Node NodeId="5" TextData="#商人|多谢您的帮助" DefaultNextTreeId="0" DefaultNextNodeId="0">
		
	</Node>
	
	
</ConversationTree>





</root>

代码结构:

    //存储一个系列的对话节点
    public class ConversationNodeTree
    {
        public int TreeId{get;set;}

        public List<ConversationNode> nodeList = new List<ConversationNode>();
        
        public ConversationNode GetNode(int nodeId)
        {
            return nodeList.Single(n=>n.NodeId == nodeId);
        }

    }

    //对话节点
    public class ConversationNode 
    {
        //Entity
        public int TreeId{get;set;}
        public int NodeId{get;set;}
        public string TextData{get;set;}
        
        public int DefaultNextTreeId{get;set;}
        public int DefaultNextNodeId{get;set;}
        
        
        [Tooltip("以“#”加名字表示下面的对话是此人说的话,每行以‘|’隔开")]
        public List<string> lines;
        public List<ConversationNodeAgent> childNodeAgents = new List<ConversationNodeAgent>();
        
    }
    
    //用于表示对话中的选项
    public class ConversationNodeAgent
    {
        public int TreeId{get;set;}
        public int NodeId{get;set;}

        

        public int TargetTreeId{get;set;}
        public int TargetNodeId{get;set;}
        //可用于发送事件时判断点击选项的参数
        public string Title{get;set;}
        
        
        public ConversationNodeAgent() { }

        public ConversationNodeAgent(int treeID, int talkNodeID, int aimTreeID, int aimNodeID, string title)
        {
            this.TreeId = treeID;
            this.NodeId = talkNodeID;

            this.TargetTreeId = aimTreeID;
            this.TargetNodeId = aimNodeID;
            this.Title = title;
            
            
            
        }

    }



解析数据:


    public class ConversationModel : AbstractModel
    {
        
        //存储不进行的更改初始配置数据,当玩家数据为空时使用初始数据
        //private Dictionary<int, ConversationNodeTree> configConversationTreeDic = new Dictionary<int, ConversationNodeTree>();
        
        private Dictionary<int, ConversationNodeTree> playerConversationTreeDic = new Dictionary<int, ConversationNodeTree>();
        
        XDocument xmlDoc;
        
        protected override void OnInit()
        {
            //Dictionary<int, ConversationNodeTree> configConversationTreeDic = LoadDicFromJson(PathConfig.configConversationNodeDataPath, PathConfig.configConversationChildNodeDataPath);
            //if(!File.Exists(PathConfig.playerConversationNodeDataPath) ||  !File.Exists(PathConfig.playerConversationChildNodeDataPath))
            //{
            //    playerConversationTreeDic = configConversationTreeDic;
            //    xmlDoc = XDocument.Load(PathConfig.configConversationNodeDataPath);
            //}
            //else
            //{
            //    playerConversationTreeDic = LoadDicFromJson(PathConfig.playerConversationNodeDataPath, PathConfig.playerConversationChildNodeDataPath);
            //    xmlDoc = XDocument.Load(PathConfig.playerConversationNodeDataPath);
            //}
            if (!File.Exists(PathConfig.playerConversationXmlDataPath))
            {
                playerConversationTreeDic = LoadDicFromXml(PathConfig.configConversationXmlDataPath);
                xmlDoc = XDocument.Load(PathConfig.configConversationXmlDataPath);
            }
            else
            {
                playerConversationTreeDic = LoadDicFromXml(PathConfig.playerConversationXmlDataPath);
                xmlDoc = XDocument.Load(PathConfig.playerConversationXmlDataPath);
            }


        }

        [Obsolete("存储json数据,已弃用,改为xml存储")]
        Dictionary<int, ConversationNodeTree> LoadDicFromJson(string nodePath, string agentPath)
        {
            Dictionary<int, ConversationNodeTree> dic = new Dictionary<int, ConversationNodeTree>();
            
            if(!File.Exists(nodePath)||!File.Exists(agentPath))
            {
                //todo:
                Debug.Log("数据不存在");
                return null;
            }
            
            string s = File.ReadAllText(nodePath,System.Text.Encoding.UTF8);
            //Debug.Log(s);
            JsonData jsonArray = JsonMapper.ToObject(s);
            for (int i = 0; i < jsonArray.Count; i++)
            {
                JsonData j = jsonArray[i];
                ConversationNodeTree t;
                if (!dic.ContainsKey(j["TreeId"].ToInt32()))
                {
                    t = new ConversationNodeTree();
                    t.TreeId = j["TreeId"].ToInt32();
                    dic.Add(j["TreeId"].ToInt32(), t);
                }
                t = dic[j["TreeId"].ToInt32()];
                
                ConversationNode n = new ConversationNode();
                n.TreeId = j["TreeId"].ToInt32();
                n.NodeId = j["NodeId"].ToInt32();
                //n.TextData =j["TextData"].ToString();
                n.DefaultNextTreeId = j["DefaultNextTreeId"].ToInt32();
                n.DefaultNextNodeId = j["DefaultNextNodeId"].ToInt32();
                //ConversationNode n = JsonMapper.ToObject<ConversationNode>(j.ToString());

                string[] strs = j["TextData"].ToString().Split("|");
                n.lines = new List<string>(strs);
                t.nodeList.Add(n);
            }


            s = File.ReadAllText(agentPath, System.Text.Encoding.UTF8);
            jsonArray = JsonMapper.ToObject(s);
            for (int i = 0; i < jsonArray.Count; i++)
            {
                JsonData j = jsonArray[i];
                //Debug.Log(JsonMapper.ToJson(j));
                ConversationNodeAgent agent = new ConversationNodeAgent(
                    j["TreeId"].ToInt32(),
                    j["NodeId"].ToInt32(),
                    j["AimTreeId"].ToInt32(),
                    j["AimNodeId"].ToInt32(),
                    j["Title"].ToString()
                    );


                //ConversationNodeAgent agent = JsonMapper.ToObject<ConversationNodeAgent>(j.ToString());
                
                ConversationNode n = dic[j["TreeId"].ToInt32()].GetNode(j["NodeId"].ToInt32());
                
                n.childNodeAgents.Add(agent);
                //agent.Index = n.childNodeAgents.Count-1;

            }
            
            
            return dic;
        }
        
        Dictionary<int, ConversationNodeTree> LoadDicFromXml(string path)
        {
            Dictionary<int, ConversationNodeTree> dic = new Dictionary<int, ConversationNodeTree>();
            
            if(!File.Exists(path))
            {
                //todo:
                Debug.Log("数据不存在");
                return null;
            }
            
            XDocument doc = XDocument.Load(path);
            XElement root = doc.Root;
            
            IEnumerable<XElement> treeData = root.Elements("ConversationTree");
            foreach(var td in treeData)
            {
                ConversationNodeTree tree = new ConversationNodeTree();
                tree.TreeId = td.Attribute("TreeId").Value.ToInt32();
                
                tree.nodeList = new List<ConversationNode>();
                IEnumerable<XElement> nodeData = td.Elements("Node");
                foreach(var nd in nodeData)
                {
                    ConversationNode node = new ConversationNode();
                    node.TreeId = tree.TreeId;
                    node.NodeId = nd.Attribute("NodeId").Value.ToInt32();
                    node.lines = nd.Attribute("TextData").Value.Split('|').ToList();
                    node.DefaultNextTreeId = nd.Attribute("DefaultNextTreeId").Value.ToInt32();
                    node.DefaultNextNodeId = nd.Attribute("DefaultNextNodeId").Value.ToInt32();
                    
                    node.childNodeAgents = new List<ConversationNodeAgent>();
                    IEnumerable<XElement> agentData = nd.Elements("ChildAgent");
                    foreach(var ad in agentData)
                    {
                        ConversationNodeAgent agent = new ConversationNodeAgent();
                        agent.TreeId = tree.TreeId;
                        agent.NodeId = node.NodeId;
                        agent.TargetTreeId = ad.Attribute("TargetTreeId").Value.ToInt32();
                        agent.TargetNodeId = ad.Attribute("TargetNodeId").Value.ToInt32();
                        agent.Title = ad.Attribute("Title").Value;
                        
                        node.childNodeAgents.Add(agent);
                        
                    }
                    
                    tree.nodeList.Add(node);
                    
                }
                
                dic.Add(tree.TreeId , tree);
                
            }
            
            return dic;
            
            
            
            
        }
        
        void SaveAllXml()
        {
            foreach(var pair in playerConversationTreeDic)
            {
                for(int i = 0;i<pair.Value.nodeList.Count;i++)
                {
                    SaveNode(pair.Value.nodeList[i]);
                }
            }
            SaveXmlDoc();
        }
        
        void SaveNode(ConversationNode node)
        {
            XElement root = xmlDoc.Root;
            
            IEnumerable<XElement> treeData = root.Elements("ConversationTree");
            XElement td = treeData.Single(t=>t.Attribute("TreeId").Value.ToInt32() == node.TreeId);
            IEnumerable<XElement> nodeData = td.Elements("Node");
            XElement nd = nodeData.Single(n=>n.Attribute("NodeId").Value.ToInt32()  == node.NodeId);
            nd.RemoveNodes();
            for(int i=0;i<node.childNodeAgents.Count;i++)
            {
                XElement agentData = new XElement("ChildAgent", 
                new XAttribute("TargetTreeId", node.childNodeAgents[i].TargetTreeId.ToString()), 
                new XAttribute("TargetNodeId", node.childNodeAgents[i].TargetNodeId.ToString()), 
                new XAttribute("Title", node.childNodeAgents[i].Title)
                );
                
                nd.Add(agentData);
                
            }
            
            
            
        }
        void SaveXmlDoc()
        {
            xmlDoc.Save(PathConfig.playerConversationXmlDataPath);
        }
        
        public ConversationNode GetNode(int treeId, int nodeId)
        {
            ConversationNode node = null;
            if (playerConversationTreeDic.ContainsKey(treeId))
            {
                node = playerConversationTreeDic[treeId].GetNode(nodeId);
                
            }
            if (node == null)
            {
                Debug.Log("没有此节点");
            }

            return node;
        }
        
        public void AddChildAgent(ConversationNodeAgent t)
        {
            AddChildAgent(t.TreeId, t.NodeId, t);
        }
        
        public void AddChildAgent(int treeId, int nodeId, ConversationNodeAgent t)
        {
            if(treeId==0&&nodeId==0) return;
            
            ConversationNode n = GetNode(treeId, nodeId);
            
            if(n.childNodeAgents.Any(a => a.Title == t.Title))
            {
                Debug.Log("存在相同标题的节点");
                return;
            }
            
            t.TreeId = treeId;
            t.NodeId = nodeId;
            n.childNodeAgents.Add(t);
            //t.Index = n.childNodeAgents.Count-1;
        }
        
        public void RemoveChildAgent(int treeId, int nodeId,string agentTitle)
        {
            ConversationNode n = GetNode(treeId, nodeId);
            
            if(n.childNodeAgents.Any(a => a.Title == agentTitle))
            {
                Debug.Log(n.childNodeAgents.Count);
                n.childNodeAgents = n.childNodeAgents.Where(a=>a.Title != agentTitle).ToList();
                Debug.Log(n.childNodeAgents.Count);
                return;
            }
            else
            {
                Debug.LogFormat("{0}-{1} 对话节点不存在标题为 {2} 子节点代理", treeId, nodeId, agentTitle);
                
            }
            
        }
        
        [Obsolete("存储json数据,已弃用,改为xml存储")]
        public void SaveConversationData()
        {
            JsonData nodejs = new JsonData();
            JsonData agentjs = new JsonData();
            foreach (var kv in playerConversationTreeDic)
            {

                for (int i = 0; i < kv.Value.nodeList.Count; i++)
                {
                    JsonData nj = new JsonData();

                    ConversationNode n = kv.Value.nodeList[i];
                    nj["TreeId"] = n.TreeId;
                    nj["NodeId"] = n.NodeId;
                    nj["TextData"] = string.Join('|', n.lines.ToArray());
                    
                    for (int j = 0; j < n.childNodeAgents.Count; j++)
                    {
                        JsonData aj = new JsonData();

                        ConversationNodeAgent t = n.childNodeAgents[i];

                        aj["TreeId"] = t.TreeId;
                        aj["NodeId"] = t.NodeId;
                        
                        aj["AimTreeId"] = t.TargetTreeId;
                        aj["AimNodeId"] = t.TargetNodeId;
                        aj["Title"] = t.Title;
                        
                        //aj["Index"] = t.Index;
                        
                        agentjs.Add(aj);
                    }

                    nodejs.Add(nj);
                }




            }
            
            //File.WriteAllText(PathConfig.playerConversationNodeDataPath,nodejs.ToString());
            //File.WriteAllText(PathConfig.playerConversationChildNodeDataPath,agentjs.ToString());
            
        }


    }

System

控制对话的基本逻辑


    public class ConversationSystem : AbstractSystem, IWindowUICtrl
    {
        public bool isShowingConversation = false;
        
        ConversationWindowUIView conversationWindow;
        
        private ConversationNode currNode;
        private ConversationNode CurrNode
        {
            get=>currNode;
            set
            {
                currNode = value;
            }
        }
        
        private string CurrLine
        {
            get
            {
                if(lineIndex<0||lineIndex>CurrNode.lines.Count-1) return null;
                
                return CurrNode.lines[lineIndex];
            }
        }
        //private string currLineContent;
        private int lineIndex;
        private bool isShowingLine;
        Tween showTween;
        
        public void OpenWindow()
        {
            conversationWindow = this.GetSystem<UIWindowSystem>().OpenWindow(UIWindowType.Conversation) as ConversationWindowUIView;
            
            
        }
        
        public void CloseWindow()
        {
            this.GetSystem<UIWindowSystem>().CloseWindow(UIWindowType.Conversation);
            
        }
        
        public void StartConversation(int treeId, int nodeId)
        {
            OpenWindow();
            conversationWindow.Init(OnClickEvent, OnShowLineOver, SelectionBtnClickEvent);
            
            CurrNode = this.GetModel<ConversationModel>().GetNode(treeId, nodeId);
            lineIndex = -1;
            MoveNextLine();
            InvokeNodeStartEvent(CurrNode);
            
            isShowingLine = true;
            isShowingConversation = true;
            
            
            showTween = conversationWindow.ShowTextTween(CurrLine);
            
        }
        
        //非点击按钮的事件
        void OnClickEvent()
        {
            if(isShowingLine)
            {
                if(showTween!=null) 
                {
                    showTween.Pause();
                    showTween.Kill();
                }
                isShowingLine = false;
                conversationWindow.ShowAllText(CurrLine);
                
            }
            else
            {
                if(lineIndex<=CurrNode.lines.Count-2)
                {
                    MoveNextLine();
                    isShowingLine = true ;
                    showTween = conversationWindow.ShowTextTween(CurrLine);
                }
                else
                {

                    //最后一行且展示完时,没有按钮时的点击
                    List<ConversationNodeAgent> agents = CurrNode.childNodeAgents;
                    if (agents != null && agents.Count <= 0)
                    {
                        isShowingLine = true;
                        ChangeConversationNode(CurrNode.DefaultNextTreeId, CurrNode.DefaultNextNodeId, "");
                    }
                }
            }
        }
        
        //一行展示完时自动进行的,只有在最后一行结束且存在子节点时,才以此显示子节点选项
        void OnShowLineOver()
        {
            isShowingLine = false;
            if (lineIndex == CurrNode.lines.Count - 1)
            {
                List<ConversationNodeAgent> agents = CurrNode.childNodeAgents;
                if (agents != null && agents.Count > 0)
                {
                    conversationWindow.ShowSelection(agents);

                }

            }

        }
        
        void SelectionBtnClickEvent(ConversationNodeAgent agent)
        {
            ChangeConversationNode(agent);
        }
        
        //检查名称
        void MoveNextLine()
        {
            lineIndex++;
            if(CurrLine == null)
            {
                return;
            }
            
            if(CurrLine.StartsWith('#'))
            {
                string name = CurrLine.Remove(0, 1);
                //CurrLine.Copyto(1, name, 0, CurrLine.Length);
                conversationWindow.SetName(name);
                
                MoveNextLine();
            }
        }
        
        //没有选项显示直接结束的,会在检查选项时转到此处;有选项来结束的,选项指引转换节点,也会转到此处;两者都传入0-0节点,表示结束对话,同时关闭窗口
        public void ChangeConversationNode(int aimTreeId,int aimNodeId, string  selectionTitle)
        {
            if(aimTreeId == 0 && aimNodeId == 0)
            {
                EndConversation();
                return;
            }
            InvokeNodeEndEvent(CurrNode, selectionTitle);
            CurrNode = this.GetModel<ConversationModel>().GetNode(aimTreeId, aimNodeId);

            lineIndex = -1;
            MoveNextLine();
            InvokeNodeStartEvent(CurrNode);
            isShowingLine = true;

            if (showTween != null)
            {
                showTween.Pause();
                showTween.Kill();
            }
            showTween = conversationWindow.ShowTextTween(CurrLine);
        }
        
        public void ChangeConversationNode(ConversationNodeAgent agent)
        {
            ChangeConversationNode(agent.TargetTreeId, agent.TargetNodeId, agent.Title);
            
        }
        public void EndConversation()
        {
            InvokeNodeEndEvent(CurrNode,"");
            isShowingConversation = false;
            isShowingLine = false;
            CurrNode = null;
            lineIndex = -1;
            CloseWindow();
            
        }
        
        void InvokeNodeStartEvent(ConversationNode node)
        {
            this.GetSystem<ConversationEventSystem>().InvokeNodeStartEvent(node.TreeId, node.NodeId);
        }
        void InvokeNodeEndEvent(ConversationNode node, string selectionTitle)
        {
            //Debug.Log(this.GetSystem<ConversationEventSystem>().IsNull());
            this.GetSystem<ConversationEventSystem>().InvokeNodeEndEvent(node.TreeId, node.NodeId, selectionTitle);
        }
        
        public void RemoveNodeAgent(ConversationNodeAgent agent)
        {
            this.GetModel<ConversationModel>().RemoveChildAgent(agent.TreeId, agent.NodeId, agent.Title);
        }
        public void RemoveNodeAgent(int treeId, int nodeId,string agentTitle)
        {
            this.GetModel<ConversationModel>().RemoveChildAgent(treeId, nodeId, agentTitle);
        }
        
        
        protected override void OnInit()
        {
            
        }

        public void DestroyWindow()
        {
            //todo
            this.GetSystem<UIWindowSystem>().DestroyWindow(conversationWindow.gameObject);
        }
    }

对话事件管理:

    public class ConversationEventSystem : AbstractSystem, IDisposable
    {
        Dictionary<Vector2, Action> conversationNodeStartEventDic;
        Dictionary<Vector2, Action<string>> conversationNodeEndEventDic;
        
        
        
        protected override void OnInit()
        {
            conversationNodeStartEventDic = new Dictionary<Vector2, Action>();
            conversationNodeEndEventDic = new Dictionary<Vector2, Action<string>>();
            
            RegisterInitialEvent();
            
        }
        
        void RegisterInitialEvent()
        {
            //初始事件
            
            RegisterNodeStartEvent(0, 1, ()=>{Debug.Log("开始与商人对话");});
            RegisterNodeStartEvent(1, 1, ()=>{Debug.Log("进入测试对话");});
            RegisterNodeEndEvent(1, 2, (i)=>
            {
                switch(i)
                {
                    case "选项1":
                        Debug.Log("执行选项1");
                        break;
                    case "选项2":
                        Debug.Log("执行选项2");
                        break;
                    case "选项3":
                        Debug.Log("执行选项3");
                        break;
                }
                
            });
            RegisterNodeEndEvent(1, 3, (i)=>
            {
                switch(i)
                {
                    case "返回选择":
                        Debug.Log("返回选择");
                        break;
                    
                }
                
            });
            RegisterNodeEndEvent(1, 4, (i)=>
            {
                switch(i)
                {
                    case "结束对话":
                        Debug.Log("结束对话");
                        break;
                    case "返回选择":
                        Debug.Log("返回选择");
                        break;
                    
                }
                
            });
            RegisterNodeEndEvent(1, 5, (i)=>{Debug.Log("结束对话");});
            
            
        }
        
        
        public IUnRegister RegisterNodeStartEvent(int treeId, int nodeId, Action action)
        {
            Vector2 key = new Vector2(treeId, nodeId);
            
            if(!conversationNodeStartEventDic.ContainsKey(key))
            {
                conversationNodeStartEventDic.Add(key, null);
            }
            conversationNodeStartEventDic[key]+=action;
            
            return new CustomUnRegister(()=>
            {
                conversationNodeStartEventDic[key]-=action;
            
            });
            
            
        }
        public IUnRegister RegisterNodeEndEvent(int treeId, int nodeId, Action<string> action)
        {
            Vector2 key = new Vector2(treeId, nodeId);
            
            if(!conversationNodeEndEventDic.ContainsKey(key))
            {
                conversationNodeEndEventDic.Add(key, null);
            }
            conversationNodeEndEventDic[key]+=action;
            
            return new CustomUnRegister(()=>
            {
                conversationNodeEndEventDic[key]-=action;
            });
        }
        
        public void InvokeNodeStartEvent(int treeId, int nodeId)
        {
            Vector2 key = new Vector2(treeId, nodeId);
            if(conversationNodeStartEventDic.ContainsKey(key))
            {
                conversationNodeStartEventDic[key]?.Invoke();
                
            }
        }
        public void InvokeNodeEndEvent(int treeId, int nodeId, string selectionTitle)
        {
            Vector2 key = new Vector2(treeId, nodeId);
            if(conversationNodeEndEventDic.ContainsKey(key))
            {
                conversationNodeEndEventDic[key]?.Invoke(selectionTitle);
                
            }
        }
        
        public void Dispose()
        {
            conversationNodeStartEventDic.Clear();
            conversationNodeStartEventDic = null;
            conversationNodeEndEventDic.Clear();
            conversationNodeEndEventDic = null;
        }
        
        
        
    }

Viewer

    public class ConversationWindowUIView : UIWindowBase
    {
        public GameObject btnPrefab;
        List<Button> buttons;

        public Text talkerName;
        public Text text;
        public Transform btnGroup;
        
        Action ClickEvent;
        Action ShowLineOverEvent;
        Action<ConversationNodeAgent> SelectionBtnClickEvent;
        
        
        
        public void Init(Action clickEvent, Action showLineOverEvent, Action<ConversationNodeAgent> SelectionBtnClickEvent)
        {
            btnGroup.gameObject.SetActive(false);
            talkerName.text = "";
            text.text = "";
            this.ClickEvent = clickEvent;
            this.ShowLineOverEvent = showLineOverEvent;
            this.SelectionBtnClickEvent = SelectionBtnClickEvent;
        }
        
        
        void Update()
        {
            if(Input.GetMouseButtonDown(0))
            {
                RaycastHit hit;
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        
                if (Physics.Raycast(ray, out hit)) 
                {
                    if(hit.collider.GetComponent<Button>()==null)
                    {
                        ClickEvent?.Invoke();
                    }
                }
                else
                {
                    ClickEvent?.Invoke();
                }
                
            }
            else
            {
                if(Input.GetKeyDown(KeyCode.Space))
                {
                    ClickEvent?.Invoke();
                }
            }
        }
        
        public void SetName(string str)
        {
            
                talkerName.text = str;
        }
        
        public Tween ShowTextTween(string str)
        {
            text.text = "";
            float duration = str.Length/10f;
            Tween showTween = text.DOText(str, duration).OnStart(()=>
            {
                
                text.text = "";
            })
            .OnComplete(()=>
            {
                
                ShowLineOverEvent?.Invoke();
            });
            return showTween;
        }
        public void ShowAllText(string str)
        {
            text.text = str;
            
            ShowLineOverEvent?.Invoke();

        }

        public void ShowSelection(List<ConversationNodeAgent> agent)
        {
            btnGroup.gameObject.SetActive(true);
            Button[] btn = UIUtility.Instance.ShowBtnGroupList(btnGroup, btnPrefab, agent.Count);
            for (int i = 0; i < btn.Length; i++)
            {
                int j = i;
                btn[i].GetComponentInChildren<Text>().text = agent[i].Title;
                btn[j].onClick.AddListener(() =>
                {
                    SelectionBtnClickEvent?.Invoke(agent[j]);
                    btnGroup.gameObject.SetActive(false);
                });

            }

        }
        
        
        public override void BeforeClose()
        {
            ClickEvent = null;
            ShowLineOverEvent= null;
            SelectionBtnClickEvent= null;
        }
        
    }

其他:

    public class Talker : FoxGameController
    {
        public int treeId;
        public int nodeId;
        
        bool isEnter;
        
        void Start()
        {
            isEnter = false;
        }
        
        void Update()
        {
            if(isEnter)
            {
                
                if(Input.GetKeyDown(KeyCode.E))
                {
                    if(!this.GetSystem<ConversationSystem>().isShowingConversation)
                    {
                        this.GetSystem<ConversationSystem>().StartConversation(treeId, nodeId);
                    }
                }
                
                
            }
        }
        
        void OnTriggerEnter2D(Collider2D coll)
        {
            if(coll.tag.Equals("Player"))
            {
                //todo:新建ui,button group,在此显示并添加按钮;
                isEnter = true;
            }
        }
        void OnTriggerExit2D(Collider2D coll)
        {
            if(coll.tag.Equals("Player"))
            {
                //todo:新建ui,button group,在此显示并添加按钮;
                isEnter = false;
            }
        }
        
        
    }

2023.12.3更新:修改个bug,转换节点时设置index从0改为-1,再用movenextline检查人名;删除agent时,从skipwhile改为使用where筛选,因为skipwhile不是遍历并跳过所有满足条件的项,而是while逻辑,跳过序列中的元素,直到某个元素不满足时就终止,对之后的元素没有进行判断。

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值