Exemplo n.º 1
0
        public BehaviourTreeBuilder Build(BehaviourTreeBuilder builder, params object[] args)
        {
            NWCreature self = (NWCreature)args[0];

            return(builder.Do("RandomWalk", t =>
            {
                if (self.IsInCombat || !_enmity.IsEnmityTableEmpty(self))
                {
                    if (_.GetCurrentAction(self.Object) == NWScript.ACTION_RANDOMWALK)
                    {
                        self.ClearAllActions();
                    }

                    return BehaviourTreeStatus.Failure;
                }

                if (_.GetCurrentAction(self.Object) == NWScript.ACTION_INVALID &&
                    _.IsInConversation(self.Object) == NWScript.FALSE &&
                    _.GetCurrentAction(self.Object) != NWScript.ACTION_RANDOMWALK &&
                    _random.Random(100) <= 25)
                {
                    self.AssignCommand(() => _.ActionRandomWalk());
                }
                return BehaviourTreeStatus.Running;
            }));
        }
        public void RepeatUntilStatusReachedNodeTest()
        {
            var root = new BehaviourTreeBuilder <TestBlackboard>()
                       .UntilSucceess("Repeat until success")
                       .Do("Reach limit", TestActions.ReachLimitAction)
                       .End()
                       .Build();
            var metadata   = new BehaviourTreeMetadata <TestBlackboard>(root);
            var data       = metadata.CreateExecutionData();
            var executor   = new BehaviourTreeExecutor <TestBlackboard>(root);
            var blackboard = new TestBlackboard();

            executor.Start(data);

            executor.Tick(data, blackboard);
            Assert.AreEqual(BehaviourTreeStatus.Running, data.Statuses[root.Id]);
            Assert.AreEqual(1, blackboard.Counter1);

            executor.Tick(data, blackboard);
            Assert.AreEqual(BehaviourTreeStatus.Running, data.Statuses[root.Id]);
            Assert.AreEqual(2, blackboard.Counter1);

            executor.Tick(data, blackboard);
            Assert.AreEqual(BehaviourTreeStatus.Success, data.Statuses[root.Id]);
            Assert.AreEqual(3, blackboard.Counter1);
            Assert.AreEqual(0, data.Stack.Count);
        }
Exemplo n.º 3
0
        public BehaviourTreeBuilder Build(BehaviourTreeBuilder builder, params object[] args)
        {
            NWCreature self = (NWCreature)args[0];

            return(builder.Do("AttackHighestEnmity", t =>
            {
                var enmityTable = _enmity.GetEnmityTable(self);

                var target = enmityTable.Values
                             .OrderByDescending(o => o.TotalAmount)
                             .FirstOrDefault(x => x.TargetObject.IsValid &&
                                             x.TargetObject.Area.Equals(self.Area));

                self.AssignCommand(() =>
                {
                    if (target == null)
                    {
                        _.ClearAllActions();
                    }
                    else
                    {
                        if (_.GetAttackTarget(self.Object) != target.TargetObject.Object)
                        {
                            _.ClearAllActions();
                            _.ActionAttack(target.TargetObject.Object);
                        }
                    }
                });

                return BehaviourTreeStatus.Running;
            }));
        }
        public void SelectorRunningTest()
        {
            var tickProvider = new TestTickSupplier();
            var root         = new BehaviourTreeBuilder <TestBlackboard>()
                               .Selector("Sequence")
                               .AlwaysFail("Fail increment")
                               .Do("Increment counter 1", TestActions.IncrementCounter1)
                               .End()
                               .Wait("Wait 1 tick", 1, tickProvider)
                               .Do("Increment counter 2", TestActions.IncrementCounter2)
                               .End()
                               .Build();
            var metadata   = new BehaviourTreeMetadata <TestBlackboard>(root);
            var data       = metadata.CreateExecutionData();
            var executor   = new BehaviourTreeExecutor <TestBlackboard>(root);
            var blackboard = new TestBlackboard();

            executor.Start(data);

            executor.Tick(data, blackboard);
            Assert.AreEqual(BehaviourTreeStatus.Running, data.Statuses[root.Id]);
            Assert.AreEqual(1, blackboard.Counter1);
            Assert.AreEqual(0, blackboard.Counter2);

            tickProvider.Tick();
            executor.Tick(data, blackboard);
            Assert.AreEqual(BehaviourTreeStatus.Success, data.Statuses[root.Id]);
            Assert.AreEqual(1, blackboard.Counter1);
            Assert.AreEqual(0, blackboard.Counter2);
            Assert.AreEqual(0, data.Stack.Count);
        }
        public static BehaviourTreeBuilder Do <T>(this BehaviourTreeBuilder builder, params object[] args)
            where T : IAIComponent
        {
            var component = App.ResolveByInterface <IAIComponent>(typeof(T).ToString());

            return(component.Build(builder, args));
        }
        public void InterruptionTest()
        {
            var tickProvider = new TestTickSupplier();
            var root         = new BehaviourTreeBuilder <TestBlackboard>()
                               .Sequence("Sequence")
                               .Inverter("Inverter")
                               .Do("Reach limit", TestActions.ReachLimitAction)
                               .End()
                               .Wait("Wait 5 ticks", 5, tickProvider)
                               .End()
                               .Build();
            var metadata   = new BehaviourTreeMetadata <TestBlackboard>(root);
            var data       = metadata.CreateExecutionData();
            var executor   = new BehaviourTreeExecutor <TestBlackboard>(root);
            var blackboard = new TestBlackboard();

            executor.Start(data);

            for (var i = 0; i < 5; i++)
            {
                executor.Tick(data, blackboard);
                Assert.AreEqual(BehaviourTreeStatus.Running, data.Statuses[root.Id]);
                Assert.AreEqual(1, blackboard.Counter1);
                tickProvider.Tick();
            }

            executor.Tick(data, blackboard);
            Assert.AreEqual(BehaviourTreeStatus.Success, data.Statuses[root.Id]);
            Assert.AreEqual(1, blackboard.Counter1);
            Assert.AreEqual(0, data.Stack.Count);
        }
Exemplo n.º 7
0
        private static void BuildRecursive(BehaviourTreeBuilder builder, BehaviourTreeData data)
        {
            if (!Mapping.ContainsKey(data.Type))
            {
                throw new Exception($"Unknown node type {data.Type}");
            }

            var node   = CreateNodeByType(Mapping[data.Type], data.Properties);
            var parent = node as IBehaviourTreeNodeParent;

            if (parent != null)
            {
                builder.AddParent(parent);
            }
            else
            {
                builder.AddChild(node);
            }

            foreach (var childData in data.Children)
            {
                BuildRecursive(builder, childData);
            }

            if (parent != null)
            {
                builder.End();
            }
        }
        public void InvertRunningTest()
        {
            var tickProvider = new TestTickSupplier();
            var root         = new BehaviourTreeBuilder <TestBlackboard>()
                               .Inverter("Invert status")
                               .Wait("Increment counter 1", 3, tickProvider)
                               .End()
                               .Build();
            var metadata   = new BehaviourTreeMetadata <TestBlackboard>(root);
            var data       = metadata.CreateExecutionData();
            var executor   = new BehaviourTreeExecutor <TestBlackboard>(root);
            var blackboard = new TestBlackboard();

            executor.Start(data);

            executor.Tick(data, blackboard);
            Assert.AreEqual(BehaviourTreeStatus.Running, data.Statuses[root.Id]);

            tickProvider.Tick();
            executor.Tick(data, blackboard);
            Assert.AreEqual(BehaviourTreeStatus.Running, data.Statuses[root.Id]);

            tickProvider.Tick();
            executor.Tick(data, blackboard);
            Assert.AreEqual(BehaviourTreeStatus.Running, data.Statuses[root.Id]);

            tickProvider.Tick();
            executor.Tick(data, blackboard);
            Assert.AreEqual(BehaviourTreeStatus.Failure, data.Statuses[root.Id]);
            Assert.AreEqual(0, data.Stack.Count);
        }
Exemplo n.º 9
0
        public BehaviourTreeBuilder Build(BehaviourTreeBuilder builder, params object[] args)
        {
            NWCreature self = (NWCreature)args[0];

            return(builder.Do("CleanUpEnmity", t =>
            {
                foreach (var enmity in _enmity.GetEnmityTable(self).ToArray())
                {
                    var val = enmity.Value;
                    var target = val.TargetObject;

                    // Remove invalid objects from the enmity table
                    if (target == null ||
                        !target.IsValid ||
                        !target.Area.Equals(self.Area) ||
                        target.CurrentHP <= -11)
                    {
                        _enmity.GetEnmityTable(self).Remove(enmity.Key);
                        continue;
                    }

                    _.AdjustReputation(target.Object, self.Object, -100);

                    // Reduce volatile enmity every tick
                    _enmity.GetEnmityTable(self)[target.GlobalID].VolatileAmount--;
                }

                return BehaviourTreeStatus.Running;
            }));
        }
    void Start()
    {
        behaviorController = GetComponent <BehaviorController>();
        var builder = new BehaviourTreeBuilder();

        tree = builder.Sequence("gatherResources").Splice(CreateGatherTreeSequence())
               .End()
               .Build();
    }
Exemplo n.º 11
0
 public PackAggroBehaviour(
     BehaviourTreeBuilder builder,
     INWScript script,
     IEnmityService enmity,
     IDialogService dialog,
     INWNXObject nwnxObject)
     : base(builder, script, enmity, dialog, nwnxObject)
 {
 }
Exemplo n.º 12
0
        public override BehaviourTree ToEntity(BehaviourTreeData data)
        {
            var builder = new BehaviourTreeBuilder();

            BuildRecursive(builder, data);

            var tree = builder.Build();

            tree.Id = data.Id;

            return(tree);
        }
        public static BehaviourTreeBuilder Do <T>(this BehaviourTreeBuilder builder, params object[] args)
            where T : IRegisteredEvent
        {
            return(builder.Do(typeof(T).ToString(), t =>
            {
                bool success = App.RunEvent <T>(args);

                return success ?
                BehaviourTreeStatus.Running :
                BehaviourTreeStatus.Failure;
            }));
        }
Exemplo n.º 14
0
 public StandardBehaviour(BehaviourTreeBuilder builder,
                          INWScript script,
                          IEnmityService enmity,
                          IDialogService dialog,
                          INWNXObject nwnxObject)
 {
     _           = script;
     _builder    = builder;
     _enmity     = enmity;
     _dialog     = dialog;
     _nwnxObject = nwnxObject;
 }
    private IBehaviourTreeNode CreateGatherTreeSequence()
    {
        var builder = new BehaviourTreeBuilder();

        return(builder.Sequence("gatherResources")
               .Do("changeColor", t => {
            behaviorController.ChangeColor(Color.magenta);
            return BehaviourTreeStatus.Success;
        })

               .Do("findNearestResource", t =>
        {
            if (behaviorController.needsResource)
            {
                target = behaviorController.GetNextResource();
                behaviorController.ai.target = target;
                behaviorController.hasTarget = true;
                behaviorController.needsResource = false;
                return BehaviourTreeStatus.Success;
            }
            else
            {
                return BehaviourTreeStatus.Success;
            }
        })
               .Do("goToResource", t =>
        {
            while (behaviorController.hasTarget && !behaviorController.ai.DestinationReached() && behaviorController.ai.target.tag == "resource")
            {
                return BehaviourTreeStatus.Failure;      //presumably we pause here
            }
            behaviorController.hasTarget = false;
            behaviorController.needsResource = true;
            return BehaviourTreeStatus.Success;
        })
               .Do("checkIfAllResourcesAreGathered", t => {
            if (behaviorController.allResourcesGathered && behaviorController.ai.DestinationReached())
            {
                return BehaviourTreeStatus.Success;
            }
            else
            {
                Debug.Log("All resouces found");
                return BehaviourTreeStatus.Failure;
            }
        })
               .End()
               .Build());
    }
Exemplo n.º 16
0
    void Start()
    {
        Debug.Log("ZombieBT start");

        var builder = new BehaviourTreeBuilder();

//        var targetPosition = GameObject.Find("Player").transform.position;
        targetPosition = GameObject.Find("Player").transform.position;

        this.tree = builder
                    .Selector("ChooseAction")
                    .Sequence("tryToGoToPlayer")
                    // If player is alive and close then go to it
                    .Condition("isPlayerClose", t => (BlackboardZombie.Instance.getIsPlayerAlive() == true && Vector3.Distance(transform.position, targetPosition) < 8 &&
                                                      Vector3.Distance(transform.position, targetPosition) > 2))
                    .Do("GoToPlayer", t =>
        {
            GetComponent <Animator>().SetBool("bool_walk", true);
            GetComponent <Animator>().SetBool("bool_attack", false);
            Debug.Log("~~~ GoToPlayer");
            BehaviourTreeStatus bts;
            bts = GoToTarget("target1", targetPosition);
            BlackboardZombie.Instance.setTarget1(bts == BehaviourTreeStatus.Success);
            return(bts);
        })
                    .End()
                    .Sequence("tryToAttackPlayer")
                    // If player is alive and in range then attack him
                    .Condition("isPlayerInRange", t => (BlackboardZombie.Instance.getIsPlayerAlive() == true && Vector3.Distance(transform.position, targetPosition) <= 2))
                    .Do("AttackPlayer", t =>
        {
            GetComponent <Animator>().SetBool("bool_walk", false);
            GetComponent <Animator>().SetBool("bool_attack", true);
            Debug.Log("~~~ AttackPlayer");
            return(AttackPlayer());
        })
                    .End()
                    .Do("Wander", t =>
        {
            GetComponent <Animator>().SetBool("bool_walk", true);
            GetComponent <Animator>().SetBool("bool_attack", false);
            GetComponent <SteerForWander>().enabled = true;
            Debug.Log("~~~ Wander");
            return(Wander());
        })
                    .End()
                    .Build();
    }
Exemplo n.º 17
0
        public CrocoBehaviour(CrocoLoco _crocoLoco)
        {
            crocoLoco = _crocoLoco;
            var builder = new BehaviourTreeBuilder();

            tree = builder
                   .Selector("Watch players")
                   .Condition("Is any player visible", IsAnyPlayerVisible)

                   .End()
                   .Build();
            timeData = new TimeData();

            properties             = new CrocoProperties();
            properties.watchLength = 300;
        }
Exemplo n.º 18
0
    protected override void Start()
    {
        BehaviourTreeBuilder treeBuilder = new BehaviourTreeBuilder();

        this.rootNode = treeBuilder.Selector("SomeSelector", true)
                        .Do("some-action-1", t => {
            return(BehaviourTreeStatus.Success);
        })
                        .Do("some-action-2", t => {
            return(BehaviourTreeStatus.Success);
        })
                        .End()
                        .Build();

        this.rootNode = this.BuildSimpleAI();
        base.Start();
    }
Exemplo n.º 19
0
        public void disabled_parent_nodes_is_ignored()
        {
            TimeData data        = new TimeData(0);
            var      invokeCount = 0;

            var builder = new BehaviourTreeBuilder <TimeData>(new List <int>
            {
                0,
                2,
                4
            });

            builder
            .Sequence("seq1")
            .Do("do1", t =>
            {
                ++invokeCount;
                throw new Exception("do1 invoked.");
            })
            .End()
            .Build()
            .Tick(data);

            builder
            .Selector("sel1")
            .Do("do2", t =>
            {
                ++invokeCount;
                throw new Exception("do2 invoked.");
            })
            .End()
            .Build()
            .Tick(data);

            builder
            .Parallel("para1", 0, 0)
            .Do("do3", t =>
            {
                ++invokeCount;
                throw new Exception("do3 invoked.");
            })
            .End()
            .Build()
            .Tick(data);
        }
        public void ActionTest()
        {
            var root = new BehaviourTreeBuilder <TestBlackboard>()
                       .Do("Increment counter 1", TestActions.IncrementCounter1)
                       .Build();
            var metadata   = new BehaviourTreeMetadata <TestBlackboard>(root);
            var data       = metadata.CreateExecutionData();
            var executor   = new BehaviourTreeExecutor <TestBlackboard>(root);
            var blackboard = new TestBlackboard();

            executor.Start(data);
            executor.Tick(data, blackboard);
            var status = data.Statuses[root.Id];

            Assert.AreEqual(BehaviourTreeStatus.Success, status);
            Assert.AreEqual(1, blackboard.Counter1);
            Assert.AreEqual(0, data.Stack.Count);
        }
Exemplo n.º 21
0
        public BehaviourTreeBuilder Build(BehaviourTreeBuilder builder, params object[] args)
        {
            return(builder.Do("EquipBestMelee", t =>
            {
                NWCreature self = (NWCreature)args[0];
                if (!self.IsInCombat ||
                    self.RightHand.IsRanged)
                {
                    return BehaviourTreeStatus.Failure;
                }

                self.AssignCommand(() =>
                {
                    _.ActionEquipMostDamagingMelee(new Object());
                });

                return BehaviourTreeStatus.Running;
            }));
        }
Exemplo n.º 22
0
    void Awake()
    {
        BehaviourTreeBuilder treeBuilder = new BehaviourTreeBuilder();

        this.rootNode = treeBuilder.Selector("SomeSelector", true)
                        .Do("some-action-1", t => {
            if (this.IsTrue)
            {
                ++invokeCount;
            }
            return(this.IsTrue ? BehaviourTreeStatus.Success : BehaviourTreeStatus.Failure);
        })
                        .Do("some-action-2", t => {
            if (!this.IsTrue)
            {
                --invokeCount;
            }
            return(this.IsTrue ? BehaviourTreeStatus.Failure : BehaviourTreeStatus.Success);
        })
                        .End()
                        .Build();
    }
Exemplo n.º 23
0
        public BehaviourTreeBuilder Build(BehaviourTreeBuilder builder, params object[] args)
        {
            return(builder.Do("AggroTargetBySound", t =>
            {
                NWCreature self = (NWCreature)args[0];

                if (self.IsInCombat)
                {
                    return BehaviourTreeStatus.Failure;
                }

                float aggroRange = self.GetLocalFloat("AGGRO_RANGE");
                if (aggroRange <= 0.0f)
                {
                    aggroRange = 5.0f;
                }

                int nth = 1;
                NWCreature creature = NWCreature.Wrap(_.GetNearestObject(NWScript.OBJECT_TYPE_CREATURE, self.Object, nth));
                while (creature.IsValid)
                {
                    if (_.GetIsEnemy(creature.Object, self.Object) == NWScript.TRUE &&
                        !_enmity.IsOnEnmityTable(self, creature) &&
                        !creature.HasAnyEffect(NWScript.EFFECT_TYPE_SANCTUARY) &&
                        _.GetDistanceBetween(self.Object, creature.Object) <= aggroRange &&
                        _.LineOfSightObject(self.Object, creature.Object) == NWScript.TRUE)
                    {
                        _enmity.AdjustEnmity(self, creature, 0, 1);
                    }

                    nth++;
                    creature = NWCreature.Wrap(_.GetNearestObject(NWScript.OBJECT_TYPE_CREATURE, self.Object, nth));
                }


                return BehaviourTreeStatus.Running;
            }));
        }
Exemplo n.º 24
0
    private void Start()
    {
        var builder = new BehaviourTreeBuilder();

        //if Dist < 0.5 doA else doB
        tree = builder.
               Parallel("All", 20, 20).
               Do("RoateX", t => {
            transform.GetChild(0).Rotate(new Vector3(60, 0) * Time.deltaTime);
            return(BehaviourTreeStatus.Success);
        }).
               Do("RoateZ", t => {
            transform.GetChild(0).Rotate(new Vector3(0, 0, 60) * Time.deltaTime);
            return(BehaviourTreeStatus.Success);
        }).
               Selector("Find Target").
               Sequence("At Target").
               Condition("At Target", t => {
            Debug.Log("Is At Target");
            var dist = Vector3.Distance(transform.position, target.position);
            return(dist < 0.5f);
        }).
               Do("Idle", t => {
            Debug.Log("Idle");
            return(BehaviourTreeStatus.Success);
        }).
               End().
               Do("Go to Target", t =>
        {
            Debug.Log("Go to target");
            var dist            = Vector3.Distance(transform.position, target.position);
            transform.position += (target.position - transform.position).normalized * speed * Time.deltaTime;
            return(BehaviourTreeStatus.Success);
        }).
               End().
               End().
               Build();
    }
Exemplo n.º 25
0
        public BehaviourTreeBuilder Build(BehaviourTreeBuilder builder, params object[] args)
        {
            return(builder.Do("AggroTargetBySight", t =>
            {
                NWCreature self = (NWCreature)args[0];

                if (self.IsInCombat)
                {
                    return BehaviourTreeStatus.Failure;
                }

                float aggroRange = self.GetLocalFloat("AGGRO_RANGE");
                if (aggroRange <= 0.0f)
                {
                    aggroRange = 10.0f;
                }
                Location targetLocation = _.Location(
                    self.Area.Object,
                    _biowarePos.GetChangedPosition(self.Position, aggroRange, self.Facing),
                    self.Facing + 180.0f);

                NWCreature creature = NWCreature.Wrap(_.GetFirstObjectInShape(NWScript.SHAPE_SPELLCYLINDER, aggroRange, targetLocation, NWScript.TRUE, NWScript.OBJECT_TYPE_CREATURE, self.Position));
                while (creature.IsValid)
                {
                    if (_.GetIsEnemy(creature.Object, self.Object) == NWScript.TRUE &&
                        !_enmity.IsOnEnmityTable(self, creature) &&
                        _.GetDistanceBetween(self.Object, creature.Object) <= aggroRange &&
                        !creature.HasAnyEffect(NWScript.EFFECT_TYPE_INVISIBILITY, NWScript.EFFECT_TYPE_SANCTUARY))
                    {
                        _enmity.AdjustEnmity(self, creature, 0, 1);
                    }

                    creature = NWCreature.Wrap(_.GetNextObjectInShape(NWScript.SHAPE_SPELLCYLINDER, aggroRange, targetLocation, NWScript.TRUE, NWScript.OBJECT_TYPE_CREATURE, self.Position));
                }

                return BehaviourTreeStatus.Running;
            }));
        }
        public void SequenceFailureTest()
        {
            var root = new BehaviourTreeBuilder <TestBlackboard>()
                       .Sequence("Sequence")
                       .AlwaysFail("Fail")
                       .Do("Increment counter 1", TestActions.IncrementCounter1)
                       .End()
                       .Do("Increment counter 2", TestActions.IncrementCounter2)
                       .End()
                       .Build();
            var metadata   = new BehaviourTreeMetadata <TestBlackboard>(root);
            var data       = metadata.CreateExecutionData();
            var executor   = new BehaviourTreeExecutor <TestBlackboard>(root);
            var blackboard = new TestBlackboard();

            executor.Start(data);

            executor.Tick(data, blackboard);
            Assert.AreEqual(BehaviourTreeStatus.Failure, data.Statuses[root.Id]);
            Assert.AreEqual(1, blackboard.Counter1);
            Assert.AreEqual(0, blackboard.Counter2);
            Assert.AreEqual(0, data.Stack.Count);
        }
        public BehaviourTree Create(
            IActorStateModel actor,
            AiMovementController aiMovementController)
        {
            _actorStateModel      = actor;
            _aiMovementController = aiMovementController;
            _generatedNodes       = new List <IBehaviourTreeNode>();

            // @formatter:off
            var startNode = new BehaviourTreeBuilder()
                            .Selector()
                            .Splice(SpawningTree(actor))
                            .Splice(UnacquaintedTree(actor))
                            .Splice(NeutralTree(actor))
                            .Splice(FriendTree(actor))
                            .Splice(EnemyTree(actor))
                            .End()
                            .Build();

            // @formatter:on

            return(new BehaviourTree(startNode, _generatedNodes.ToArray()));
        }
        public void IfNodeFailTest()
        {
            var root = new BehaviourTreeBuilder <TestBlackboard>()
                       .If("If false", TestActions.True)
                       .AlwaysFail("Fail")
                       .Do("Increment counter 1", TestActions.IncrementCounter1)
                       .End()
                       .End()
                       .Build();
            var metadata   = new BehaviourTreeMetadata <TestBlackboard>(root);
            var data       = metadata.CreateExecutionData();
            var executor   = new BehaviourTreeExecutor <TestBlackboard>(root);
            var blackboard = new TestBlackboard();

            executor.Start(data);
            executor.Tick(data, blackboard);

            var status = data.Statuses[root.Id];

            Assert.AreEqual(BehaviourTreeStatus.Failure, status);
            Assert.AreEqual(1, blackboard.Counter1);
            Assert.AreEqual(0, data.Stack.Count);
        }
Exemplo n.º 29
0
    private void Awake()
    {
        base.Awake();
        PathWalker = gameObject.GetComponent <PathWalker>();

        var _builder = new BehaviourTreeBuilder();

        _builder = _builder.Selector(); // MainNode

        _builder = _builder.StateFulSequence("Patrol")
                   .Inverter("!").Condition("HayEnemigo", () => enemyTransform != null).End()
                   .Condition("EndPath", () => PathWalker.Ended)
                   .Do("FindPath", () => { _ = PathWalker.WalkTo(PathFinderManager.Instance.RandomWalkablePosition); PathWalker.WALK_SPEED = 5; return(BehaviorReturnCode.Success); })
                   .End();

        _builder = _builder.StateFulSequence("FindEnemy")
                   .Inverter("!").Condition("HayEnemigo", () => enemyTransform != null).End()
                   .Inverter("!").Do("BuscarEnemigo", FindEnemy).End()
                   .End();

        _builder = _builder.StateFulSequence("Follow")
                   .Condition("HayEnemigo", () => enemyTransform != null)
                   .Inverter("!").Condition("EstaCerca", () => (enemyTransform.position - transform.position).magnitude < attack_range).End()
                   .Condition("EndPath", () => PathWalker.Ended)
                   .Do("FindPath", () => { _ = PathWalker.WalkTo(enemyTransform.position + ((transform.position - enemyTransform.position).normalized * 1.5f)); return(BehaviorReturnCode.Success); })
                   .End();

        _builder = _builder.StateFulSequence("Attack")
                   .Condition("HayEnemigo", () => enemyTransform != null)
                   .Condition("EstaCerca", () => (enemyTransform.position - transform.position).magnitude < attack_range)
                   .Do("AttackEnemy", AttackEnemy)
                   .End();

        _builder = _builder.End(); // End MainNode

        _root = _builder.Build();
    }
        public void WaitNodeTest()
        {
            var tickProvider = new TestTickSupplier();
            var root         = new BehaviourTreeBuilder <TestBlackboard>()
                               .Wait("Increment counter 1", 3, tickProvider)
                               .Build();
            var metadata   = new BehaviourTreeMetadata <TestBlackboard>(root);
            var data       = metadata.CreateExecutionData();
            var executor   = new BehaviourTreeExecutor <TestBlackboard>(root);
            var blackboard = new TestBlackboard();

            executor.Start(data);

            for (var i = 0; i < 3; i++)
            {
                executor.Tick(data, blackboard);
                Assert.AreEqual(BehaviourTreeStatus.Running, data.Statuses[root.Id]);
                tickProvider.Tick();
            }

            executor.Tick(data, blackboard);
            Assert.AreEqual(BehaviourTreeStatus.Success, data.Statuses[root.Id]);
            Assert.AreEqual(0, data.Stack.Count);
        }