-
-
Save forestrf/b297466ff080bcc67463043978bb59aa to your computer and use it in GitHub Desktop.
Behaviour Tree in C#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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