public void SetBehaviourTree(BehaviourTree tree) { NodeSelection.ClearSelection(); Canvas = new BonsaiCanvas(tree); Viewer.Canvas = Canvas; Viewer.NodeSelection = NodeSelection; Viewer.zoom = tree.zoomPosition; Viewer.panOffset = tree.panPosition; }
public static BonsaiNode DuplicateSingle(BonsaiCanvas canvas, BonsaiNode original) { BonsaiNode duplicate = canvas.CreateNode(original.Behaviour.GetType()); // Duplicate nodes are placed offset from the original. duplicate.Position = original.Position + Vector2.one * 40f; return(duplicate); }
// Adds the tree to the database and saves the nodes to the database. private void SaveNewTree(string path, TreeMetaData meta, BonsaiCanvas canvas) { // Save tree and black board assets AssetDatabase.CreateAsset(canvas.Tree, path); AssetDatabase.AddObjectToAsset(canvas.Tree.Blackboard, canvas.Tree); // Save nodes. SaveTree(meta, canvas); }
private void SaveTreeMetaData(TreeMetaData meta, BonsaiCanvas canvas) { foreach (var editorNode in canvas.Nodes) { editorNode.Behaviour.bonsaiNodePosition = editorNode.Position; } canvas.Tree.panPosition = meta.pan; canvas.Tree.zoomPosition = meta.zoom; }
private void SetCompositeChildren(BonsaiCanvas canvas) { IEnumerable <BonsaiNode> compositeNodes = canvas.Nodes.Where(n => n.Behaviour.IsComposite()); foreach (BonsaiNode node in compositeNodes) { var compositeBehaviour = node.Behaviour as Composite; compositeBehaviour.SetChildren(node.Children.Select(ch => ch.Behaviour).ToArray()); } }
private void SetDecoratorChildren(BonsaiCanvas canvas) { IEnumerable <BonsaiNode> decoratorNodes = canvas.Nodes .Where(n => n.Behaviour.IsDecorator() && n.ChildCount() == 1); foreach (BonsaiNode node in decoratorNodes) { var decoratorBehaviour = node.Behaviour as Decorator; decoratorBehaviour.SetChild(node.GetChildAt(0).Behaviour); } }
// Saves the current tree and nodes. private void SaveTree(TreeMetaData meta, BonsaiCanvas canvas) { // If the blackboard is not yet in the database, then add. AddBlackboardIfMissing(canvas.Tree); var treeBehaviours = canvas.Tree.AllNodes; var canvasBehaviours = canvas.Nodes.Select(n => n.Behaviour); // New nodes that need to be added to the database. foreach (BehaviourNode newNodes in canvasBehaviours.Except(treeBehaviours)) { newNodes.name = newNodes.GetType().Name; newNodes.hideFlags = HideFlags.HideInHierarchy; AssetDatabase.AddObjectToAsset(newNodes, canvas.Tree); } // Clear all parent-child connections. These will be reconstructed to match the connection in the BonsaiNodes. canvas.Tree.ClearStructure(); // Sort the canvas. // Only consider nodes with 2 or more children for sorting. foreach (BonsaiNode node in canvas.Nodes.Where(node => node.ChildCount() > 1)) { node.SortChildren(); } // Set parent-child connections matching those in the canvas. Only consider decorators and composites. foreach (BonsaiNode node in canvas.Nodes.Where(node => node.ChildCount() > 0)) { foreach (BonsaiNode child in node.Children) { node.Behaviour.AddChild(child.Behaviour); } } // Re-add nodes to tree. foreach (BonsaiNode node in canvas.Nodes) { node.Behaviour.Tree = canvas.Tree; } if (canvas.Root != null) { canvas.Tree.Root = canvas.Root.Behaviour; } // Sort the nodes in pre order so it is easier to clone the tree. canvas.Tree.SortNodes(); SaveTreeMetaData(meta, canvas); AssetDatabase.SaveAssets(); }
/// <summary> /// Create a new node for the first time. /// </summary> /// <param name="parentCanvas">The canvas that the node belongs to.</param> /// <param name="bCreateInput">If the node should have an input.</param> /// <param name="bCreateOuput">If the node should have an output.</param> public BonsaiNode(BonsaiCanvas parentCanvas, bool bCreateInput, bool bCreateOuput, bool bCanHaveMultipleChildren) { bodyRect = new Rect(Vector2.zero, kDefaultSize); if (bCreateInput) { _inputKnob = new BonsaiInputKnob(); _inputKnob.parentNode = this; } if (bCreateOuput) { _outputKnob = new BonsaiOutputKnob(); _outputKnob.parentNode = this; } this.bCanHaveMultipleChildren = bCanHaveMultipleChildren; }
private void onMultiNodeCallback(object o) { NodeContext context = (NodeContext)o; switch (context) { case NodeContext.DuplicateSelection: BonsaiCanvas canvas = _window.editor.canvas; BehaviourTree bt = _window.tree; for (int i = 0; i < _selectedNodes.Count; ++i) { // The original nodes will become selected. BonsaiNode node = _selectedNodes[i]; node.bAreaSelectionFlag = false; Type t = node.behaviour.GetType(); // Duplicate nodes become selected and are spawned // at offset from their original. BonsaiNode duplicate = canvas.CreateNode(t, bt); duplicate.bAreaSelectionFlag = true; duplicate.bodyRect.position = node.bodyRect.position + Vector2.one * 40f; // Replace in the list with new selections. _selectedNodes[i] = duplicate; } // Notify inspector about the new selections. setSelectedInInspector(); break; case NodeContext.DeleteSelection: _window.editor.canvas.RemoveSelected(); clearAreaSelection(); setTreeAsSelected(); break; } }
/// <summary> /// Duplicate multiple nodes and preserve the connections between parent and child nodes. /// </summary> /// <param name="canvas"></param> /// <param name="tree"></param> /// <param name="originals"></param> /// <returns></returns> public static List <BonsaiNode> DuplicateMultiple(BonsaiCanvas canvas, IEnumerable <BonsaiNode> originals) { var duplicateMap = originals.ToDictionary(og => og, og => DuplicateSingle(canvas, og)); // Reconstruct connection in clone nodes. foreach (BonsaiNode original in originals) { for (int i = 0; i < original.ChildCount(); i++) { // Only consider children if they were also cloned. if (duplicateMap.TryGetValue(original.GetChildAt(i), out BonsaiNode cloneChild)) { BonsaiNode cloneParent = duplicateMap[original]; cloneChild.SetParent(cloneParent); } } } return(duplicateMap.Values.ToList()); }
/// <summary> /// Saves the behaviour tree from the canvas. /// If the tree is unsaved (new) then it prompts the user to specify a file to save. /// </summary> /// <param name="canvas"></param> public void SaveCanvas(BonsaiCanvas canvas, TreeMetaData meta) { // Tree is new, need to save to asset database. if (!AssetDatabase.Contains(canvas.Tree)) { GetSaveFilePath() .OnSuccess(savePath => { SaveNewTree(savePath, meta, canvas); OnTreeSaved(); }) .OnFailure(OnInvalidPathError); } // Tree is already saved. Save nodes and tree data. else { SaveTree(meta, canvas); OnTreeSaved(); } }
// Saves the current tree and nodes. private void SaveTree(TreeMetaData meta, BonsaiCanvas canvas) { // If the blackboard is not yet in the database, then add. AddBlackboardIfMissing(canvas.Tree); var canvasBehaviours = canvas.Nodes.Select(n => n.Behaviour); AddNewNodeAssets(canvas.Tree, canvasBehaviours); // Clear all parent-child connections. These will be reconstructed to match the connection in the BonsaiNodes. canvas.Tree.ClearStructure(); // Sort the canvas. // Only consider nodes with 2 or more children for sorting. foreach (BonsaiNode node in canvas.Nodes.Where(node => node.ChildCount() > 1)) { node.SortChildren(); } // Set parent-child connections matching those in the canvas. Only consider decorators and composites. SetCompositeChildren(canvas); SetDecoratorChildren(canvas); // Re-add nodes to tree. if (canvas.Root != null) { canvas.Tree.SetNodes(canvas.Root.Behaviour); } // Nodes not connected to he root will have an unset pre-order index. // Tree.ClearStructure unsets the index and is only set in Tree.SetNodes // for nodes under the root. canvas.Tree.unusedNodes = canvasBehaviours.Where( b => b.PreOrderIndex == BehaviourNode.kInvalidOrder).ToList(); SaveTreeMetaData(meta, canvas); AssetDatabase.SaveAssets(); }