예제 #1
0
 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);
        }
예제 #3
0
        // 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);
        }
예제 #4
0
        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;
        }
예제 #5
0
        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());
            }
        }
예제 #6
0
        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);
            }
        }
예제 #7
0
        // 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();
        }
예제 #8
0
        /// <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;
        }
예제 #9
0
        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());
        }
예제 #11
0
        /// <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();
            }
        }
예제 #12
0
        // 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();
        }