Skip to content

Commit

Permalink
feat(behavior-tree): calling Reset() now triggers End on active nodes
Browse files Browse the repository at this point in the history
Previously calling reset on a BehaviorTree did not call `End()` because it was not performant. Nodes
that return continue on a tree are now registered as active and removed after returning continue.
Allowing them to be discovered at the top level by the BehaviorTree without traversing the entire
system.
  • Loading branch information
ashblue committed Jun 3, 2019
1 parent 6367990 commit 0287fa8
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 43 deletions.
31 changes: 27 additions & 4 deletions Assets/FluidBehaviorTree/Runtime/BehaviorTree/BehaviorTree.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
using CleverCrow.Fluid.BTs.TaskParents;
using System.Collections.Generic;
using CleverCrow.Fluid.BTs.TaskParents;
using CleverCrow.Fluid.BTs.Tasks;
using UnityEngine;

namespace CleverCrow.Fluid.BTs.Trees {
public class BehaviorTree {
public interface IBehaviorTree {
int TickCount { get; }

void AddActiveTask (ITask task);
void RemoveActiveTask (ITask task);
}

public class BehaviorTree : IBehaviorTree {
private readonly GameObject _owner;
private readonly List<ITask> _tasks = new List<ITask>();

public int TickCount { get; private set; }

public TaskRoot Root { get; } = new TaskRoot();
public IReadOnlyList<ITask> ActiveTasks => _tasks;

public BehaviorTree (GameObject owner) {
_owner = owner;
Expand All @@ -18,13 +28,18 @@ public BehaviorTree (GameObject owner) {
public TaskStatus Tick () {
var status = Root.Update();
if (status != TaskStatus.Continue) {
TickCount++;
Reset();
}

return status;
}

public void Reset () {
foreach (var task in _tasks) {
task.End();
}

_tasks.Clear();
TickCount++;
}

Expand Down Expand Up @@ -54,5 +69,13 @@ private void SyncNodes (ITaskParent taskParent) {
}
}
}

public void AddActiveTask (ITask task) {
_tasks.Add(task);
}

public void RemoveActiveTask (ITask task) {
_tasks.Remove(task);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public abstract class DecoratorBase : ITaskParent {
public bool Enabled { get; set; } = true;

public GameObject Owner { get; set; }
public BehaviorTree ParentTree { get; set; }
public IBehaviorTree ParentTree { get; set; }
public TaskStatus LastStatus { get; private set; }

public ITask Child => Children.Count > 0 ? Children[0] : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace CleverCrow.Fluid.BTs.TaskParents {
public abstract class TaskParentBase : ITaskParent {
public BehaviorTree ParentTree { get; set; }
public IBehaviorTree ParentTree { get; set; }
public TaskStatus LastStatus { get; private set; }

public string Name { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion Assets/FluidBehaviorTree/Runtime/Tasks/ITask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public interface ITask {
/// <summary>
/// Tree this node belongs to
/// </summary>
BehaviorTree ParentTree { get; set; }
IBehaviorTree ParentTree { get; set; }

/// <summary>
/// Last status returned by Update
Expand Down
9 changes: 7 additions & 2 deletions Assets/FluidBehaviorTree/Runtime/Tasks/TaskBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ public abstract class TaskBase : ITask {
private bool _start;
private bool _exit;
private int _lastTickCount;
private bool _active;

public string Name { get; set; }
public bool Enabled { get; set; } = true;
public GameObject Owner { get; set; }
public BehaviorTree ParentTree { get; set; }
public IBehaviorTree ParentTree { get; set; }

public TaskStatus LastStatus { get; private set; }

Expand All @@ -32,9 +33,12 @@ public TaskStatus Update () {
var status = GetUpdate();
LastStatus = status;

// Soft reset since the node has completed
if (status != TaskStatus.Continue) {
if (_active) ParentTree?.RemoveActiveTask(this);
Exit();
} else if (!_active) {
ParentTree?.AddActiveTask(this);
_active = true;
}

return status;
Expand All @@ -56,6 +60,7 @@ private void UpdateTicks () {
/// Reset the node to be re-used
/// </summary>
public void Reset () {
_active = false;
_start = false;
_exit = false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using CleverCrow.Fluid.BTs.TaskParents.Composites;
using CleverCrow.Fluid.BTs.Tasks;
using CleverCrow.Fluid.BTs.Testing;
using NSubstitute;
using NUnit.Framework;
using UnityEngine;
Expand Down Expand Up @@ -121,6 +123,27 @@ public void It_should_increase_the_tick_count () {

Assert.AreEqual(1, _tree.TickCount);
}

[Test]
public void It_should_call_End_on_active_nodes () {
var task = A.TaskStub().Build();

_tree.AddActiveTask(task);
_tree.Reset();

task.Received(1).End();
}

[Test]
public void It_should_not_call_End_on_active_nodes_twice_if_called_again () {
var task = A.TaskStub().Build();

_tree.AddActiveTask(task);
_tree.Reset();
_tree.Reset();

task.Received(1).End();
}
}

public class TickMethod : BehaviorTreeTest {
Expand Down Expand Up @@ -218,5 +241,28 @@ public void Does_not_run_reset_on_2nd_action_if_1st_fails () {
}
}
}

public class AddActiveTaskMethod : BehaviorTreeTest {
[Test]
public void It_should_add_an_active_task () {
var task = A.TaskStub().Build();

_tree.AddActiveTask(task);

Assert.IsTrue(_tree.ActiveTasks.Contains(task));
}
}

public class RemoveActiveTaskMethod : BehaviorTreeTest {
[Test]
public void It_should_add_an_active_task () {
var task = A.TaskStub().Build();

_tree.AddActiveTask(task);
_tree.RemoveActiveTask(task);

Assert.IsFalse(_tree.ActiveTasks.Contains(task));
}
}
}
}
Loading

0 comments on commit 0287fa8

Please sign in to comment.