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
20 changes: 12 additions & 8 deletions src/BehaviourTreeBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FluentBehaviourTree
{
Expand All @@ -13,12 +11,12 @@ public class BehaviourTreeBuilder
/// <summary>
/// Last node created.
/// </summary>
private IBehaviourTreeNode curNode = null;
private BehaviourTreeNode curNode = null;

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

/// <summary>
/// Create an action node.
Expand All @@ -29,7 +27,10 @@ public BehaviourTreeBuilder Do(string name, Func<TimeData, BehaviourTreeStatus>
{
throw new ApplicationException("Can't create an unnested ActionNode, it must be a leaf node.");
}

if (string.IsNullOrEmpty(name))
{
name = fn.Method.Name;
}
var actionNode = new ActionNode(name, fn);
parentNodeStack.Peek().AddChild(actionNode);
return this;
Expand All @@ -40,6 +41,10 @@ public BehaviourTreeBuilder Do(string name, Func<TimeData, BehaviourTreeStatus>
/// </summary>
public BehaviourTreeBuilder Condition(string name, Func<TimeData, bool> fn)
{
if (string.IsNullOrEmpty(name))
{
name = fn.Method.Name;
}
return Do(name, t => fn(t) ? BehaviourTreeStatus.Success : BehaviourTreeStatus.Failure);
}

Expand Down Expand Up @@ -110,13 +115,12 @@ public BehaviourTreeBuilder Selector(string name)
/// <summary>
/// Splice a sub tree into the parent tree.
/// </summary>
public BehaviourTreeBuilder Splice(IBehaviourTreeNode subTree)
public BehaviourTreeBuilder Splice(BehaviourTreeNode subTree)
{
if (subTree == null)
{
throw new ArgumentNullException("subTree");
}

if (parentNodeStack.Count <= 0)
{
throw new ApplicationException("Can't splice an unnested sub-tree, there must be a parent-tree.");
Expand All @@ -129,7 +133,7 @@ public BehaviourTreeBuilder Splice(IBehaviourTreeNode subTree)
/// <summary>
/// Build the actual tree.
/// </summary>
public IBehaviourTreeNode Build()
public BehaviourTreeNode Build()
{
if (curNode == null)
{
Expand Down
46 changes: 46 additions & 0 deletions src/BehaviourTreeNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
namespace FluentBehaviourTree
{
/// <summary>
/// Interface for behaviour tree nodes.
/// </summary>
public abstract class BehaviourTreeNode
{
/// <summary>
/// The reference name for this node
/// </summary>
public string name { get; private set; }
/// <summary>
/// The result of the last execution
/// </summary>
public BehaviourTreeStatus lastExecutionStatus { get; private set; }
/// <summary>
/// Used to determine if this node has been ticked yet this iteration.
/// </summary>
public bool hasExecuted { get; private set; }

public BehaviourTreeNode(string name)
{
this.name = name;
lastExecutionStatus = BehaviourTreeStatus.Failure;
}

/// <summary>
/// Update the time of the behaviour tree.
/// </summary>
public BehaviourTreeStatus Tick(TimeData time)
{
ResetLastExecStatus();
lastExecutionStatus = AbstractTick(time);
hasExecuted = true;
return lastExecutionStatus;
}
/// <summary>
/// Marks that this node hasn't executed yet.
/// </summary>
internal virtual void ResetLastExecStatus()
{
hasExecuted = false;
}
protected abstract BehaviourTreeStatus AbstractTick(TimeData time);
}
}
18 changes: 0 additions & 18 deletions src/IBehaviourTreeNode.cs

This file was deleted.

18 changes: 0 additions & 18 deletions src/IParentBehaviourTreeNode.cs

This file was deleted.

18 changes: 4 additions & 14 deletions src/Nodes/ActionNode.cs
Original file line number Diff line number Diff line change
@@ -1,33 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FluentBehaviourTree
{
/// <summary>
/// A behaviour tree leaf node for running an action.
/// </summary>
public class ActionNode : IBehaviourTreeNode
public class ActionNode : BehaviourTreeNode
{
/// <summary>
/// The name of the node.
/// </summary>
private string name;

/// <summary>
/// Function to invoke for the action.
/// </summary>
private Func<TimeData, BehaviourTreeStatus> fn;


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

public BehaviourTreeStatus Tick(TimeData time)
protected override BehaviourTreeStatus AbstractTick(TimeData time)
{
return fn(time);
}
Expand Down
37 changes: 15 additions & 22 deletions src/Nodes/InverterNode.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FluentBehaviourTree
{
/// <summary>
/// Decorator node that inverts the success/failure of its child.
/// </summary>
public class InverterNode : IParentBehaviourTreeNode
public class InverterNode : ParentBehaviourTreeNode
{
/// <summary>
/// Name of the node.
/// </summary>
private string name;

/// <summary>
/// The child to be inverted.
/// </summary>
private IBehaviourTreeNode childNode;

public InverterNode(string name)
{
this.name = name;
private BehaviourTreeNode childNode {
get {
if (childCount == 0)
{
return null;
}
return this[0];
}
}

public BehaviourTreeStatus Tick(TimeData time)
public InverterNode(string name) : base(name) { }

protected override BehaviourTreeStatus AbstractTick(TimeData time)
{
if (childNode == null)
{
Expand All @@ -47,17 +44,13 @@ public BehaviourTreeStatus Tick(TimeData time)
}
}

/// <summary>
/// Add a child to the parent node.
/// </summary>
public void AddChild(IBehaviourTreeNode child)
public override void AddChild(BehaviourTreeNode child)
{
if (this.childNode != null)
if (childNode != null)
{
throw new ApplicationException("Can't add more than a single child to InverterNode!");
}

this.childNode = child;
base.AddChild(child);
}
}
}
36 changes: 6 additions & 30 deletions src/Nodes/ParallelNode.cs
Original file line number Diff line number Diff line change
@@ -1,73 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FluentBehaviourTree
namespace FluentBehaviourTree
{
/// <summary>
/// Runs childs nodes in parallel.
/// </summary>
public class ParallelNode : IParentBehaviourTreeNode
public class ParallelNode : ParentBehaviourTreeNode
{
/// <summary>
/// Name of the node.
/// </summary>
private string name;

/// <summary>
/// List of child nodes.
/// </summary>
private List<IBehaviourTreeNode> children = new List<IBehaviourTreeNode>();

/// <summary>
/// Number of child failures required to terminate with failure.
/// </summary>
private int numRequiredToFail;

/// <summary>
/// Number of child successess require to terminate with success.
/// </summary>
private int numRequiredToSucceed;

public ParallelNode(string name, int numRequiredToFail, int numRequiredToSucceed)
public ParallelNode(string name, int numRequiredToFail, int numRequiredToSucceed) : base(name)
{
this.name = name;
this.numRequiredToFail = numRequiredToFail;
this.numRequiredToSucceed = numRequiredToSucceed;
}

public BehaviourTreeStatus Tick(TimeData time)
protected override BehaviourTreeStatus AbstractTick(TimeData time)
{
var numChildrenSuceeded = 0;
var numChildrenFailed = 0;

foreach (var child in children)
for (int i = 0; i < childCount; i++)
{
var child = this[i];
var childStatus = child.Tick(time);
switch (childStatus)
{
case BehaviourTreeStatus.Success: ++numChildrenSuceeded; break;
case BehaviourTreeStatus.Failure: ++numChildrenFailed; break;
}
}

if (numRequiredToSucceed > 0 && numChildrenSuceeded >= numRequiredToSucceed)
{
return BehaviourTreeStatus.Success;
}

if (numRequiredToFail > 0 && numChildrenFailed >= numRequiredToFail)
{
return BehaviourTreeStatus.Failure;
}

return BehaviourTreeStatus.Running;
}

public void AddChild(IBehaviourTreeNode child)
{
children.Add(child);
}
}
}
38 changes: 6 additions & 32 deletions src/Nodes/SelectorNode.cs
Original file line number Diff line number Diff line change
@@ -1,50 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FluentBehaviourTree
namespace FluentBehaviourTree
{
/// <summary>
/// Selects the first node that succeeds. Tries successive nodes until it finds one that doesn't fail.
/// </summary>
public class SelectorNode : IParentBehaviourTreeNode
public class SelectorNode : ParentBehaviourTreeNode
{
/// <summary>
/// The name of the node.
/// </summary>
private string name;

/// <summary>
/// List of child nodes.
/// </summary>
private List<IBehaviourTreeNode> children = new List<IBehaviourTreeNode>(); //todo: optimization, bake this to an array.

public SelectorNode(string name)
{
this.name = name;
}
public SelectorNode(string name) : base(name) { }

public BehaviourTreeStatus Tick(TimeData time)
protected override BehaviourTreeStatus AbstractTick(TimeData time)
{
foreach (var child in children)
for (int i = 0; i < childCount; i++)
{
var child = this[i];
var childStatus = child.Tick(time);
if (childStatus != BehaviourTreeStatus.Failure)
{
return childStatus;
}
}

return BehaviourTreeStatus.Failure;
}

/// <summary>
/// Add a child node to the selector.
/// </summary>
public void AddChild(IBehaviourTreeNode child)
{
children.Add(child);
}
}
}
Loading