public void ShouldListenToEvents_WhenUsingChildBlackboard()
        {
            Blackboard rootBlackboard = new Blackboard(clock);
            Blackboard blackboard     = new Blackboard(rootBlackboard, clock);

            // our mock nodes we want to query for status
            MockNode firstChild  = new MockNode(false); // false -> fail when aborted
            MockNode secondChild = new MockNode(false);

            // conditions for each subtree that listen the BB for events
            BlackboardCondition firstCondition  = new BlackboardCondition("branch1", Operator.IS_EQUAL, true, Stops.IMMEDIATE_RESTART, firstChild);
            BlackboardCondition secondCondition = new BlackboardCondition("branch2", Operator.IS_EQUAL, true, Stops.IMMEDIATE_RESTART, secondChild);

            // set up the tree
            Selector selector     = new Selector(firstCondition, secondCondition);
            TestRoot behaviorTree = new TestRoot(blackboard, clock, selector);

            // intially we want to activate branch2
            rootBlackboard.Set("branch2", true);

            // start the tree
            behaviorTree.Start();

            // tick the timer to ensure the blackboard notifies the nodes
            clock.Update(0.1f);

            // verify the second child is running
            Assert.AreEqual(Node.State.INACTIVE, firstChild.CurrentState);
            Assert.AreEqual(Node.State.ACTIVE, secondChild.CurrentState);

            // change keys so the first conditions get true, too
            rootBlackboard.Set("branch1", true);

            // tick the timer to ensure the blackboard notifies the nodes
            clock.Update(0.1f);

            // now we should be in branch1
            Assert.AreEqual(Node.State.ACTIVE, firstChild.CurrentState);
            Assert.AreEqual(Node.State.INACTIVE, secondChild.CurrentState);
        }
Beispiel #2
0
        public void ShouldNotActivateLowerPriorityBranchInCaseMultipleBranchesGetValid()
        {
            this.Timer      = new Clock();
            this.Blackboard = new Blackboard(Timer);

            // our mock nodes we want to query for status
            MockNode firstChild  = new MockNode(false); // false -> fail when aborted
            MockNode secondChild = new MockNode(false);
            MockNode thirdChild  = new MockNode(false);

            // coniditions for each subtree that listen the BB for events
            BlackboardCondition firstCondition  = new BlackboardCondition("branch1", Operator.IS_EQUAL, true, Stops.IMMEDIATE_RESTART, firstChild);
            BlackboardCondition secondCondition = new BlackboardCondition("branch2", Operator.IS_EQUAL, true, Stops.IMMEDIATE_RESTART, secondChild);
            BlackboardCondition thirdCondtion   = new BlackboardCondition("branch3", Operator.IS_EQUAL, true, Stops.IMMEDIATE_RESTART, thirdChild);

            // set up the tree
            Selector selector     = new Selector(firstCondition, secondCondition, thirdCondtion);
            TestRoot behaviorTree = new TestRoot(Blackboard, Timer, selector);

            // intially we want to activate branch3
            Blackboard.Set("branch3", true);

            // start the tree
            behaviorTree.Start();

            // verify the third child is running
            Assert.AreEqual(Node.State.INACTIVE, firstChild.CurrentState);
            Assert.AreEqual(Node.State.INACTIVE, secondChild.CurrentState);
            Assert.AreEqual(Node.State.ACTIVE, thirdChild.CurrentState);
            Assert.AreEqual(0, firstChild.DebugNumStartCalls);
            Assert.AreEqual(0, secondChild.DebugNumStartCalls);
            Assert.AreEqual(1, thirdChild.DebugNumStartCalls);

            // change keys so the first & second conditions get true, too
            Blackboard.Set("branch1", true);
            Blackboard.Set("branch2", true);

            // still the third child should be active, as the blackboard didn't yet notifiy the nodes
            Assert.AreEqual(Node.State.INACTIVE, firstChild.CurrentState);
            Assert.AreEqual(Node.State.INACTIVE, secondChild.CurrentState);
            Assert.AreEqual(Node.State.ACTIVE, thirdChild.CurrentState);
            Assert.AreEqual(0, firstChild.DebugNumStartCalls);
            Assert.AreEqual(0, secondChild.DebugNumStartCalls);
            Assert.AreEqual(1, thirdChild.DebugNumStartCalls);

            // tick the timer to ensure the blackboard notifies the nodes
            Timer.Update(0.1f);

            // now we should be in branch1
            Assert.AreEqual(Node.State.ACTIVE, firstChild.CurrentState);
            Assert.AreEqual(Node.State.INACTIVE, secondChild.CurrentState);
            Assert.AreEqual(Node.State.INACTIVE, thirdChild.CurrentState);
            Assert.AreEqual(1, firstChild.DebugNumStartCalls);
            Assert.AreEqual(0, secondChild.DebugNumStartCalls);
            Assert.AreEqual(1, thirdChild.DebugNumStartCalls);

            // disable first branch
            Blackboard.Set("branch1", false);
            Timer.Update(0.1f);

            // and now the second branch should be active
            Assert.AreEqual(Node.State.INACTIVE, firstChild.CurrentState);
            Assert.AreEqual(Node.State.ACTIVE, secondChild.CurrentState);
            Assert.AreEqual(Node.State.INACTIVE, thirdChild.CurrentState);
            Assert.AreEqual(1, firstChild.DebugNumStartCalls);
            Assert.AreEqual(1, secondChild.DebugNumStartCalls);
            Assert.AreEqual(1, thirdChild.DebugNumStartCalls);
        }
Beispiel #3
0
        private void DrawNode(Node node, int depth, bool connected)
        {
            float tStopRequested = Mathf.Lerp(0.85f, 0.25f, 2.0f * (Time.time - node.DebugLastStopRequestAt));
            float tStopped       = Mathf.Lerp(0.85f, 0.25f, 2.0f * (Time.time - node.DebugLastStoppedAt));
            bool  inactive       = node.CurrentState != Node.State.ACTIVE;
            float alpha          = inactive ? Mathf.Max(0.35f, Mathf.Pow(tStopped, 1.5f)) : 1.0f;
            bool  failed         = (tStopped > 0.25f && tStopped < 1.0f && !node.DebugLastResult && inactive);
            bool  stopRequested  = (tStopRequested > 0.25f && tStopRequested < 1.0f && inactive);

            EditorGUILayout.BeginHorizontal();
            {
                GUI.color = new Color(1f, 1f, 1f, alpha);

                string   tagName;
                GUIStyle tagStyle = stopRequested ? nodeCapsuleStopRequested : (failed ? nodeCapsuleFailed : nodeCapsuleGray);

                bool   drawLabel = !string.IsNullOrEmpty(node.Label);
                string label     = node.Label;

                if (node is BlackboardCondition)
                {
                    BlackboardCondition nodeBlackboardCond = node as BlackboardCondition;
                    tagName             = nodeBlackboardCond.Key + " " + operatorToString[nodeBlackboardCond.Operator] + " " + nodeBlackboardCond.Value;
                    GUI.backgroundColor = new Color(0.9f, 0.9f, 0.6f);
                }
                else
                {
                    if (node is Composite)
                    {
                        GUI.backgroundColor = new Color(0.3f, 1f, 0.1f);
                    }
                    if (node is Decorator)
                    {
                        GUI.backgroundColor = new Color(0.3f, 1f, 1f);
                    }
                    if (node is Task)
                    {
                        GUI.backgroundColor = new Color(0.5f, 0.1f, 0.5f);
                    }
                    if (node is ObservingDecorator)
                    {
                        GUI.backgroundColor = new Color(0.9f, 0.9f, 0.6f);
                    }

                    nameToTagString.TryGetValue(node.Name, out tagName);
                }

                if ((node is Container) && ((Container)node).Collapse)
                {
                    if (!drawLabel)
                    {
                        drawLabel = true;
                        label     = tagName;
                    }
                    tagName             = "...";
                    GUI.backgroundColor = new Color(0.4f, 0.4f, 0.4f);
                }

                if (string.IsNullOrEmpty(tagName))
                {
                    tagName = node.Name;
                }

                if (!drawLabel)
                {
                    GUILayout.Label(tagName, tagStyle);
                }
                else
                {
                    GUILayout.Label("(" + tagName + ") " + label, tagStyle);
                    // Reset background color
                    GUI.backgroundColor = Color.white;
                }

                GUILayout.FlexibleSpace();

                // Draw Buttons
                if (node.CurrentState == Node.State.ACTIVE)
                {
                    if (GUILayout.Button("stop", EditorStyles.miniButton))
                    {
                        node.Stop();
                    }
                }
                else if (node is Root)
                {
                    GUI.color = new Color(1f, 1f, 1f, 1f);
                    if (GUILayout.Button("start", EditorStyles.miniButton))
                    {
                        node.Start();
                    }
                    GUI.color = new Color(1f, 1f, 1f, 0.3f);
                }

                // Draw Stats
                GUILayout.Label((node.DebugNumStoppedCalls > 0 ? node.DebugLastResult.ToString() : "") + " | " + node.DebugNumStartCalls + " , " + node.DebugNumStopCalls + " , " + node.DebugNumStoppedCalls, smallTextStyle);
            }

            EditorGUILayout.EndHorizontal();

            // Draw the lines
            if (connected)
            {
                Rect rect = GUILayoutUtility.GetLastRect();

                Handles.color = new Color(0f, 0f, 0f, 1f);
                Handles.BeginGUI();
                float midY = 4 + (rect.yMin + rect.yMax) / 2f;
                Handles.DrawLine(new Vector2(rect.xMin - 5, midY), new Vector2(rect.xMin, midY));
                Handles.EndGUI();
            }
        }