diff --git a/BehaviorLibrary.sln b/BehaviorLibrary.sln index 9eed5dd..a6cfc79 100644 --- a/BehaviorLibrary.sln +++ b/BehaviorLibrary.sln @@ -1,20 +1,30 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BehaviorLibrary", "BehaviorLibrary\BehaviorLibrary.csproj", "{CC824B6F-6145-485F-9604-FB94F0ECACA7}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CC824B6F-6145-485F-9604-FB94F0ECACA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CC824B6F-6145-485F-9604-FB94F0ECACA7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CC824B6F-6145-485F-9604-FB94F0ECACA7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CC824B6F-6145-485F-9604-FB94F0ECACA7}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26020.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BehaviorLibrary", "BehaviorLibrary\BehaviorLibrary.csproj", "{CC824B6F-6145-485F-9604-FB94F0ECACA7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{A7D9F051-A51E-42FF-AD2B-D94DC8A06650}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CC824B6F-6145-485F-9604-FB94F0ECACA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CC824B6F-6145-485F-9604-FB94F0ECACA7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CC824B6F-6145-485F-9604-FB94F0ECACA7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CC824B6F-6145-485F-9604-FB94F0ECACA7}.Release|Any CPU.Build.0 = Release|Any CPU + {A7D9F051-A51E-42FF-AD2B-D94DC8A06650}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A7D9F051-A51E-42FF-AD2B-D94DC8A06650}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A7D9F051-A51E-42FF-AD2B-D94DC8A06650}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = BehaviorLibrary\BehaviorLibrary.csproj + EndGlobalSection +EndGlobal diff --git a/BehaviorLibrary/Behavior.cs b/BehaviorLibrary/Behavior.cs index 8f0b24c..b7102cf 100644 --- a/BehaviorLibrary/Behavior.cs +++ b/BehaviorLibrary/Behavior.cs @@ -1,76 +1,81 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using BehaviorLibrary.Components; -using BehaviorLibrary.Components.Composites; - -namespace BehaviorLibrary -{ - public enum BehaviorReturnCode - { - Failure, - Success, - Running - } - - public delegate BehaviorReturnCode BehaviorReturn(); - - /// - /// - /// - public class Behavior - { - - private RootSelector b_Root; - - private BehaviorReturnCode b_ReturnCode; - - public BehaviorReturnCode ReturnCode - { - get { return b_ReturnCode; } - set { b_ReturnCode = value; } - } - - /// - /// - /// - /// - public Behavior(RootSelector root) - { - b_Root = root; - } - - /// - /// perform the behavior - /// - public BehaviorReturnCode Behave() - { - try - { - switch (b_Root.Behave()) - { - case BehaviorReturnCode.Failure: - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - case BehaviorReturnCode.Success: - ReturnCode = BehaviorReturnCode.Success; - return ReturnCode; - case BehaviorReturnCode.Running: - ReturnCode = BehaviorReturnCode.Running; - return ReturnCode; - default: - ReturnCode = BehaviorReturnCode.Running; - return ReturnCode; - } - } - catch (Exception e) - { -#if DEBUG - Console.Error.WriteLine(e.ToString()); -#endif - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using BehaviorLibrary.Components; +using BehaviorLibrary.Components.Composites; + +namespace BehaviorLibrary +{ + public enum BehaviorReturnCode + { + Failure, + Success, + Running + } + + public delegate BehaviorReturnCode BehaviorReturn(); + + /// + /// + /// + public class Behavior + { + + private BehaviorComponent _Root; + + private BehaviorReturnCode _ReturnCode; + + public BehaviorReturnCode ReturnCode + { + get { return _ReturnCode; } + set { _ReturnCode = value; } + } + + /// + /// + /// + /// + public Behavior(IndexSelector root) + { + _Root = root; + } + + public Behavior(BehaviorComponent root){ + _Root = root; + } + + /// + /// perform the behavior + /// + public BehaviorReturnCode Behave(TreeContext context) + { + try + { + switch (_Root.Behave(context)) + { + case BehaviorReturnCode.Failure: + ReturnCode = BehaviorReturnCode.Failure; + break; + case BehaviorReturnCode.Success: + ReturnCode = BehaviorReturnCode.Success; + break; + case BehaviorReturnCode.Running: + ReturnCode = BehaviorReturnCode.Running; + break; + default: + ReturnCode = BehaviorReturnCode.Running; + break; + } + } + catch (Exception e) + { +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + ReturnCode = BehaviorReturnCode.Failure; + } + + return this.ReturnCode; + } + } +} diff --git a/BehaviorLibrary/BehaviorLibrary.csproj b/BehaviorLibrary/BehaviorLibrary.csproj index f351907..d098070 100644 --- a/BehaviorLibrary/BehaviorLibrary.csproj +++ b/BehaviorLibrary/BehaviorLibrary.csproj @@ -43,19 +43,34 @@ + - - + + + - - + + + + + + + + + + + + + + + diff --git a/BehaviorLibrary/Components/Actions/BehaviorAction.cs b/BehaviorLibrary/Components/Actions/BehaviorAction.cs index f899abe..d536017 100644 --- a/BehaviorLibrary/Components/Actions/BehaviorAction.cs +++ b/BehaviorLibrary/Components/Actions/BehaviorAction.cs @@ -1,51 +1,66 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace BehaviorLibrary.Components.Actions -{ - public class BehaviorAction : BehaviorComponent - { - - private Func ba_Action; - - public BehaviorAction() { } - - public BehaviorAction(Func action) - { - ba_Action = action; - } - - public override BehaviorReturnCode Behave() - { - try - { - switch (ba_Action.Invoke()) - { - case BehaviorReturnCode.Success: - ReturnCode = BehaviorReturnCode.Success; - return ReturnCode; - case BehaviorReturnCode.Failure: - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - case BehaviorReturnCode.Running: - ReturnCode = BehaviorReturnCode.Running; - return ReturnCode; - default: - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - } - } - catch (Exception e) - { -#if DEBUG - Console.Error.WriteLine(e.ToString()); -#endif - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - } - } - - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Actions +{ + public class BehaviorAction : BehaviorComponent + { + + private Func _Action; + private Func _Action2; + + public BehaviorAction() { } + + public BehaviorAction(Func action) + { + _Action = action; + this.DebugName = action.Method.Name; + } + + public BehaviorAction(Func action) + { + _Action2 = action; + this.DebugName = action.Method.Name; + } + + public override BehaviorReturnCode OnBehave(TreeContext context) + { + try + { + if (this._Action != null) + { + switch (_Action.Invoke()) + { + case BehaviorReturnCode.Success: + ReturnCode = BehaviorReturnCode.Success; + return ReturnCode; + case BehaviorReturnCode.Failure: + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + case BehaviorReturnCode.Running: + ReturnCode = BehaviorReturnCode.Running; + return ReturnCode; + default: + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + } + } + else + { + return _Action2.Invoke(this, context); + } + } + catch (Exception e) + { +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + } + } + + } +} diff --git a/BehaviorLibrary/Components/Actions/OnNotCalled.cs b/BehaviorLibrary/Components/Actions/OnNotCalled.cs new file mode 100644 index 0000000..9f0d417 --- /dev/null +++ b/BehaviorLibrary/Components/Actions/OnNotCalled.cs @@ -0,0 +1,45 @@ +namespace BehaviorLibrary.Components.Actions +{ + /// + /// Provides a way to specifiy behavior for when a behavior is no longer called, due to a different subtree being executed. + /// + public class OnNotCalled : BehaviorComponent + { + private BehaviorComponent finalizer; + private CallHierarchy lastCallHierarchy; + private bool handledThisTick; + + public OnNotCalled(BehaviorComponent finalizer) + { + this.finalizer = finalizer; + } + + public override BehaviorReturnCode OnBehave(TreeContext context) + { + this.lastCallHierarchy = context.CallingHierarchy; + this.handledThisTick = false; + context.RegisterOnNotCalledBehavior(this); + return BehaviorReturnCode.Success; + } + + public bool CanInvokeFinalizer(TreeContext context, BehaviorComponent caller) + { + if (this.handledThisTick) return true; + + // Check if call hierarchies differ. + var currentHierarchy = context.CallingHierarchy; + if (context.OldContext != null) + { + return !currentHierarchy.Matches(context.OldContext.CallingHierarchy); + } + + return false; + } + + public BehaviorReturnCode InvokeFinalizer(TreeContext context) + { + this.handledThisTick = true; + return this.finalizer.Behave(context); + } + } +} \ No newline at end of file diff --git a/BehaviorLibrary/Components/BehaviorComponent.cs b/BehaviorLibrary/Components/BehaviorComponent.cs index ee31e8b..9d0f09e 100644 --- a/BehaviorLibrary/Components/BehaviorComponent.cs +++ b/BehaviorLibrary/Components/BehaviorComponent.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace BehaviorLibrary.Components +namespace BehaviorLibrary.Components { public abstract class BehaviorComponent { @@ -11,6 +6,16 @@ public abstract class BehaviorComponent public BehaviorComponent() { } - public abstract BehaviorReturnCode Behave(); + public string DebugName { get; set; } + + public abstract BehaviorReturnCode OnBehave(TreeContext context); + + public BehaviorReturnCode Behave(TreeContext context) + { + context.OnAboutToCall(this); + this.ReturnCode = this.OnBehave(context); + context.OnCalled(this, this.ReturnCode); + return this.ReturnCode; + } } -} +} \ No newline at end of file diff --git a/BehaviorLibrary/Components/CallHierarchy.cs b/BehaviorLibrary/Components/CallHierarchy.cs new file mode 100644 index 0000000..51255d5 --- /dev/null +++ b/BehaviorLibrary/Components/CallHierarchy.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.Linq; + +namespace BehaviorLibrary.Components +{ + public class CallHierarchy + { + private IEnumerable callList; + + public CallHierarchy(IEnumerable callList) + { + this.callList = callList; + } + + public bool Matches(CallHierarchy other) + { + var array = callList.ToArray(); + var otherArray = other.callList.ToArray(); + if (array.Length > otherArray.Length) return false; // The current list can be shorter than the old one, because we can still be processing. + + for (int i = 0; i < array.Length; i++) + { + if (array[i] != otherArray[i]) + { + string oldCallTree = ""; + otherArray.ToList().ForEach(x => oldCallTree += x.DebugName + System.Environment.NewLine); + + string newCallTree = ""; + otherArray.ToList().ForEach(x => newCallTree += x.DebugName + System.Environment.NewLine); + + System.Console.Error.WriteLine("Called with {0}, now {1}. Mismatch at {2}", oldCallTree, newCallTree, i); + return false; + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/BehaviorLibrary/Components/Composites/BinarySelector.cs b/BehaviorLibrary/Components/Composites/BinarySelector.cs new file mode 100644 index 0000000..46557a5 --- /dev/null +++ b/BehaviorLibrary/Components/Composites/BinarySelector.cs @@ -0,0 +1,33 @@ +using BehaviorLibrary.Components.Conditionals; + +namespace BehaviorLibrary.Components.Composites +{ + public class BinarySelector : BehaviorComponent + { + private BehaviorComponent condition; + private BehaviorComponent ifTrue; + private BehaviorComponent ifFalse; + + public BinarySelector(BehaviorComponent condition, BehaviorComponent ifTrue, BehaviorComponent ifFalse) + { + this.condition = condition; + this.ifTrue = ifTrue; + this.ifFalse = ifFalse; + } + + public override BehaviorReturnCode OnBehave(TreeContext context) + { + var result = this.condition.Behave(context); + if (result == BehaviorReturnCode.Success) + { + return this.ifTrue.Behave(context); + } + else if (result == BehaviorReturnCode.Failure) + { + return this.ifFalse.Behave(context); + } + + return BehaviorReturnCode.Running; + } + } +} \ No newline at end of file diff --git a/BehaviorLibrary/Components/Composites/ConditionalSelector.cs b/BehaviorLibrary/Components/Composites/ConditionalSelector.cs new file mode 100644 index 0000000..d596b73 --- /dev/null +++ b/BehaviorLibrary/Components/Composites/ConditionalSelector.cs @@ -0,0 +1,50 @@ +using System; + +namespace BehaviorLibrary.Components.Composites +{ + public class ConditionalSelector : BehaviorComponent + { + protected BehaviorComponent[] conditions; + private BehaviorComponent action; + + public ConditionalSelector(BehaviorComponent condition, BehaviorComponent action) + { + this.conditions = new BehaviorComponent[] { condition }; + this.action = action; + } + + public ConditionalSelector(BehaviorComponent[] conditions, BehaviorComponent action) + { + this.conditions = conditions; + this.action = action; + } + + public override BehaviorReturnCode OnBehave(TreeContext context) + { + for (int i = 0; i < this.conditions.Length; i++) + { + try + { + switch (this.conditions[i].Behave(context)) + { + case BehaviorReturnCode.Failure: + return BehaviorReturnCode.Failure; + case BehaviorReturnCode.Running: + return BehaviorReturnCode.Running; + default: + continue; + } + } + catch (Exception e) + { +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + continue; + } + } + + return this.action.Behave(context); + } + } +} \ No newline at end of file diff --git a/BehaviorLibrary/Components/Composites/RootSelector.cs b/BehaviorLibrary/Components/Composites/IndexSelector.cs similarity index 77% rename from BehaviorLibrary/Components/Composites/RootSelector.cs rename to BehaviorLibrary/Components/Composites/IndexSelector.cs index 5c41c4e..eb1894a 100644 --- a/BehaviorLibrary/Components/Composites/RootSelector.cs +++ b/BehaviorLibrary/Components/Composites/IndexSelector.cs @@ -1,60 +1,60 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace BehaviorLibrary.Components.Composites -{ - public class RootSelector : Selector - { - - private BehaviorComponent[] rs_Behaviors; - - private Func rs_Index; - - /// - /// The selector for the root node of the behavior tree - /// - /// an index representing which of the behavior branches to perform - /// the behavior branches to be selected from - public RootSelector(Func index, params BehaviorComponent[] behaviors) - { - rs_Index = index; - rs_Behaviors = behaviors; - } - - /// - /// performs the given behavior - /// - /// the behaviors return code - public override BehaviorReturnCode Behave() - { - try - { - switch (rs_Behaviors[rs_Index.Invoke()].Behave()) - { - case BehaviorReturnCode.Failure: - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - case BehaviorReturnCode.Success: - ReturnCode = BehaviorReturnCode.Success; - return ReturnCode; - case BehaviorReturnCode.Running: - ReturnCode = BehaviorReturnCode.Running; - return ReturnCode; - default: - ReturnCode = BehaviorReturnCode.Running; - return ReturnCode; - } - } - catch (Exception e) - { -#if DEBUG - Console.Error.WriteLine(e.ToString()); -#endif - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Composites +{ + public class IndexSelector : BehaviorComponent + { + + private BehaviorComponent[] _Behaviors; + + private Func _Index; + + /// + /// The selector for the root node of the behavior tree + /// + /// an index representing which of the behavior branches to perform + /// the behavior branches to be selected from + public IndexSelector(Func index, params BehaviorComponent[] behaviors) + { + _Index = index; + _Behaviors = behaviors; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) + { + try + { + switch (_Behaviors[_Index.Invoke()].Behave(context)) + { + case BehaviorReturnCode.Failure: + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + case BehaviorReturnCode.Success: + ReturnCode = BehaviorReturnCode.Success; + return ReturnCode; + case BehaviorReturnCode.Running: + ReturnCode = BehaviorReturnCode.Running; + return ReturnCode; + default: + ReturnCode = BehaviorReturnCode.Running; + return ReturnCode; + } + } + catch (Exception e) + { +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + } + } + } +} diff --git a/BehaviorLibrary/Components/Composites/ParallelSelector.cs b/BehaviorLibrary/Components/Composites/ParallelSelector.cs deleted file mode 100644 index 70f1ef0..0000000 --- a/BehaviorLibrary/Components/Composites/ParallelSelector.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace BehaviorLibrary.Components.Composites -{ - public class ParallelSelector : BehaviorComponent - { - - protected BehaviorComponent[] p_Behaviors; - - private short p_Selections = 0; - - private short p_SelLength = 0; - - /// - /// Selects among the given behavior components - /// Performs an OR-Like behavior and will "fail-over" to each successive component until Success is reached or Failure is certain - /// -Returns Success if a behavior component returns Success - /// -Returns Running if a behavior component returns Running - /// -Returns Failure if all behavior components returned Failure - /// - /// one to many behavior components - public ParallelSelector(params BehaviorComponent[] behaviors) - { - p_Behaviors = behaviors; - p_SelLength = (short)p_Behaviors.Length; - } - - /// - /// performs the given behavior - /// - /// the behaviors return code - public override BehaviorReturnCode Behave() - { - - for (int i = 0; i < p_SelLength; i++) - { - try - { - switch (p_Behaviors[i].Behave()) - { - case BehaviorReturnCode.Failure: - continue; - case BehaviorReturnCode.Success: - ReturnCode = BehaviorReturnCode.Success; - return ReturnCode; - case BehaviorReturnCode.Running: - ReturnCode = BehaviorReturnCode.Running; - return ReturnCode; - default: - continue; - } - } - catch (Exception e) - { -#if DEBUG - Console.Error.WriteLine(e.ToString()); -#endif - continue; - } - } - - - /* - while (p_Selections < p_SelLength) - { - try - { - switch (p_Behaviors[p_Selections].Behave()) - { - case BehaviorReturnCode.Failure: - p_Selections++; - continue; - case BehaviorReturnCode.Success: - p_Selections = 0; - ReturnCode = BehaviorReturnCode.Success; - return ReturnCode; - case BehaviorReturnCode.Running: - ReturnCode = BehaviorReturnCode.Running; - return ReturnCode; - default: - p_Selections++; - continue; - } - } - catch (Exception) - { - p_Selections++; - continue; - } - }*/ - - p_Selections = 0; - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - } - } -} diff --git a/BehaviorLibrary/Components/Composites/ParallelSequence.cs b/BehaviorLibrary/Components/Composites/ParallelSequence.cs deleted file mode 100644 index e08dd1f..0000000 --- a/BehaviorLibrary/Components/Composites/ParallelSequence.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace BehaviorLibrary.Components.Composites -{ - public class ParallelSequence : BehaviorComponent - { - - private BehaviorComponent[] p_Behaviors; - - /// - /// attempts to run the behaviors all in one cycle - /// -Returns Success when all are successful - /// -Returns Failure if one behavior fails or an error occurs - /// -Does not Return Running - /// - /// - public ParallelSequence(params BehaviorComponent[] behaviors) - { - p_Behaviors = behaviors; - } - - /// - /// performs the given behavior - /// - /// the behaviors return code - public override BehaviorReturnCode Behave() - { - - for(int i = 0; i < p_Behaviors.Length;i++) - { - try - { - switch (p_Behaviors[i].Behave()) - { - case BehaviorReturnCode.Failure: - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - case BehaviorReturnCode.Success: - continue; - case BehaviorReturnCode.Running: - continue; - default: - ReturnCode = BehaviorReturnCode.Success; - return ReturnCode; - } - } - catch (Exception e) - { -#if DEBUG - Console.Error.WriteLine(e.ToString()); -#endif - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - } - } - - ReturnCode = BehaviorReturnCode.Success; - return ReturnCode; - } - - - } -} diff --git a/BehaviorLibrary/Components/Composites/PartialSelector.cs b/BehaviorLibrary/Components/Composites/PartialSelector.cs new file mode 100644 index 0000000..6139e5d --- /dev/null +++ b/BehaviorLibrary/Components/Composites/PartialSelector.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Composites +{ + public class PartialSelector : BehaviorComponent + { + + protected BehaviorComponent[] _Behaviors; + + private short _selections = 0; + + private short _selLength = 0; + + /// + /// Selects among the given behavior components (one evaluation per Behave call) + /// Performs an OR-Like behavior and will "fail-over" to each successive component until Success is reached or Failure is certain + /// -Returns Success if a behavior component returns Success + /// -Returns Running if a behavior component returns Failure or Running + /// -Returns Failure if all behavior components returned Failure or an error has occured + /// + /// one to many behavior components + public PartialSelector(params BehaviorComponent[] behaviors) + { + _Behaviors = behaviors; + _selLength = (short)_Behaviors.Length; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) + { + while (_selections < _selLength) + { + try + { + switch (_Behaviors[_selections].Behave(context)) + { + case BehaviorReturnCode.Failure: + _selections++; + ReturnCode = BehaviorReturnCode.Running; + return ReturnCode; + case BehaviorReturnCode.Success: + _selections = 0; + ReturnCode = BehaviorReturnCode.Success; + return ReturnCode; + case BehaviorReturnCode.Running: + ReturnCode = BehaviorReturnCode.Running; + return ReturnCode; + default: + _selections++; + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + } + } + catch (Exception e) + { +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + _selections++; + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + } + } + + _selections = 0; + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + } + + + } +} diff --git a/BehaviorLibrary/Components/Composites/PartialSequence.cs b/BehaviorLibrary/Components/Composites/PartialSequence.cs new file mode 100644 index 0000000..e5e14f4 --- /dev/null +++ b/BehaviorLibrary/Components/Composites/PartialSequence.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Composites +{ + public class PartialSequence : BehaviorComponent + { + + protected BehaviorComponent[] _Behaviors; + + private short _sequence = 0; + + private short _seqLength = 0; + + /// + /// Performs the given behavior components sequentially (one evaluation per Behave call) + /// Performs an AND-Like behavior and will perform each successive component + /// -Returns Success if all behavior components return Success + /// -Returns Running if an individual behavior component returns Success or Running + /// -Returns Failure if a behavior components returns Failure or an error is encountered + /// + /// one to many behavior components + public PartialSequence(params BehaviorComponent[] behaviors) + { + _Behaviors = behaviors; + _seqLength = (short) _Behaviors.Length; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) + { + //while you can go through them, do so + while (_sequence < _seqLength) + { + try + { + switch (_Behaviors[_sequence].Behave(context)) + { + case BehaviorReturnCode.Failure: + _sequence = 0; + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + case BehaviorReturnCode.Success: + _sequence++; + ReturnCode = BehaviorReturnCode.Running; + return ReturnCode; + case BehaviorReturnCode.Running: + ReturnCode = BehaviorReturnCode.Running; + return ReturnCode; + } + } + catch (Exception e) + { +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + _sequence = 0; + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + } + + } + + _sequence = 0; + ReturnCode = BehaviorReturnCode.Success; + return ReturnCode; + + } + + } +} diff --git a/BehaviorLibrary/Components/Composites/RandomSelector.cs b/BehaviorLibrary/Components/Composites/RandomSelector.cs index e2ab30a..805d2ed 100644 --- a/BehaviorLibrary/Components/Composites/RandomSelector.cs +++ b/BehaviorLibrary/Components/Composites/RandomSelector.cs @@ -1,64 +1,64 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace BehaviorLibrary.Components.Composites -{ - public class RandomSelector : BehaviorComponent - { - - private BehaviorComponent[] r_Behaviors; - - //use current milliseconds to set random seed - private Random r_Random = new Random(DateTime.Now.Millisecond); - - /// - /// Randomly selects and performs one of the passed behaviors - /// -Returns Success if selected behavior returns Success - /// -Returns Failure if selected behavior returns Failure - /// -Returns Running if selected behavior returns Running - /// - /// one to many behavior components - public RandomSelector(params BehaviorComponent[] behaviors) - { - r_Behaviors = behaviors; - } - - /// - /// performs the given behavior - /// - /// the behaviors return code - public override BehaviorReturnCode Behave() - { - r_Random = new Random(DateTime.Now.Millisecond); - - try - { - switch (r_Behaviors[r_Random.Next(0, r_Behaviors.Length - 1)].Behave()) - { - case BehaviorReturnCode.Failure: - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - case BehaviorReturnCode.Success: - ReturnCode = BehaviorReturnCode.Success; - return ReturnCode; - case BehaviorReturnCode.Running: - ReturnCode = BehaviorReturnCode.Running; - return ReturnCode; - default: - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - } - } - catch (Exception e) - { -#if DEBUG - Console.Error.WriteLine(e.ToString()); -#endif - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Composites +{ + public class RandomSelector : BehaviorComponent + { + + private BehaviorComponent[] _Behaviors; + + //use current milliseconds to set random seed + private Random _Random = new Random(DateTime.Now.Millisecond); + + /// + /// Randomly selects and performs one of the passed behaviors + /// -Returns Success if selected behavior returns Success + /// -Returns Failure if selected behavior returns Failure + /// -Returns Running if selected behavior returns Running + /// + /// one to many behavior components + public RandomSelector(params BehaviorComponent[] behaviors) + { + _Behaviors = behaviors; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) + { + _Random = new Random(DateTime.Now.Millisecond); + + try + { + switch (_Behaviors[_Random.Next(0, _Behaviors.Length)].Behave(context)) + { + case BehaviorReturnCode.Failure: + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + case BehaviorReturnCode.Success: + ReturnCode = BehaviorReturnCode.Success; + return ReturnCode; + case BehaviorReturnCode.Running: + ReturnCode = BehaviorReturnCode.Running; + return ReturnCode; + default: + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + } + } + catch (Exception e) + { +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + } + } + } +} diff --git a/BehaviorLibrary/Components/Composites/Selector.cs b/BehaviorLibrary/Components/Composites/Selector.cs index 7f95035..a75d6d1 100644 --- a/BehaviorLibrary/Components/Composites/Selector.cs +++ b/BehaviorLibrary/Components/Composites/Selector.cs @@ -1,78 +1,65 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace BehaviorLibrary.Components.Composites -{ - public class Selector : BehaviorComponent - { - - protected BehaviorComponent[] s_Behaviors; - - private short selections = 0; - - private short selLength = 0; - - /// - /// Selects among the given behavior components - /// Performs an OR-Like behavior and will "fail-over" to each successive component until Success is reached or Failure is certain - /// -Returns Success if a behavior component returns Success - /// -Returns Running if a behavior component returns Failure or Running - /// -Returns Failure if all behavior components returned Failure or an error has occured - /// - /// one to many behavior components - public Selector(params BehaviorComponent[] behaviors) - { - s_Behaviors = behaviors; - selLength = (short)s_Behaviors.Length; - } - - /// - /// performs the given behavior - /// - /// the behaviors return code - public override BehaviorReturnCode Behave() - { - while (selections < selLength) - { - try - { - switch (s_Behaviors[selections].Behave()) - { - case BehaviorReturnCode.Failure: - selections++; - ReturnCode = BehaviorReturnCode.Running; - return ReturnCode; - case BehaviorReturnCode.Success: - selections = 0; - ReturnCode = BehaviorReturnCode.Success; - return ReturnCode; - case BehaviorReturnCode.Running: - ReturnCode = BehaviorReturnCode.Running; - return ReturnCode; - default: - selections++; - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - } - } - catch (Exception e) - { -#if DEBUG - Console.Error.WriteLine(e.ToString()); -#endif - selections++; - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - } - } - - selections = 0; - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - } - - - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Composites +{ + public class Selector : BehaviorComponent + { + + protected BehaviorComponent[] _Behaviors; + + + /// + /// Selects among the given behavior components + /// Performs an OR-Like behavior and will "fail-over" to each successive component until Success is reached or Failure is certain + /// -Returns Success if a behavior component returns Success + /// -Returns Running if a behavior component returns Running + /// -Returns Failure if all behavior components returned Failure + /// + /// one to many behavior components + public Selector(params BehaviorComponent[] behaviors) + { + _Behaviors = behaviors; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) + { + + for (int i = 0; i < _Behaviors.Length; i++) + { + try + { + switch (_Behaviors[i].Behave(context)) + { + case BehaviorReturnCode.Failure: + continue; + case BehaviorReturnCode.Success: + ReturnCode = BehaviorReturnCode.Success; + return ReturnCode; + case BehaviorReturnCode.Running: + ReturnCode = BehaviorReturnCode.Running; + return ReturnCode; + default: + continue; + } + } + catch (Exception e) + { +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + continue; + } + } + + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + } + } +} diff --git a/BehaviorLibrary/Components/Composites/Sequence.cs b/BehaviorLibrary/Components/Composites/Sequence.cs index 9f1de9d..de3c36b 100644 --- a/BehaviorLibrary/Components/Composites/Sequence.cs +++ b/BehaviorLibrary/Components/Composites/Sequence.cs @@ -1,76 +1,70 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace BehaviorLibrary.Components.Composites -{ - public class Sequence : BehaviorComponent - { - - protected BehaviorComponent[] s_Behaviors; - - private short sequence = 0; - - private short seqLength = 0; - - /// - /// Performs the given behavior components sequentially - /// Performs an AND-Like behavior and will perform each successive component - /// -Returns Success if all behavior components return Success - /// -Returns Running if an individual behavior component returns Success or Running - /// -Returns Failure if a behavior components returns Failure or an error is encountered - /// - /// one to many behavior components - public Sequence(params BehaviorComponent[] behaviors) - { - s_Behaviors = behaviors; - seqLength = (short) s_Behaviors.Length; - } - - /// - /// performs the given behavior - /// - /// the behaviors return code - public override BehaviorReturnCode Behave() - { - //while you can go through them, do so - while (sequence < seqLength) - { - try - { - switch (s_Behaviors[sequence].Behave()) - { - case BehaviorReturnCode.Failure: - sequence = 0; - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - case BehaviorReturnCode.Success: - sequence++; - ReturnCode = BehaviorReturnCode.Running; - return ReturnCode; - case BehaviorReturnCode.Running: - ReturnCode = BehaviorReturnCode.Running; - return ReturnCode; - } - } - catch (Exception e) - { -#if DEBUG - Console.Error.WriteLine(e.ToString()); -#endif - sequence = 0; - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - } - - } - - sequence = 0; - ReturnCode = BehaviorReturnCode.Success; - return ReturnCode; - - } - - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Composites +{ + public class Sequence : BehaviorComponent + { + + private BehaviorComponent[] _behaviors; + + /// + /// attempts to run the behaviors all in one cycle + /// -Returns Success when all are successful + /// -Returns Failure if one behavior fails or an error occurs + /// -Returns Running if any are running + /// + /// + public Sequence(params BehaviorComponent[] behaviors) + { + _behaviors = behaviors; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) + { + //add watch for any running behaviors + bool anyRunning = false; + + for(int i = 0; i < _behaviors.Length;i++) + { + try + { + switch (_behaviors[i].Behave(context)) + { + case BehaviorReturnCode.Failure: + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + case BehaviorReturnCode.Success: + continue; + case BehaviorReturnCode.Running: + anyRunning = true; + continue; + default: + ReturnCode = BehaviorReturnCode.Success; + return ReturnCode; + } + } + catch (Exception e) + { +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + } + } + + //if none running, return success, otherwise return running + ReturnCode = !anyRunning ? BehaviorReturnCode.Success : BehaviorReturnCode.Running; + return ReturnCode; + } + + + } +} diff --git a/BehaviorLibrary/Components/Composites/StatefulSelector.cs b/BehaviorLibrary/Components/Composites/StatefulSelector.cs new file mode 100644 index 0000000..6afa664 --- /dev/null +++ b/BehaviorLibrary/Components/Composites/StatefulSelector.cs @@ -0,0 +1,59 @@ +using System; +using BehaviorLibrary.Components; + +namespace BehaviorLibrary +{ + public class StatefulSelector : BehaviorComponent + { + private BehaviorComponent[] _Behaviors; + + private int _LastBehavior = 0; + + /// + /// Selects among the given behavior components (stateful on running) + /// Performs an OR-Like behavior and will "fail-over" to each successive component until Success is reached or Failure is certain + /// -Returns Success if a behavior component returns Success + /// -Returns Running if a behavior component returns Running + /// -Returns Failure if all behavior components returned Failure + /// + /// one to many behavior components + public StatefulSelector(params BehaviorComponent[] behaviors){ + this._Behaviors = behaviors; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) { + + for(; _LastBehavior < _Behaviors.Length; _LastBehavior++){ + try{ + switch (_Behaviors[_LastBehavior].Behave(context)){ + case BehaviorReturnCode.Failure: + continue; + case BehaviorReturnCode.Success: + _LastBehavior = 0; + ReturnCode = BehaviorReturnCode.Success; + return ReturnCode; + case BehaviorReturnCode.Running: + ReturnCode = BehaviorReturnCode.Running; + return ReturnCode; + default: + continue; + } + } + catch (Exception e){ +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + continue; + } + } + + _LastBehavior = 0; + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + } + } +} diff --git a/BehaviorLibrary/Components/Composites/StatefulSequence.cs b/BehaviorLibrary/Components/Composites/StatefulSequence.cs new file mode 100644 index 0000000..da69638 --- /dev/null +++ b/BehaviorLibrary/Components/Composites/StatefulSequence.cs @@ -0,0 +1,66 @@ +using System; +using BehaviorLibrary.Components; + +namespace BehaviorLibrary +{ + public class StatefulSequence : BehaviorComponent + { + private BehaviorComponent[] _Behaviors; + + private int _LastBehavior = 0; + + /// + /// attempts to run the behaviors all in one cycle (stateful on running) + /// -Returns Success when all are successful + /// -Returns Failure if one behavior fails or an error occurs + /// -Does not Return Running + /// + /// + public StatefulSequence (params BehaviorComponent[] behaviors){ + this._Behaviors = behaviors; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) { + + //start from last remembered position + for(; _LastBehavior < _Behaviors.Length;_LastBehavior++){ + try{ + switch (_Behaviors[_LastBehavior].Behave(context)){ + case BehaviorReturnCode.Failure: + _LastBehavior = 0; + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + case BehaviorReturnCode.Success: + continue; + case BehaviorReturnCode.Running: + ReturnCode = BehaviorReturnCode.Running; + return ReturnCode; + default: + _LastBehavior = 0; + ReturnCode = BehaviorReturnCode.Success; + return ReturnCode; + } + } + catch (Exception e){ +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + _LastBehavior = 0; + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + } + } + + _LastBehavior = 0; + ReturnCode = BehaviorReturnCode.Success; + return ReturnCode; + } + + + } +} + diff --git a/BehaviorLibrary/Components/Conditionals/Conditional.cs b/BehaviorLibrary/Components/Conditionals/Conditional.cs index db79631..f663353 100644 --- a/BehaviorLibrary/Components/Conditionals/Conditional.cs +++ b/BehaviorLibrary/Components/Conditionals/Conditional.cs @@ -1,56 +1,56 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace BehaviorLibrary.Components.Conditionals -{ - public class Conditional : BehaviorComponent - { - - private Func c_Bool; - - /// - /// Returns a return code equivalent to the test - /// -Returns Success if true - /// -Returns Failure if false - /// - /// the value to be tested - public Conditional(Func test) - { - c_Bool = test; - } - - /// - /// performs the given behavior - /// - /// the behaviors return code - public override BehaviorReturnCode Behave() - { - - try - { - switch (c_Bool.Invoke()) - { - case true: - ReturnCode = BehaviorReturnCode.Success; - return ReturnCode; - case false: - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - default: - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - } - } - catch (Exception e) - { -#if DEBUG - Console.Error.WriteLine(e.ToString()); -#endif - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Conditionals +{ + public class Conditional : BehaviorComponent + { + + private Func _Bool; + + /// + /// Returns a return code equivalent to the test + /// -Returns Success if true + /// -Returns Failure if false + /// + /// the value to be tested + public Conditional(Func test) + { + _Bool = test; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) + { + + try + { + switch (_Bool.Invoke()) + { + case true: + ReturnCode = BehaviorReturnCode.Success; + return ReturnCode; + case false: + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + default: + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + } + } + catch (Exception e) + { +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + } + } + } +} diff --git a/BehaviorLibrary/Components/Decorators/Awaiter.cs b/BehaviorLibrary/Components/Decorators/Awaiter.cs new file mode 100644 index 0000000..e259e7f --- /dev/null +++ b/BehaviorLibrary/Components/Decorators/Awaiter.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Decorators +{ + public class Awaiter : BehaviorComponent + { + private Func condition; + private BehaviorComponent behavior; + + /// + /// executes the behavior after a condition is true. + /// + /// the condition + /// behavior to run + public Awaiter(Func conditon, BehaviorComponent behavior) + { + this.condition = conditon; + this.behavior = behavior; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) + { + try + { + if (this.condition.Invoke()) + { + return this.behavior.Behave(context); + } + else + { + return BehaviorReturnCode.Running; + } + } + catch (Exception e) + { +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + return BehaviorReturnCode.Failure; + } + } + } +} diff --git a/BehaviorLibrary/Components/Decorators/Counter.cs b/BehaviorLibrary/Components/Decorators/Counter.cs index a51f377..fa93a53 100644 --- a/BehaviorLibrary/Components/Decorators/Counter.cs +++ b/BehaviorLibrary/Components/Decorators/Counter.cs @@ -1,59 +1,59 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace BehaviorLibrary.Components.Decorators -{ - public class Counter : BehaviorComponent - { - private int c_MaxCount; - private int c_Counter = 0; - - private BehaviorComponent c_Behavior; - - /// - /// executes the behavior based on a counter - /// -each time Counter is called the counter increments by 1 - /// -Counter executes the behavior when it reaches the supplied maxCount - /// - /// max number to count to - /// behavior to run - public Counter(int maxCount, BehaviorComponent behavior) - { - c_MaxCount = maxCount; - c_Behavior = behavior; - } - - /// - /// performs the given behavior - /// - /// the behaviors return code - public override BehaviorReturnCode Behave() - { - try - { - if (c_Counter < c_MaxCount) - { - c_Counter++; - ReturnCode = BehaviorReturnCode.Running; - return BehaviorReturnCode.Running; - } - else - { - c_Counter = 0; - ReturnCode = c_Behavior.Behave(); - return ReturnCode; - } - } - catch (Exception e) - { -#if DEBUG - Console.Error.WriteLine(e.ToString()); -#endif - ReturnCode = BehaviorReturnCode.Failure; - return BehaviorReturnCode.Failure; - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Decorators +{ + public class Counter : BehaviorComponent + { + private int _MaxCount; + private int _Counter = 0; + + private BehaviorComponent _Behavior; + + /// + /// executes the behavior based on a counter + /// -each time Counter is called the counter increments by 1 + /// -Counter executes the behavior when it reaches the supplied maxCount + /// + /// max number to count to + /// behavior to run + public Counter(int maxCount, BehaviorComponent behavior) + { + _MaxCount = maxCount; + _Behavior = behavior; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) + { + try + { + if (_Counter < _MaxCount) + { + _Counter++; + ReturnCode = BehaviorReturnCode.Running; + return BehaviorReturnCode.Running; + } + else + { + _Counter = 0; + ReturnCode = _Behavior.Behave(context); + return ReturnCode; + } + } + catch (Exception e) + { +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + ReturnCode = BehaviorReturnCode.Failure; + return BehaviorReturnCode.Failure; + } + } + } +} diff --git a/BehaviorLibrary/Components/Decorators/Failer.cs b/BehaviorLibrary/Components/Decorators/Failer.cs new file mode 100644 index 0000000..c326ed4 --- /dev/null +++ b/BehaviorLibrary/Components/Decorators/Failer.cs @@ -0,0 +1,31 @@ +namespace BehaviorLibrary.Components.Decorators +{ + public class Failer : BehaviorComponent + { + private BehaviorComponent behavior; + + /// + /// Returns a failure even when the decorated component succeeded or is running. + /// + /// behavior to run + public Failer(BehaviorComponent behavior) + { + this.behavior = behavior; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) + { + this.ReturnCode = behavior.Behave(context); + if (this.ReturnCode == BehaviorReturnCode.Success || this.ReturnCode == BehaviorReturnCode.Running) + { + this.ReturnCode = BehaviorReturnCode.Failure; + } + + return this.ReturnCode; + } + } +} diff --git a/BehaviorLibrary/Components/Decorators/Inverter.cs b/BehaviorLibrary/Components/Decorators/Inverter.cs index 1a75f74..c7ad72b 100644 --- a/BehaviorLibrary/Components/Decorators/Inverter.cs +++ b/BehaviorLibrary/Components/Decorators/Inverter.cs @@ -1,61 +1,61 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace BehaviorLibrary.Components.Decorators -{ - public class Inverter : BehaviorComponent - { - - private BehaviorComponent d_Behavior; - - /// - /// inverts the given behavior - /// -Returns Success on Failure or Error - /// -Returns Failure on Success - /// -Returns Running on Running - /// - /// - public Inverter(BehaviorComponent behavior) - { - d_Behavior = behavior; - } - - /// - /// performs the given behavior - /// - /// the behaviors return code - public override BehaviorReturnCode Behave() - { - try - { - switch (d_Behavior.Behave()) - { - case BehaviorReturnCode.Failure: - ReturnCode = BehaviorReturnCode.Success; - return ReturnCode; - case BehaviorReturnCode.Success: - ReturnCode = BehaviorReturnCode.Failure; - return ReturnCode; - case BehaviorReturnCode.Running: - ReturnCode = BehaviorReturnCode.Running; - return ReturnCode; - } - } - catch (Exception e) - { -#if DEBUG - Console.Error.WriteLine(e.ToString()); -#endif - ReturnCode = BehaviorReturnCode.Success; - return ReturnCode; - } - - ReturnCode = BehaviorReturnCode.Success; - return ReturnCode; - - } - - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Decorators +{ + public class Inverter : BehaviorComponent + { + + private BehaviorComponent _Behavior; + + /// + /// inverts the given behavior + /// -Returns Success on Failure or Error + /// -Returns Failure on Success + /// -Returns Running on Running + /// + /// + public Inverter(BehaviorComponent behavior) + { + _Behavior = behavior; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) + { + try + { + switch (_Behavior.Behave(context)) + { + case BehaviorReturnCode.Failure: + ReturnCode = BehaviorReturnCode.Success; + return ReturnCode; + case BehaviorReturnCode.Success: + ReturnCode = BehaviorReturnCode.Failure; + return ReturnCode; + case BehaviorReturnCode.Running: + ReturnCode = BehaviorReturnCode.Running; + return ReturnCode; + } + } + catch (Exception e) + { +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + ReturnCode = BehaviorReturnCode.Success; + return ReturnCode; + } + + ReturnCode = BehaviorReturnCode.Success; + return ReturnCode; + + } + + } +} diff --git a/BehaviorLibrary/Components/Decorators/RandomDecorator.cs b/BehaviorLibrary/Components/Decorators/RandomDecorator.cs index 4273243..e65fd4f 100644 --- a/BehaviorLibrary/Components/Decorators/RandomDecorator.cs +++ b/BehaviorLibrary/Components/Decorators/RandomDecorator.cs @@ -1,56 +1,56 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace BehaviorLibrary.Components.Decorators -{ - public class RandomDecorator : BehaviorComponent - { - - private float r_Probability; - - private Func r_RandomFunction; - - private BehaviorComponent r_Behavior; - - /// - /// randomly executes the behavior - /// - /// probability of execution - /// function that determines probability to execute - /// behavior to execute - public RandomDecorator(float probability, Func randomFunction, BehaviorComponent behavior) - { - r_Probability = probability; - r_RandomFunction = randomFunction; - r_Behavior = behavior; - } - - - public override BehaviorReturnCode Behave() - { - try - { - if (r_RandomFunction.Invoke() <= r_Probability) - { - ReturnCode = r_Behavior.Behave(); - return ReturnCode; - } - else - { - ReturnCode = BehaviorReturnCode.Running; - return BehaviorReturnCode.Running; - } - } - catch (Exception e) - { -#if DEBUG - Console.Error.WriteLine(e.ToString()); -#endif - ReturnCode = BehaviorReturnCode.Failure; - return BehaviorReturnCode.Failure; - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Decorators +{ + public class RandomDecorator : BehaviorComponent + { + + private float _Probability; + + private Func _RandomFunction; + + private BehaviorComponent _Behavior; + + /// + /// randomly executes the behavior + /// + /// probability of execution + /// function that determines probability to execute + /// behavior to execute + public RandomDecorator(float probability, Func randomFunction, BehaviorComponent behavior) + { + _Probability = probability; + _RandomFunction = randomFunction; + _Behavior = behavior; + } + + + public override BehaviorReturnCode OnBehave(TreeContext context) + { + try + { + if (_RandomFunction.Invoke() <= _Probability) + { + ReturnCode = _Behavior.Behave(context); + return ReturnCode; + } + else + { + ReturnCode = BehaviorReturnCode.Running; + return BehaviorReturnCode.Running; + } + } + catch (Exception e) + { +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + ReturnCode = BehaviorReturnCode.Failure; + return BehaviorReturnCode.Failure; + } + } + } +} diff --git a/BehaviorLibrary/Components/Decorators/RepeatUntilFail.cs b/BehaviorLibrary/Components/Decorators/RepeatUntilFail.cs new file mode 100644 index 0000000..be406d3 --- /dev/null +++ b/BehaviorLibrary/Components/Decorators/RepeatUntilFail.cs @@ -0,0 +1,41 @@ +using System; +using BehaviorLibrary; +using BehaviorLibrary.Components; +using BehaviorLibrary.Components.Composites; +using BehaviorLibrary.Components.Actions; +using BehaviorLibrary.Components.Conditionals; +using BehaviorLibrary.Components.Decorators; +using BehaviorLibrary.Components.Utility; + +namespace BehaviorLibrary.Components.Decorators +{ + public class RepeatUntilFail : BehaviorComponent + { + private BehaviorComponent _Behavior; + + /// + /// executes the behavior every time again + /// + /// maximum time to wait before executing behavior + /// behavior to run + public RepeatUntilFail(BehaviorComponent behavior) + { + _Behavior = behavior; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) + { + ReturnCode = _Behavior.Behave(context); + if (ReturnCode == BehaviorReturnCode.Failure) { + return BehaviorReturnCode.Failure; + } else { + ReturnCode = BehaviorReturnCode.Running; + return BehaviorReturnCode.Running; + } + } + } +} diff --git a/BehaviorLibrary/Components/Decorators/Repeater.cs b/BehaviorLibrary/Components/Decorators/Repeater.cs new file mode 100644 index 0000000..404ea19 --- /dev/null +++ b/BehaviorLibrary/Components/Decorators/Repeater.cs @@ -0,0 +1,37 @@ +using System; +using BehaviorLibrary; +using BehaviorLibrary.Components; +using BehaviorLibrary.Components.Composites; +using BehaviorLibrary.Components.Actions; +using BehaviorLibrary.Components.Conditionals; +using BehaviorLibrary.Components.Decorators; +using BehaviorLibrary.Components.Utility; + +namespace BehaviorLibrary.Components.Decorators +{ + public class Repeater : BehaviorComponent + { + private BehaviorComponent _Behavior; + + /// + /// executes the behavior every time again + /// + /// maximum time to wait before executing behavior + /// behavior to run + public Repeater(BehaviorComponent behavior) + { + _Behavior = behavior; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) + { + ReturnCode = _Behavior.Behave(context); + ReturnCode = BehaviorReturnCode.Running; + return BehaviorReturnCode.Running; + } + } +} diff --git a/BehaviorLibrary/Components/Decorators/Succeeder.cs b/BehaviorLibrary/Components/Decorators/Succeeder.cs new file mode 100644 index 0000000..991ca54 --- /dev/null +++ b/BehaviorLibrary/Components/Decorators/Succeeder.cs @@ -0,0 +1,38 @@ +using System; +using BehaviorLibrary; +using BehaviorLibrary.Components; +using BehaviorLibrary.Components.Composites; +using BehaviorLibrary.Components.Actions; +using BehaviorLibrary.Components.Conditionals; +using BehaviorLibrary.Components.Decorators; +using BehaviorLibrary.Components.Utility; + +namespace BehaviorLibrary.Components.Decorators +{ + public class Succeeder : BehaviorComponent + { + private BehaviorComponent _Behavior; + + /// + /// returns a success even when the decorated component failed + /// + /// behavior to run + public Succeeder(BehaviorComponent behavior) + { + _Behavior = behavior; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) + { + ReturnCode = _Behavior.Behave(context); + if (ReturnCode == BehaviorReturnCode.Failure) { + ReturnCode = BehaviorReturnCode.Success; + } + return ReturnCode; + } + } +} diff --git a/BehaviorLibrary/Components/Decorators/Timer.cs b/BehaviorLibrary/Components/Decorators/Timer.cs index 7004dc8..8f76961 100644 --- a/BehaviorLibrary/Components/Decorators/Timer.cs +++ b/BehaviorLibrary/Components/Decorators/Timer.cs @@ -1,64 +1,64 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace BehaviorLibrary.Components.Decorators -{ - public class Timer : BehaviorComponent - { - - private Func t_ElapsedTimeFunction; - - private BehaviorComponent t_Behavior; - - private int t_TimeElapsed = 0; - - private int t_WaitTime; - - /// - /// executes the behavior after a given amount of time in miliseconds has passed - /// - /// function that returns elapsed time - /// maximum time to wait before executing behavior - /// behavior to run - public Timer(Func elapsedTimeFunction, int timeToWait, BehaviorComponent behavior) - { - t_ElapsedTimeFunction = elapsedTimeFunction; - t_Behavior = behavior; - t_WaitTime = timeToWait; - } - - /// - /// performs the given behavior - /// - /// the behaviors return code - public override BehaviorReturnCode Behave() - { - try - { - t_TimeElapsed += t_ElapsedTimeFunction.Invoke(); - - if (t_TimeElapsed >= t_WaitTime) - { - t_TimeElapsed = 0; - ReturnCode = t_Behavior.Behave(); - return ReturnCode; - } - else - { - ReturnCode = BehaviorReturnCode.Running; - return BehaviorReturnCode.Running; - } - } - catch (Exception e) - { -#if DEBUG - Console.Error.WriteLine(e.ToString()); -#endif - ReturnCode = BehaviorReturnCode.Failure; - return BehaviorReturnCode.Failure; - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Decorators +{ + public class Timer : BehaviorComponent + { + + private Func _ElapsedTimeFunction; + + private BehaviorComponent _Behavior; + + private int _TimeElapsed = 0; + + private int _WaitTime; + + /// + /// executes the behavior after a given amount of time in miliseconds has passed + /// + /// function that returns elapsed time + /// maximum time to wait before executing behavior + /// behavior to run + public Timer(Func elapsedTimeFunction, int timeToWait, BehaviorComponent behavior) + { + _ElapsedTimeFunction = elapsedTimeFunction; + _Behavior = behavior; + _WaitTime = timeToWait; + } + + /// + /// performs the given behavior + /// + /// the behaviors return code + public override BehaviorReturnCode OnBehave(TreeContext context) + { + try + { + _TimeElapsed += _ElapsedTimeFunction.Invoke(); + + if (_TimeElapsed >= _WaitTime) + { + _TimeElapsed = 0; + ReturnCode = _Behavior.Behave(context); + return ReturnCode; + } + else + { + ReturnCode = BehaviorReturnCode.Running; + return BehaviorReturnCode.Running; + } + } + catch (Exception e) + { +#if DEBUG + Console.Error.WriteLine(e.ToString()); +#endif + ReturnCode = BehaviorReturnCode.Failure; + return BehaviorReturnCode.Failure; + } + } + } +} diff --git a/BehaviorLibrary/Components/Utility/UtilityPair.cs b/BehaviorLibrary/Components/Utility/UtilityPair.cs new file mode 100644 index 0000000..25edc05 --- /dev/null +++ b/BehaviorLibrary/Components/Utility/UtilityPair.cs @@ -0,0 +1,39 @@ +// +// UtilityPair.cs +// +// Author: +// Thomas H. Jonell <@Net_Gnome> +// +// Copyright (c) 2014 Thomas H. Jonell +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Utility +{ + public class UtilityPair + { + public UtilityPair(UtilityVector vector, BehaviorComponent behavior) + { + this.vector = vector; + this.behavior = behavior; + } + + public UtilityVector vector { get; set; } + public BehaviorComponent behavior { get; set; } + } +} diff --git a/BehaviorLibrary/Components/Utility/UtilitySelector.cs b/BehaviorLibrary/Components/Utility/UtilitySelector.cs new file mode 100644 index 0000000..57780bf --- /dev/null +++ b/BehaviorLibrary/Components/Utility/UtilitySelector.cs @@ -0,0 +1,77 @@ +// +// UtilitySelector.cs +// +// Author: +// Thomas H. Jonell <@Net_Gnome> +// +// Copyright (c) 2014 Thomas H. Jonell +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Utility +{ + public class UtilitySelector : BehaviorComponent + { + private UtilityPair[] _utility_pairs; + private Func _utility_function; + + public UtilitySelector(Func utility_function, params UtilityPair[] pairs) + { + this._utility_pairs = pairs; + this._utility_function = utility_function; + } + + public override BehaviorReturnCode OnBehave(TreeContext context) + { + try{ + UtilityVector func_vector = this._utility_function.Invoke (); + + float min = -2.0f; + UtilityPair best_match = null; + + //find max pair match + foreach(UtilityPair pair in this._utility_pairs){ + float val = func_vector.dot(pair.vector); + if(val > min){ + min = val; + best_match = pair; + } + } + + //make sure we found a match + if(best_match == null){ + #if DEBUG + Console.WriteLine("best_match not defined..."); + #endif + this.ReturnCode = BehaviorReturnCode.Failure; + return this.ReturnCode; + } + + //execute best pair match and return result + this.ReturnCode = best_match.behavior.Behave(context); + return this.ReturnCode; + }catch(Exception e){ + #if DEBUG + Console.WriteLine(e.ToString()); + #endif + this.ReturnCode = BehaviorReturnCode.Failure; + return BehaviorReturnCode.Failure; + } + } + } +} diff --git a/BehaviorLibrary/Components/Utility/UtilityVector.cs b/BehaviorLibrary/Components/Utility/UtilityVector.cs new file mode 100644 index 0000000..aed7248 --- /dev/null +++ b/BehaviorLibrary/Components/Utility/UtilityVector.cs @@ -0,0 +1,85 @@ +// +// UtilityVector.cs +// +// Author: +// Thomas H. Jonell <@Net_Gnome> +// +// Copyright (c) 2014 Thomas H. Jonell +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BehaviorLibrary.Components.Utility +{ + public class UtilityVector + { + public UtilityVector(params float[] values){ + this.values = values; + } + + public float[] values{ get; set; } + + //return the magnitude of this vector + public float magnitude{ + get{ + float mag = 0; + for (int i = 0; i < this.values.Length; i++) + mag += this.values [i] * this.values [i]; + + return (float) Math.Sqrt (mag); + } + } + + /// + /// Return a new vector based on the normalization of this instance. + /// + public UtilityVector normalize(){ + if (this.values.Length <= 0) + return null; + + UtilityVector vec = new UtilityVector(); + vec.values = new float[this.values.Length]; + this.values.CopyTo (vec.values, 0); + + float mag = vec.magnitude; + + for (int i = 0; i < vec.values.Length; i++) + vec.values [i] = vec.values [i] / mag; + + return vec; + } + + /// + /// Dot between this and another specified vector. (based on normalized vectors) + /// + /// Vector. + public float dot(UtilityVector vector){ + if (this.magnitude == 0 || vector.magnitude == 0) + return -2; + + UtilityVector a = this.normalize (); + UtilityVector b = vector.normalize (); + + float val = 0; + + for (int i = 0; i < this.values.Length; i++) + val += a.values [i] * b.values [i]; + + return val; + } + } +} \ No newline at end of file diff --git a/BehaviorLibrary/TreeContext.cs b/BehaviorLibrary/TreeContext.cs new file mode 100644 index 0000000..5274ca0 --- /dev/null +++ b/BehaviorLibrary/TreeContext.cs @@ -0,0 +1,96 @@ +using BehaviorLibrary.Components; +using BehaviorLibrary.Components.Actions; +using System.Collections.Generic; + +namespace BehaviorLibrary +{ + public class TreeContext + { + private List calling; + private List called; + private int callCount; + private List onNotCalledBehaviors; + private bool isInvokingFinalizer; + + public TreeContext() + { + this.calling = new List(); + this.called = new List(); + this.onNotCalledBehaviors = new List(); + } + + public BehaviorComponent[] Calling { get { return this.calling.ToArray(); } } + public BehaviorComponent[] Called { get { return this.called.ToArray(); } } + + public TreeContext(TreeContext oldContext) : this() + { + this.OldContext = oldContext; + } + + public CallHierarchy CallingHierarchy + { + get + { + return new CallHierarchy(this.calling); + } + } + + public TreeContext OldContext { get; private set; } + + private void AddToCalling(BehaviorComponent behavior) + { + this.calling.Add(behavior); + } + + private void AddToCalled(BehaviorComponent behavior) + { + this.called.Add(behavior); + } + + public bool HasBeenCalled(BehaviorComponent behavior) + { + return this.called.Contains(behavior); + } + + public bool IsCalling(BehaviorComponent behavior) + { + return this.calling.Contains(behavior); + } + + public void OnAboutToCall(BehaviorComponent caller) + { + this.AddToCalling(caller); + this.callCount++; + } + + public void RegisterOnNotCalledBehavior(OnNotCalled onNotCalledBehavior) + { + this.onNotCalledBehaviors.Add(onNotCalledBehavior); + } + + public void OnCalled(BehaviorComponent called, BehaviorReturnCode result) + { + this.AddToCalled(called); + + // Check if we just called the root node, so are done with the tree. + if (!this.isInvokingFinalizer && this.calling.Count > 0 && this.calling[0] == called) + { + this.ProcessFinalizers(this.calling[0]); + } + } + + private void ProcessFinalizers(BehaviorComponent rootNode) + { + if (this.OldContext == null) return; + foreach (var onNotCalledBehavior in this.OldContext.onNotCalledBehaviors) + { + if (!this.HasBeenCalled(onNotCalledBehavior)) + { + this.isInvokingFinalizer = true; + onNotCalledBehavior.InvokeFinalizer(this); + this.isInvokingFinalizer = false; + } + } + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index bafd1b8..8963121 100644 --- a/README.md +++ b/README.md @@ -3,17 +3,38 @@ Behavior Library BehaviorLibrary is a framework for creating behavior trees for game AI. It is free to use, modify, and redestribute as covered under the attached License (FreeBSD). +Changes +------- + +RootSelector has been refactored to IndexSelector. It works exactly the same, just has a more appropriate name. + +Behavior has had an additional constructor added that allows BehaviorComponent objects to be used rather than just RootSelector/IndexSelector objects. + +Merged in new Repeater, Succeeder, RepeatUntilFail Decorators. + + +Utilities +--------- + +Added Utility components, see Utility Test cases for test examples. + +The basic point is to use a vector of floating numbers representing weights/values that will be paired with a BehaviorComponent object. When a UtilitySelector is called, it will execute a function that returns a UtilityVector that will then be compared against the BehaviorComponents' paired vectors (via a dot product) and select the pair that best matches and execute its Behavior. + + +Example +------- + It is simple to use and with that simplicity comes performance. Example of a simple A* following AI on a tilemap //setup all coniditionals and their delegate functions - Coniditional tooClose = new Conditional(isTooClose); - Coniditional targetMoved = new Conditional(hasTargetMoved); - Coniditional pathFound = new Conditional(hasPathBeenFound); - Coniditional reachedCell = new Conditional(hasReachedCell); - Coniditional reachedTarget = new Conditional(hasReachedTarget); - Coniditional isNewPath = new Conditional(hasNewPath); + Conditional tooClose = new Conditional(isTooClose); + Conditional targetMoved = new Conditional(hasTargetMoved); + Conditional pathFound = new Conditional(hasPathBeenFound); + Conditional reachedCell = new Conditional(hasReachedCell); + Conditional reachedTarget = new Conditional(hasReachedTarget); + Conditional isNewPath = new Conditional(hasNewPath); //setup all actions and their delegate functions BehaviorAction moveToCell = new BehaviorAction(moveTowardsCell); @@ -27,20 +48,20 @@ Example of a simple A* following AI on a tilemap BehaviorAction animate = new BehaviorAction(updateAnimation); //setup an initilization branch - ParallelSequence initialize = new ParallelSequence(initPathfinder, calcPath); + Sequence initialize = new Sequence(initPathfinder, calcPath); //if the target has moved, reset and calculate a new path - ParallelSelector ifMovedCreateNewPath = new ParallelSelector(new Inverter(targetMoved), new Inverter(reset), calcPath); - ParallelSelector ifPathFoundGetPath = new ParallelSelector(new Inverter(pathFound), getPath); - ParallelSelector ifPathNewUseIt = new ParallelSelector(new Inverter(isNewPath), setPath); - ParallelSelector ifReachedCellGetNext = new ParallelSelector(new Inverter(reachedCell), getNextCell); - ParallelSelector ifNotReachedTargetMoveTowardsCell = new ParallelSelector(reachedTarget, moveToCell); + Selector ifMovedCreateNewPath = new Selector(new Inverter(targetMoved), new Inverter(reset), calcPath); + Selector ifPathFoundGetPath = new Selector(new Inverter(pathFound), getPath); + Selector ifPathNewUseIt = new Selector(new Inverter(isNewPath), setPath); + Selector ifReachedCellGetNext = new Selector(new Inverter(reachedCell), getNextCell); + Selector ifNotReachedTargetMoveTowardsCell = new Selector(reachedTarget, moveToCell); //follow target so long as you're not too close and then animate - ParallelSequence follow = new ParallelSequence(new Inverter(tooClose), updatePosition, ifMovedCreateNewPath, ifPathFoundGetPath, ifPathIsNewUseIt, ifReachedCellGetNext, ifNotReachedTargetMoveTowardsCell, animate); + Sequence follow = new Sequence(new Inverter(tooClose), updatePosition, ifMovedCreateNewPath, ifPathFoundGetPath, ifPathIsNewUseIt, ifReachedCellGetNext, ifNotReachedTargetMoveTowardsCell, animate); //setup root node, choose initialization phase or pathing/movement phase - RootSelector root = new RootSelector(switchBehaviors, initialize, follow); + IndexSelector root = new IndexSelector(switchBehaviors, initialize, follow); //set a reference to the root Behavior behavior = new Behavior(root); diff --git a/Tests/Issue2.cs b/Tests/Issue2.cs new file mode 100644 index 0000000..b1889cf --- /dev/null +++ b/Tests/Issue2.cs @@ -0,0 +1,85 @@ +using System; +using CSTester; +using CSLogging; +using BehaviorLibrary; +using BehaviorLibrary.Components; +using BehaviorLibrary.Components.Composites; +using BehaviorLibrary.Components.Actions; + +namespace Tests +{ + [TestCase] + public class Issue2 + { + public Issue2 () + { + } + + CSLogger _log = CSLogger.Instance; + + [BuildUp] + public void buildup(){ + _log.setEnableLogging (true); + _log.setEnableDebug (true); + _log.setEnableError (true); + _log.setEnableMessage (true); + _log.loadLog ("./", "issue2.log"); + _log.enterScope ("buildup"); + _log.logMessage ("---------- BEGIN TESTING ISSUE 2 ----------"); + _log.exitScope (); + } + + [TearDown] + public void teardown(){ + _log.enterScope ("teardown"); + _log.logMessage ("---------- END TESTING ISSUE 2 ----------"); + _log.exitScope (); + _log.closeLog (); + } + + [Test] + public void test1(){ + _log.enterScope ("test1"); + + var foo = new Sequence (new BehaviorAction (delegate() { + return BehaviorReturnCode.Running; + }), new BehaviorAction (delegate() { + return BehaviorReturnCode.Running; + }), new BehaviorAction (delegate() { + return BehaviorReturnCode.Running; + }), new BehaviorAction (delegate() { + return BehaviorReturnCode.Running; + })); + + Verify.VerifyEquals ("all running is running", true, foo.Behave(), BehaviorReturnCode.Running); + + foo = new Sequence (new BehaviorAction (delegate() { + return BehaviorReturnCode.Running; + }), new BehaviorAction (delegate() { + return BehaviorReturnCode.Running; + }), new BehaviorAction (delegate() { + return BehaviorReturnCode.Running; + }), new BehaviorAction (delegate() { + return BehaviorReturnCode.Success; + })); + + Verify.VerifyEquals ("all but one running is running", true, foo.Behave(), BehaviorReturnCode.Running); + + foo = new Sequence (new BehaviorAction (delegate() { + return BehaviorReturnCode.Success; + }), new BehaviorAction (delegate() { + return BehaviorReturnCode.Success; + }), new BehaviorAction (delegate() { + return BehaviorReturnCode.Success; + }), new BehaviorAction (delegate() { + return BehaviorReturnCode.Success; + })); + + Verify.VerifyEquals ("all success is success", true, foo.Behave(), BehaviorReturnCode.Success); + + + _log.exitScope (); + } + } +} + diff --git a/Tests/Issue7.cs b/Tests/Issue7.cs new file mode 100644 index 0000000..f7f7f04 --- /dev/null +++ b/Tests/Issue7.cs @@ -0,0 +1,85 @@ +using System; +using CSTester; +using CSLogging; +using BehaviorLibrary; +using BehaviorLibrary.Components.Composites; +using BehaviorLibrary.Components.Actions; + +namespace Tests +{ + [TestCase] + public class Issue7 + { + public Issue7 () + { + } + + private CSLogger _log = CSLogger.Instance; + + [BuildUp] + public void build_up(){ + _log.setEnableLogging (true); + _log.setEnableDebug (true); + _log.setEnableError (true); + _log.setEnableMessage (true); + _log.loadLog ("./", "issue7.log"); + _log.enterScope (); + _log.logMessage ("---------- BEGIN TESTING ISSUE 7 ----------"); + _log.exitScope (); + + } + + [TearDown] + public void tear_down(){ + _log.enterScope (); + _log.logMessage ("---------- END TESTING ISSUE 7 ----------"); + _log.exitScope (); + _log.closeLog (); + } + + private int[] counts = new int[4]; + + public BehaviorReturnCode component_1(){ + counts [0]++; + + return BehaviorReturnCode.Success; + } + + public BehaviorReturnCode component_2(){ + counts [1]++; + return BehaviorReturnCode.Success; + } + + public BehaviorReturnCode component_3(){ + counts [2]++; + return BehaviorReturnCode.Success; + } + + public BehaviorReturnCode component_4(){ + counts [3]++; + return BehaviorReturnCode.Success; + } + + + [Test] + public void test_1(){ + _log.enterScope (); + + RandomSelector rs = new RandomSelector (new BehaviorAction(component_1), + new BehaviorAction(component_2), + new BehaviorAction(component_3), + new BehaviorAction(component_4)); + + + for (int i = 0; i < 100000; i++) + rs.Behave (); + + _log.logMessage ("1:" + counts[0] +", 2:" + counts[1]+ ", 3:" + counts[2]+ ", 4:" + counts [3]); + + Verify.VerifyTrue ("verify last component actioned", true, counts [3] > 0); + + _log.exitScope (); + } + } +} + diff --git a/Tests/Program.cs b/Tests/Program.cs new file mode 100644 index 0000000..cb82c06 --- /dev/null +++ b/Tests/Program.cs @@ -0,0 +1,45 @@ +// +// Program.cs +// +// Author: +// Thomas H. Jonell <@Net_Gnome> +// +// Copyright (c) 2013 Thomas H. Jonell +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +using System; +using CSTester; +using CSLogging; + +namespace Tests +{ + class MainClass + { + public static void Main (string[] args) + { + try + { + Tester tester = new Tester(); + tester.registerTestCases(); + tester.executeTestCases(); + Console.Write(tester.getResults()); + } + catch (Exception e) + { + Console.Write(e.ToString()); + } + } + + } +} diff --git a/Tests/Properties/AssemblyInfo.cs b/Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d1009d6 --- /dev/null +++ b/Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. +[assembly: AssemblyTitle ("Tests")] +[assembly: AssemblyDescription ("")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany ("")] +[assembly: AssemblyProduct ("")] +[assembly: AssemblyCopyright ("tom")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. +[assembly: AssemblyVersion ("1.0.*")] +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/Tests/TestCases.cs b/Tests/TestCases.cs new file mode 100644 index 0000000..0eb4a51 --- /dev/null +++ b/Tests/TestCases.cs @@ -0,0 +1,138 @@ +// +// TestCases.cs +// +// Author: +// Thomas H. Jonell <@Net_Gnome> +// +// Copyright (c) 2013 Thomas H. Jonell +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +using System; +using CSTester; +using CSLogging; +using BehaviorLibrary; +using BehaviorLibrary.Components; +using BehaviorLibrary.Components.Actions; + +namespace Tests +{ + [TestCase] + public class TestCases + { + public TestCases (){} + + private CSLogger _log = CSLogger.Instance; + + [BuildUp] + public void buildup(){ + _log.setEnableLogging (true); + _log.setEnableDebug (true); + _log.setEnableError (true); + _log.setEnableMessage (true); + _log.loadLog("","behaviorLibrary.log"); + _log.enterScope ("TestCases"); + _log.logMessage ("----------------- STARTING BEHAVIOR LIBRARY TESTS -----------------"); + } + + [TearDown] + public void teardown(){ + _log.enterScope("teardown"); + _log.exitScope (); + _log.logMessage ("----------------- ENDING BEHAVIOR LIBRARY TESTS -----------------"); + _log.exitScope (); + _log.closeLog (); + } + + [Test] + public void testStatefulSeq(){ + _log.enterScope("testStatefulSeq"); + + bool first = true; + + var foo = new StatefulSequence (new BehaviorAction(delegate(){ + if(first){ + return BehaviorReturnCode.Success; + }else{ + return BehaviorReturnCode.Failure; + } + }),new BehaviorAction( delegate(){ + if(first){ + first = false; + return BehaviorReturnCode.Running; + }else{ + return BehaviorReturnCode.Success; + } + }),new BehaviorAction(delegate(){ + return BehaviorReturnCode.Success; + })); + + Verify.VerifyEquals ("1st running", true, foo.Behave (), BehaviorReturnCode.Running); + Verify.VerifyEquals ("2nd success", true, foo.Behave (), BehaviorReturnCode.Success); + Verify.VerifyEquals ("3rd failure", true, foo.Behave (), BehaviorReturnCode.Failure); + + _log.logMessage ("restting first"); + first = true; + + Verify.VerifyEquals ("after reset running", true, foo.Behave (), BehaviorReturnCode.Running); + Verify.VerifyEquals ("final success", true, foo.Behave (), BehaviorReturnCode.Success); + Verify.VerifyEquals ("final failure", true, foo.Behave (), BehaviorReturnCode.Failure); + + _log.exitScope (); + } + + [Test] + public void testStatefulSel(){ + _log.enterScope("testStatefulSel"); + + bool first = true; + bool second = true; + var foo = new StatefulSelector (new BehaviorAction (delegate(){ + return BehaviorReturnCode.Failure; + }), new BehaviorAction (delegate() { + if(first){ + first = false; + return BehaviorReturnCode.Running; + }else{ + return BehaviorReturnCode.Failure; + } + }), new BehaviorAction (delegate(){ + if(first){ + return BehaviorReturnCode.Success; + }else{ + if(second){ + second = false; + return BehaviorReturnCode.Success; + }else{ + return BehaviorReturnCode.Failure; + } + } + })); + + Verify.VerifyEquals ("1st running", true, foo.Behave (), BehaviorReturnCode.Running); + Verify.VerifyEquals ("2nd success", true, foo.Behave (), BehaviorReturnCode.Success); + Verify.VerifyEquals ("3rd failure", true, foo.Behave (), BehaviorReturnCode.Failure); + + _log.logMessage ("restting flags"); + first = true; + second = true; + + Verify.VerifyEquals ("after reset running", true, foo.Behave (), BehaviorReturnCode.Running); + Verify.VerifyEquals ("final success", true, foo.Behave (), BehaviorReturnCode.Success); + Verify.VerifyEquals ("final failure", true, foo.Behave (), BehaviorReturnCode.Failure); + + _log.exitScope (); + } + } +} + diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj new file mode 100644 index 0000000..b8da6f3 --- /dev/null +++ b/Tests/Tests.csproj @@ -0,0 +1,55 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {A7D9F051-A51E-42FF-AD2B-D94DC8A06650} + Exe + Tests + Tests + + + true + full + false + bin\Debug + DEBUG;TRACE + prompt + 4 + true + + + full + true + bin\Release + prompt + 4 + true + + + + + ..\..\CSTester\CSLogging\bin\Release\CSLogging.dll + + + ..\..\CSTester\CSTester\bin\Release\CSTester.dll + + + + + + + + + + + + + + {CC824B6F-6145-485F-9604-FB94F0ECACA7} + BehaviorLibrary + + + \ No newline at end of file diff --git a/Tests/UtilityTests.cs b/Tests/UtilityTests.cs new file mode 100644 index 0000000..f71587c --- /dev/null +++ b/Tests/UtilityTests.cs @@ -0,0 +1,257 @@ +// +// UtilityTests.cs +// +// Author: +// Thomas H. Jonell <@Net_Gnome> +// +// Copyright (c) 2014 Thomas H. Jonell +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + + + +using CSTester; +using CSLogging; + +using BehaviorLibrary; +using BehaviorLibrary.Components; +using BehaviorLibrary.Components.Utility; +using BehaviorLibrary.Components.Actions; + +namespace Tests +{ + [TestCase] + class UtilityTests + { + + private CSLogger _log = CSLogger.Instance; + + [BuildUp] + public void buildup() + { + _log.setEnableLogging(true); + _log.setEnableDebug(true); + _log.setEnableError(true); + _log.setEnableMessage(true); + _log.loadLog("", "utility_tests.log"); + _log.enterScope(); + _log.logMessage("----------------- STARTING BEHAVIOR LIBRARY UTILITY TESTS -----------------"); + } + + [TearDown] + public void teardown() + { + _log.enterScope(); + _log.exitScope(); + _log.logMessage("----------------- ENDING BEHAVIOR LIBRARY UTILITY TESTS -----------------"); + _log.exitScope(); + _log.closeLog(); + } + + [Test] + public void test_vector(){ + _log.enterScope (); + + UtilityVector vec1 = new UtilityVector (0, 1, 2, 3, 4, 5); + + float mag = vec1.magnitude; + _log.logDebug ("mag: " + mag); + Verify.VerifyTrue ("verify mag gte 0", true, mag >= 0); + + Verify.VerifyTrue ("norm is not null", true, vec1.normalize () != null); + + UtilityVector vec2 = new UtilityVector (5, 4, 3, 2, 1, 0); + + float dot = vec1.dot (vec2); + _log.logDebug ("dot: " + dot); + Verify.VerifyTrue ("dot between 1 and -1", true, (dot <= 1) && (dot >= -1)); + + dot = vec1.dot (vec1); + _log.logDebug ("self dot: " + dot); + Verify.VerifyTrue ("dot with itself should be 1", true, dot == 1); + + + _log.exitScope (); + } + + [Test] + public void selector_1() + { + _log.enterScope(); + + UtilityVector vector = new UtilityVector(0, 1, 0, 2); + BehaviorAction action = new BehaviorAction(delegate() { return BehaviorReturnCode.Success; }); + UtilityPair pair = new UtilityPair(vector, action); + UtilitySelector sel = new UtilitySelector(delegate(){return new UtilityVector(0,1,1,2);},pair,pair); + + BehaviorReturnCode result = sel.Behave(); + + Verify.VerifyNotEquals("basic vector compare", true, result, BehaviorReturnCode.Failure); + + _log.exitScope(); + } + + [Test] + public void selector_2(){ + _log.enterScope(); + + //build vectors + UtilityVector a = new UtilityVector(0, 1, 0, 1); + UtilityVector b = new UtilityVector(1, 1, 0, 0); + UtilityVector c = new UtilityVector(1, 0, 1, 0); + UtilityVector d = new UtilityVector(0, 0, 1, 1); + + string choice = ""; + + //build actions that change choice if called + BehaviorAction aa = new BehaviorAction (delegate() { + choice = "a"; + return BehaviorReturnCode.Success; + }); + BehaviorAction ba = new BehaviorAction (delegate() { + choice = "b"; + return BehaviorReturnCode.Success; + }); + BehaviorAction ca = new BehaviorAction (delegate() { + choice = "c"; + return BehaviorReturnCode.Success; + }); + BehaviorAction da = new BehaviorAction (delegate() { + choice = "d"; + return BehaviorReturnCode.Success; + }); + + //build the appropraite pairs + UtilityPair ap = new UtilityPair (a, aa); + UtilityPair bp = new UtilityPair (b, ba); + UtilityPair cp = new UtilityPair (c, ca); + UtilityPair dp = new UtilityPair (d, da); + + + //execute tests + UtilitySelector sel = new UtilitySelector (delegate() { + return new UtilityVector (0,1,0,1); + }, ap, bp, cp, dp); + + sel.Behave (); + + Verify.VerifyTrue ("a chosen", true, choice == "a"); + + sel = new UtilitySelector (delegate() { + return new UtilityVector (1,1,0,0); + }, ap, bp, cp, dp); + + sel.Behave (); + + Verify.VerifyTrue ("b chosen", true, choice == "b"); + + sel = new UtilitySelector (delegate() { + return new UtilityVector (1,0,1,0); + }, ap, bp, cp, dp); + + sel.Behave (); + + Verify.VerifyTrue ("c chosen", true, choice == "c"); + + sel = new UtilitySelector (delegate() { + return new UtilityVector (0,0,1,1); + }, ap, bp, cp, dp); + + sel.Behave (); + + Verify.VerifyTrue ("d chosen", true, choice == "d"); + + + _log.exitScope (); + } + + [Test] + public void selector_3(){ + _log.enterScope(); + + //build vectors + UtilityVector a = new UtilityVector(0, 1, 0, 1); + UtilityVector b = new UtilityVector(1, 1, 0, 0); + UtilityVector c = new UtilityVector(1, 0, 1, 0); + UtilityVector d = new UtilityVector(0, 0, 1, 1); + + string choice = ""; + + //build actions that change choice if called + BehaviorAction aa = new BehaviorAction (delegate() { + choice = "a"; + return BehaviorReturnCode.Success; + }); + BehaviorAction ba = new BehaviorAction (delegate() { + choice = "b"; + return BehaviorReturnCode.Success; + }); + BehaviorAction ca = new BehaviorAction (delegate() { + choice = "c"; + return BehaviorReturnCode.Success; + }); + BehaviorAction da = new BehaviorAction (delegate() { + choice = "d"; + return BehaviorReturnCode.Success; + }); + + //build the appropraite pairs + UtilityPair ap = new UtilityPair (a, aa); + UtilityPair bp = new UtilityPair (b, ba); + UtilityPair cp = new UtilityPair (c, ca); + UtilityPair dp = new UtilityPair (d, da); + + + //execute tests + UtilitySelector sel = new UtilitySelector (delegate() { + return new UtilityVector (0.5f,0.7f,0.4f,0.8f); + }, ap, bp, cp, dp); + + sel.Behave (); + + Verify.VerifyTrue ("a chosen", true, choice == "a"); + + sel = new UtilitySelector (delegate() { + return new UtilityVector (0.7f,0.8f,0.5f,0.4f); + }, ap, bp, cp, dp); + + sel.Behave (); + + Verify.VerifyTrue ("b chosen", true, choice == "b"); + + sel = new UtilitySelector (delegate() { + return new UtilityVector (0.7f,0.5f,0.8f,0.4f); + }, ap, bp, cp, dp); + + sel.Behave (); + + Verify.VerifyTrue ("c chosen", true, choice == "c"); + + sel = new UtilitySelector (delegate() { + return new UtilityVector (0.5f,0.4f,0.7f,0.8f); + }, ap, bp, cp, dp); + + sel.Behave (); + + Verify.VerifyTrue ("d chosen", true, choice == "d"); + + + _log.exitScope (); + } + } +}