Beispiel #1
0
        // Saves nodes
        private bool SaveNodes(BTDataContainer btContainer, string fileName)
        {
            // If there are no connections then display error
            if (!edges.Any())
            {
                EditorUtility.DisplayDialog("No connections", "Create some connections in your tree before saving!", "Ok");
                return(false);
            }

            // Save node connections
            Edge[] connectedPorts = edges.Where(x => x.input.node != null).ToArray();

            for (int i = 0; i < connectedPorts.Length; i++)
            {
                BTEditorNode outputNode = connectedPorts[i].output.node as BTEditorNode;
                BTEditorNode inputNode  = connectedPorts[i].input.node as BTEditorNode;

                btContainer.nodeLinks.Add(new NodeLinkData
                {
                    BaseNodeGuid   = outputNode.GUID,
                    PortName       = connectedPorts[i].output.portName,
                    TargetNodeGuid = inputNode.GUID
                });
            }

            // Save individual node data
            foreach (BTEditorNode node in nodes)
            {
                NodeData temp = new NodeData
                {
                    nodeTitle = node.title,
                    nodeName  = node.nodeName,
                    GUID      = node.GUID,
                    Position  = node.GetPosition().position,
                    nodeType  = (int)node.nodeType,
                    topNode   = node.topNode
                };

                if (node.compositeInstance != null)
                {
                    temp.compositeInstance = (Composite)SaveNode(node.title + node.GUID, node.compositeInstance, fileName);
                }
                else if (node.decoratorInstance != null)
                {
                    temp.decoratorInstance = (Decorator)SaveNode(node.title + node.GUID, node.decoratorInstance, fileName);
                }
                else if (node.actionInstance != null)
                {
                    temp.actionInstance = (Action)SaveNode(node.title + node.GUID, node.actionInstance, fileName);
                }

                btContainer.nodeData.Add(temp);
            }

            return(true);
        }
Beispiel #2
0
        /// <summary>
        /// Called when a search tree entry is selected
        /// </summary>
        /// <param name="SearchTreeEntry"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public bool OnSelectEntry(SearchTreeEntry SearchTreeEntry, SearchWindowContext context)
        {
            // Get mouse world mosue position in editor window
            Vector2 worldMousePosition = _editorWindow.rootVisualElement.ChangeCoordinatesTo(_editorWindow.rootVisualElement.parent,
                                                                                             context.screenMousePosition - _editorWindow.position.position);

            // Convert it to graphview coords to spawn nodes at mouse position
            Vector2 localMousePosition = _graphView.contentViewContainer.WorldToLocal(worldMousePosition);

            BTEditorNode tempNode = (BTEditorNode)SearchTreeEntry.userData;

            _graphView.CreateNode(tempNode.nodeName, tempNode.nodeName, tempNode.nodeType, localMousePosition);

            return(true);
        }
Beispiel #3
0
        /// <summary>
        /// Adds a port to a target node
        /// </summary>
        /// <param name="targetNode"></param>
        /// <param name="overriddenPortName"></param>
        public void AddPort(BTEditorNode targetNode, string overriddenPortName = "")
        {
            // Generate port
            Port generatedPort = GeneratePort(targetNode, Direction.Output);

            // Removes default label from port in favour of editable labels
            Label oldLabel = generatedPort.contentContainer.Q <Label>("type");

            generatedPort.contentContainer.Remove(oldLabel);

            // Adds default port name
            int outputPortCount = targetNode.outputContainer.Query("connector").ToList().Count;

            generatedPort.portName = outputPortCount.ToString();

            // Check if default portname is overridden
            string portName = string.IsNullOrEmpty(overriddenPortName)
                ? outputPortCount.ToString()
                : overriddenPortName;

            // Adds name field
            TextField textField = new TextField
            {
                name  = string.Empty,
                value = portName
            };

            // textField.RegisterValueChangedCallback(evt => generatedPort.portName = evt.newValue);
            generatedPort.contentContainer.Add(new Label("     "));
            generatedPort.contentContainer.Add(textField);

            // Adds delete port button
            Button deleteButton = new Button(() => RemovePort(targetNode, generatedPort))
            {
                text = "X"
            };

            generatedPort.contentContainer.Add(deleteButton);
            generatedPort.portName = portName;

            targetNode.outputContainer.Add(generatedPort);

            targetNode.RefreshPorts();
            targetNode.RefreshExpandedState();
        }
Beispiel #4
0
        /// <summary>
        /// Returns list of child nodes based on node GUID
        /// </summary>
        /// <param name="nodeGUID"></param>
        /// <returns></returns>
        public List <BTEditorNode> GetChildNodes(string nodeGUID, string fileName)
        {
            // Update cache to contain current nodes
            SaveGraph(fileName);
            _containerCache = Resources.Load <BTDataContainer>(fileName);

            List <NodeLinkData> connections = _containerCache.nodeLinks.Where(x => x.BaseNodeGuid == nodeGUID).ToList(); // Get connections from active container cache
            List <BTEditorNode> childNodes  = new List <BTEditorNode>();

            // Loop through connections for a given node and find its child nodes via GUID matching
            for (int i = 0; i < connections.Count; i++)
            {
                string targetNodeGUID = connections[i].TargetNodeGuid;

                BTEditorNode targetNode = nodes.First(x => x.GUID == targetNodeGUID);

                childNodes.Add(targetNode);
            }

            return(childNodes);
        }
Beispiel #5
0
        // Removes port from target node
        private void RemovePort(BTEditorNode targetNode, Port portToRemove)
        {
            // Find port in node that matches port to remove
            IEnumerable <Edge> targetEdge = edges.ToList().Where(x => x.output.portName == portToRemove.portName && x.output.node == portToRemove.node);

            // If no edges got added to the list only remove port
            if (!targetEdge.Any())
            {
                targetNode.outputContainer.Remove(portToRemove);
            }
            else // If edges remove edges then remove port
            {
                // Get edge matching the above requirements and remove connections and then the port
                Edge edge = targetEdge.First();
                edge.input.Disconnect(edge);
                RemoveElement(targetEdge.First());

                targetNode.outputContainer.Remove(portToRemove);
                targetNode.RefreshPorts();
                targetNode.RefreshExpandedState();
            }
        }
Beispiel #6
0
        // Generate nodes based on save data
        private void CreateNodes()
        {
            BTEditorNode tempNode = null;

            foreach (NodeData nodeData in _containerCache.nodeData)
            {
                // Generate node based on node data. We pass node position later so we can use zerovector while loading
                switch ((NodeTypes)nodeData.nodeType)
                {
                case NodeTypes.Composite:
                    tempNode      = _targetGraphView.GenerateNode(nodeData.nodeTitle, nodeData.nodeName, (NodeTypes)nodeData.nodeType, Vector2.zero, nodeData.topNode, nodeData.compositeInstance);
                    tempNode.GUID = nodeData.GUID;
                    break;

                case NodeTypes.Decorator:
                    tempNode      = _targetGraphView.GenerateNode(nodeData.nodeTitle, nodeData.nodeName, (NodeTypes)nodeData.nodeType, Vector2.zero, nodeData.topNode, nodeData.decoratorInstance);
                    tempNode.GUID = nodeData.GUID;
                    break;

                case NodeTypes.Action:
                    tempNode      = _targetGraphView.GenerateNode(nodeData.nodeTitle, nodeData.nodeName, (NodeTypes)nodeData.nodeType, Vector2.zero, nodeData.topNode, nodeData.actionInstance);
                    tempNode.GUID = nodeData.GUID;
                    break;

                default:
                    break;
                }

                // Add ports to node based on node data. If it's a decorator node the port will be generated automatically so theres no need to add ports
                if (tempNode.nodeType != NodeTypes.Decorator)
                {
                    List <NodeLinkData> nodePorts = _containerCache.nodeLinks.Where(x => x.BaseNodeGuid == nodeData.GUID).ToList();
                    nodePorts.ForEach(x => _targetGraphView.AddPort(tempNode, x.PortName));
                }

                _targetGraphView.AddElement(tempNode);
            }
        }
Beispiel #7
0
        /// <summary>
        /// Generates and returns an node instance without adding it to the editor window
        /// </summary>
        /// <param name="nodeTitle"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public BTEditorNode GenerateNode(string nodeTitle, string nodeName, NodeTypes type, Vector2 position, bool isTopNode = false, AbstractNode instance = null)
        {
            BTEditorNode node = null;

            switch (type)
            {
            case NodeTypes.Composite:
                node = GenerateCompositeNode(nodeTitle, nodeName, position, isTopNode, instance);
                break;

            case NodeTypes.Decorator:
                node = GenerateDecoratorNode(nodeTitle, nodeName, position, isTopNode, instance);
                break;

            case NodeTypes.Action:
                node = GenerateActionNode(nodeTitle, nodeName, position, isTopNode, instance);
                break;

            default:
                break;
            }
            return(node);
        }
Beispiel #8
0
 // Generate a port
 private Port GeneratePort(BTEditorNode target, Direction portDir, Port.Capacity capacity = Port.Capacity.Single)
 {
     return(target.InstantiatePort(Orientation.Horizontal, portDir, capacity, typeof(float)));
 }
Beispiel #9
0
        // Generate decorator node
        private BTEditorNode GenerateDecoratorNode(string nodeTitle, string name, Vector2 position, bool isTopNode = false, AbstractNode instance = null)
        {
            BTEditorNode node = new BTEditorNode
            {
                title    = nodeTitle,
                nodeName = name,
                GUID     = System.Guid.NewGuid().ToString(),
                nodeType = NodeTypes.Decorator,
                topNode  = isTopNode
            };

            // Create new instance if not loading from already existing behaviour tree
            if (instance != null)
            {
                node.decoratorInstance = instance as Decorator;
            }
            else
            {
                node.decoratorInstance = ScriptableObject.CreateInstance(name) as Decorator;
            }

            // Stash and remove old title and minimize button elements
            Label oldTitleLabel = node.titleContainer.Q <Label>("title-label");

            node.titleContainer.Remove(oldTitleLabel);

            VisualElement oldTitleButton = node.titleContainer.Q <VisualElement>("title-button-container");

            node.titleContainer.Remove(oldTitleButton);

            // Create and add text field for title input
            TextField textField = new TextField
            {
                name  = string.Empty,
                value = node.title
            };

            textField.RegisterValueChangedCallback(evt => node.title = evt.newValue);
            node.titleContainer.Add(textField);
            node.titleContainer.Add(oldTitleButton); // Add back minimize button in title container after adding title input field

            // Input/Output port
            node.inputContainer.Add(GeneratePort(node, Direction.Input, Port.Capacity.Multi));
            node.outputContainer.Add(GeneratePort(node, Direction.Output, Port.Capacity.Multi));

            // Object field for behaviour instance
            ObjectField objectField = new ObjectField();

            objectField.objectType = typeof(ScriptableObject);
            objectField.value      = node.decoratorInstance;
            node.mainContainer.Add(objectField);

            // Node state element
            Label nodeStateLabel = new Label {
                name = "node-state-label", text = node.decoratorInstance.NodeState.ToString()
            };

            node.titleContainer.Add(nodeStateLabel);

            node.RefreshExpandedState();
            node.RefreshPorts();

            node.SetPosition(new Rect(position, defaultNodeSize));

            return(node);
        }
Beispiel #10
0
        // Generates entry point node at editor startup
        private BTEditorNode GenerateEntryPointNode(string nodeName)
        {
            // Instantiate new node
            BTEditorNode node = new BTEditorNode
            {
                title             = nodeName,
                nodeName          = "Selector",
                compositeInstance = (Composite)ScriptableObject.CreateInstance("Selector"),
                GUID     = System.Guid.NewGuid().ToString(),
                nodeType = NodeTypes.Composite,
                topNode  = true,
            };

            // Stash and remove old title and minimize button elements
            Label oldTitleLabel = node.titleContainer.Q <Label>("title-label");

            node.titleContainer.Remove(oldTitleLabel);

            VisualElement oldTitleButton = node.titleContainer.Q <VisualElement>("title-button-container");

            node.titleContainer.Remove(oldTitleButton);

            // Create and add text field for title input
            TextField textField = new TextField
            {
                name  = nodeName,
                value = "Top Node"
            };

            textField.RegisterValueChangedCallback(evt => node.title = evt.newValue);
            node.titleContainer.Add(textField);
            node.titleContainer.Add(oldTitleButton); // Add back minixmize button in title container after adding title input field

            // Node state element
            Label nodeStateLabel = new Label {
                name = "node-state-label", text = node.compositeInstance.NodeState.ToString()
            };

            node.titleContainer.Add(nodeStateLabel);

            // Instantiate add port button
            Button button = new Button(() => { AddPort(node); });

            button.text = "New Child Behaviour";
            node.titleContainer.Add(button);

            // Instance field
            ObjectField objectField = new ObjectField();

            objectField.objectType = typeof(ScriptableObject);
            objectField.value      = node.compositeInstance;
            node.mainContainer.Add(objectField);

            AddPort(node);
            AddPort(node);

            node.capabilities &= ~Capabilities.Movable;
            node.capabilities &= ~Capabilities.Deletable;

            // Refresh node
            node.RefreshExpandedState();
            node.RefreshPorts();

            node.SetPosition(new Rect(new Vector2(100, 200), defaultNodeSize));

            return(node);
        }