Skip to content

Instantly share code, notes, and snippets.

@forestrf
Forked from NovemberDev/BehaviourTree.cs
Created March 12, 2020 01:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save forestrf/b297466ff080bcc67463043978bb59aa to your computer and use it in GitHub Desktop.
Save forestrf/b297466ff080bcc67463043978bb59aa to your computer and use it in GitHub Desktop.
Behaviour Tree in C#
using System;
using System.Linq;
using System.Collections.Generic;
public enum BTS
{
Success,
Failure,
Running
}
public abstract class BTN
{
public string Name;
public List<BTN> ChildNodes = new List<BTN>();
public abstract BTS Tick(float deltaTime);
}
public class ParallelNode : BTN
{
public int CountToFail, CountToSucceed;
public ParallelNode(string name, int countToFail, int countToSucceed)
{
Name = name;
CountToFail = countToFail;
CountToSucceed = countToSucceed;
}
public override BTS Tick(float deltaTime)
{
int succeeded = 0,
failed = 0;
foreach(BTN child in ChildNodes)
{
BTS status = child.Tick(deltaTime);
switch(status)
{
case BTS.Success:
++succeeded;
break;
case BTS.Failure:
++failed;
break;
}
}
if (CountToSucceed > 0 && succeeded >= CountToSucceed)
return BTS.Success;
if (CountToFail > 0 && failed >= CountToFail)
return BTS.Failure;
return BTS.Running;
}
}
public class LeafNode : BTN
{
public Func<float, BTS> Function;
public LeafNode(string name, Func<float, BTS> function)
{
Name = name;
Function = function;
}
public override BTS Tick(float deltaTime) => Function(deltaTime);
}
public class InverterNode : BTN
{
public InverterNode(string name)
{
Name = name;
}
public override BTS Tick(float deltaTime)
{
BTS status = ChildNodes.First().Tick(deltaTime);
switch (status)
{
case BTS.Failure:
return BTS.Success;
case BTS.Success:
return BTS.Failure;
default:
return status;
}
}
}
public class SelectorNode : BTN
{
public SelectorNode(string name)
{
Name = name;
}
public override BTS Tick(float deltaTime)
{
foreach(BTN child in ChildNodes)
{
BTS status = child.Tick(deltaTime);
if (status != BTS.Failure)
return status;
}
return BTS.Failure;
}
}
public class SequenceNode : BTN
{
public SequenceNode(string name)
{
Name = name;
}
public override BTS Tick(float deltaTime)
{
foreach(BTN node in ChildNodes)
{
BTS status = node.Tick(deltaTime);
if (status != BTS.Success)
return status;
}
return BTS.Success;
}
}
public class BTB
{
public BTN CurrentNode;
public Stack<BTN> ParentNodes = new Stack<BTN>();
public BTB Do(string name, Func<float, BTS> function)
{
ParentNodes.Peek().ChildNodes.Add(new LeafNode(name, function));
return this;
}
public BTB Condition(string name, Func<float, bool> function)
{
Do(name, t => function(t) ? BTS.Success : BTS.Failure);
return this;
}
public BTB Inverter(string name)
{
ParentNodes.Push(new InverterNode(name));
return this;
}
public BTB Sequence(string name)
{
SequenceNode sequenceNode = new SequenceNode(name);
if (ParentNodes.Count > 0)
ParentNodes.Peek().ChildNodes.Add(sequenceNode);
ParentNodes.Push(sequenceNode);
return this;
}
public BTB Parallel(string name, int countToFail, int countToSucceed)
{
ParentNodes.Push(new ParallelNode(name, countToFail, countToSucceed));
return this;
}
public BTB Selector(string name)
{
ParentNodes.Push(new SelectorNode(name));
return this;
}
public BTB End()
{
CurrentNode = ParentNodes.Pop();
return this;
}
public BTN Return() => CurrentNode;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment