/// <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(); }
// 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(); } }
// 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); }
// 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); }