Skip to content
This repository was archived by the owner on Sep 9, 2018. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 32 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ A behaviour tree is created through *BehaviourTreeBuilder*. The tree is returned

...

IBehaviourTreeNode tree;
IBehaviourTreeNode<TimeData> tree;

public void Startup()
{
var builder = new BehaviourTreeBuilder();
this.tree = BehaviourTreeBuilder
var builder = new BehaviourTreeBuilder<TimeData>();
this.tree = builder
.Sequence("my-sequence")
.Do(t =>
{
Expand Down Expand Up @@ -117,11 +117,33 @@ Runs all child nodes in parallel. Continues to run until a required number of ch
})
.End()

### Selector
### Priority Selector

Runs child nodes in sequence until it finds one that *succeeds*. Succeeds when it finds the first child that *succeeds*. For child nodes that *fail* it moves forward to the next child node. While a child is *running* it stays on that child node without moving forward.

.Selector("my-selector")
.PrioritySelector("my-selector")
.Do(t =>
{
// Action 1.
return BehaviourTreeStatus.Failure; // Fail, move onto next child.
});
.Do(t =>
{
// Action 2.
return BehaviourTreeStatus.Success; // Success, stop here.
})
.Do(t =>
{
// Action 3.
return BehaviourTreeStatus.Success; // Doesn't get this far.
})
.End()

### Probability Selector

Runs a random child node until it *succeeds* or *fails*. It returns the status of the child that was run. While a child is *running* it stays on that child node without selecting a new child.

.ProbabilitySelector("my-selector")
.Do(t =>
{
// Action 1.
Expand Down Expand Up @@ -184,10 +206,10 @@ Behaviour trees can be nested to any depth, for example:

Separately created sub-trees can be spliced into parent trees. This makes it easy to build behaviour trees from reusable components.

private IBehaviourTreeNode CreateSubTree()
private IBehaviourTreeNode<TimeData> CreateSubTree()
{
var builder = new BehaviourTreeBuilder();
return BehaviourTreeBuilder
var builder = new BehaviourTreeBuilder<TimeData>();
return builder
.Sequence("my-sub-tree")
.Do(t =>
{
Expand All @@ -205,8 +227,8 @@ Separately created sub-trees can be spliced into parent trees. This makes it eas

public void Startup()
{
var builder = new BehaviourTreeBuilder();
this.tree = BehaviourTreeBuilder
var builder = new BehaviourTreeBuilder<TimeData>();
this.tree = builder
.Sequence("my-parent-sequence")
.Splice(CreateSubTree()) // Splice the child tree in.
.Splice(CreateSubTree()) // Splice again.
Expand Down
65 changes: 42 additions & 23 deletions src/BehaviourTreeBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,54 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FluentBehaviourTree
namespace FluentBehaviourTree
{
using System;
using System.Collections.Generic;

public class BehaviourTreeBuilder : BehaviourTreeBuilder<TimeData>
{

}

/// <summary>
/// Fluent API for building a behaviour tree.
/// </summary>
public class BehaviourTreeBuilder
public class BehaviourTreeBuilder<TTickData>
{
/// <summary>
/// Last node created.
/// </summary>
private IBehaviourTreeNode curNode = null;
private IBehaviourTreeNode<TTickData> curNode = null;

/// <summary>
/// Stack node nodes that we are build via the fluent API.
/// </summary>
private Stack<IParentBehaviourTreeNode> parentNodeStack = new Stack<IParentBehaviourTreeNode>();
private Stack<IParentBehaviourTreeNode<TTickData>> parentNodeStack = new Stack<IParentBehaviourTreeNode<TTickData>>();

/// <summary>
/// Create an action node.
/// </summary>
public BehaviourTreeBuilder Do(string name, Func<TimeData, BehaviourTreeStatus> fn)
public BehaviourTreeBuilder<TTickData> Do(string name, Func<TTickData, BehaviourTreeStatus> fn)
{
if (parentNodeStack.Count <= 0)
{
throw new ApplicationException("Can't create an unnested ActionNode, it must be a leaf node.");
}

var actionNode = new ActionNode(name, fn);
var actionNode = new ActionNode<TTickData>(name, fn);
parentNodeStack.Peek().AddChild(actionNode);
return this;
}

/// <summary>
/// Like an action node... but the function can return true/false and is mapped to success/failure.
/// </summary>
public BehaviourTreeBuilder Condition(string name, Func<TimeData, bool> fn)
public BehaviourTreeBuilder<TTickData> Condition(string name, Func<TTickData, bool> fn)
{
return Do(name, t => fn(t) ? BehaviourTreeStatus.Success : BehaviourTreeStatus.Failure);
}

/// <summary>
/// Create an inverter node that inverts the success/failure of its children.
/// </summary>
public BehaviourTreeBuilder Inverter(string name)
public BehaviourTreeBuilder<TTickData> Inverter(string name)
{
var inverterNode = new InverterNode(name);
var inverterNode = new InverterNode<TTickData>(name);

if (parentNodeStack.Count > 0)
{
Expand All @@ -62,9 +65,9 @@ public BehaviourTreeBuilder Inverter(string name)
/// <summary>
/// Create a sequence node.
/// </summary>
public BehaviourTreeBuilder Sequence(string name)
public BehaviourTreeBuilder<TTickData> Sequence(string name)
{
var sequenceNode = new SequenceNode(name);
var sequenceNode = new SequenceNode<TTickData>(name);

if (parentNodeStack.Count > 0)
{
Expand All @@ -78,9 +81,9 @@ public BehaviourTreeBuilder Sequence(string name)
/// <summary>
/// Create a parallel node.
/// </summary>
public BehaviourTreeBuilder Parallel(string name, int numRequiredToFail, int numRequiredToSucceed)
public BehaviourTreeBuilder<TTickData> Parallel(string name, int numRequiredToFail, int numRequiredToSucceed)
{
var parallelNode = new ParallelNode(name, numRequiredToFail, numRequiredToSucceed);
var parallelNode = new ParallelNode<TTickData>(name, numRequiredToFail, numRequiredToSucceed);

if (parentNodeStack.Count > 0)
{
Expand All @@ -94,9 +97,25 @@ public BehaviourTreeBuilder Parallel(string name, int numRequiredToFail, int num
/// <summary>
/// Create a selector node.
/// </summary>
public BehaviourTreeBuilder Selector(string name)
public BehaviourTreeBuilder<TTickData> PrioritySelector(string name)
{
var selectorNode = new PrioritySelectorNode<TTickData>(name);

if (parentNodeStack.Count > 0)
{
parentNodeStack.Peek().AddChild(selectorNode);
}

parentNodeStack.Push(selectorNode);
return this;
}

/// <summary>
/// Create a selector node.
/// </summary>
public BehaviourTreeBuilder<TTickData> PropabilitySelector(string name)
{
var selectorNode = new SelectorNode(name);
var selectorNode = new ProbabilitySelectorNode<TTickData>(name);

if (parentNodeStack.Count > 0)
{
Expand All @@ -110,7 +129,7 @@ public BehaviourTreeBuilder Selector(string name)
/// <summary>
/// Splice a sub tree into the parent tree.
/// </summary>
public BehaviourTreeBuilder Splice(IBehaviourTreeNode subTree)
public BehaviourTreeBuilder<TTickData> Splice(IBehaviourTreeNode<TTickData> subTree)
{
if (subTree == null)
{
Expand All @@ -129,7 +148,7 @@ public BehaviourTreeBuilder Splice(IBehaviourTreeNode subTree)
/// <summary>
/// Build the actual tree.
/// </summary>
public IBehaviourTreeNode Build()
public IBehaviourTreeNode<TTickData> Build()
{
if (curNode == null)
{
Expand All @@ -141,7 +160,7 @@ public IBehaviourTreeNode Build()
/// <summary>
/// Ends a sequence of children.
/// </summary>
public BehaviourTreeBuilder End()
public BehaviourTreeBuilder<TTickData> End()
{
curNode = parentNodeStack.Pop();
return this;
Expand Down
7 changes: 1 addition & 6 deletions src/BehaviourTreeStatus.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FluentBehaviourTree
namespace FluentBehaviourTree
{
/// <summary>
/// The return type when invoking behaviour tree nodes.
Expand Down
14 changes: 6 additions & 8 deletions src/IBehaviourTreeNode.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FluentBehaviourTree
namespace FluentBehaviourTree
{
public interface IBehaviourTreeNode : IBehaviourTreeNode<TimeData>
{ }

/// <summary>
/// Interface for behaviour tree nodes.
/// </summary>
public interface IBehaviourTreeNode
public interface IBehaviourTreeNode<TTickData>
{
/// <summary>
/// Update the time of the behaviour tree.
/// </summary>
BehaviourTreeStatus Tick(TimeData time);
BehaviourTreeStatus Tick(TTickData time);
}
}
14 changes: 6 additions & 8 deletions src/IParentBehaviourTreeNode.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FluentBehaviourTree
namespace FluentBehaviourTree
{
public interface IParentBehaviourTreeNode : IParentBehaviourTreeNode<TimeData>
{ }

/// <summary>
/// Interface for behaviour tree nodes.
/// </summary>
public interface IParentBehaviourTreeNode : IBehaviourTreeNode
public interface IParentBehaviourTreeNode<TTickData> : IBehaviourTreeNode<TTickData>
{
/// <summary>
/// Add a child to the parent node.
/// </summary>
void AddChild(IBehaviourTreeNode child);
void AddChild(IBehaviourTreeNode<TTickData> child);
}
}
30 changes: 17 additions & 13 deletions src/Nodes/ActionNode.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FluentBehaviourTree
namespace FluentBehaviourTree
{
using System;

public class ActionNode : ActionNode<TimeData>
{
public ActionNode(string name, Func<TimeData, BehaviourTreeStatus> fn) : base(name, fn)
{
}
}

/// <summary>
/// A behaviour tree leaf node for running an action.
/// </summary>
public class ActionNode : IBehaviourTreeNode
public class ActionNode<TTickData> : IBehaviourTreeNode<TTickData>
{
/// <summary>
/// The name of the node.
Expand All @@ -18,16 +22,16 @@ public class ActionNode : IBehaviourTreeNode
/// <summary>
/// Function to invoke for the action.
/// </summary>
private Func<TimeData, BehaviourTreeStatus> fn;
private Func<TTickData, BehaviourTreeStatus> fn;


public ActionNode(string name, Func<TimeData, BehaviourTreeStatus> fn)
public ActionNode(string name, Func<TTickData, BehaviourTreeStatus> fn)
{
this.name=name;
this.fn=fn;
this.name = name;
this.fn = fn;
}

public BehaviourTreeStatus Tick(TimeData time)
public BehaviourTreeStatus Tick(TTickData time)
{
return fn(time);
}
Expand Down
24 changes: 14 additions & 10 deletions src/Nodes/InverterNode.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FluentBehaviourTree
namespace FluentBehaviourTree
{
using System;

public class InverterNode : InverterNode<TimeData>
{
public InverterNode(string name) : base(name)
{
}
}

/// <summary>
/// Decorator node that inverts the success/failure of its child.
/// </summary>
public class InverterNode : IParentBehaviourTreeNode
public class InverterNode<TTickData> : IParentBehaviourTreeNode<TTickData>
{
/// <summary>
/// Name of the node.
Expand All @@ -18,14 +22,14 @@ public class InverterNode : IParentBehaviourTreeNode
/// <summary>
/// The child to be inverted.
/// </summary>
private IBehaviourTreeNode childNode;
private IBehaviourTreeNode<TTickData> childNode;

public InverterNode(string name)
{
this.name = name;
}

public BehaviourTreeStatus Tick(TimeData time)
public BehaviourTreeStatus Tick(TTickData time)
{
if (childNode == null)
{
Expand All @@ -50,7 +54,7 @@ public BehaviourTreeStatus Tick(TimeData time)
/// <summary>
/// Add a child to the parent node.
/// </summary>
public void AddChild(IBehaviourTreeNode child)
public void AddChild(IBehaviourTreeNode<TTickData> child)
{
if (this.childNode != null)
{
Expand Down
Loading