Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First release of the BehaviorTreeStarterKit from February 2012, files…
… from AiGD-BehaviorTreeStarterKit-1.0-src.zip.
- Loading branch information
Showing
11 changed files
with
1,791 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,3 +10,9 @@ | |
*.lai | ||
*.la | ||
*.a | ||
/Debug | ||
/Release | ||
*.opensdf | ||
*.sdf | ||
*.suo | ||
*.user |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 11.00 | ||
# Visual Studio 2010 | ||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BehaviorTreeStarterKit", "BehaviorTreeStarterKit.vcxproj", "{157B27E5-12E2-43F4-A99C-703B54052DE3}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Win32 = Debug|Win32 | ||
Release|Win32 = Release|Win32 | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{157B27E5-12E2-43F4-A99C-703B54052DE3}.Debug|Win32.ActiveCfg = Debug|Win32 | ||
{157B27E5-12E2-43F4-A99C-703B54052DE3}.Debug|Win32.Build.0 = Debug|Win32 | ||
{157B27E5-12E2-43F4-A99C-703B54052DE3}.Release|Win32.ActiveCfg = Release|Win32 | ||
{157B27E5-12E2-43F4-A99C-703B54052DE3}.Release|Win32.Build.0 = Release|Win32 | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
EndGlobal |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,327 @@ | ||
/****************************************************************************** | ||
* This file is part of the Behavior Tree Starter Kit. | ||
* | ||
* Copyright (c) 2012, AiGameDev.com. | ||
* | ||
* Credits: Alex J. Champandard | ||
*****************************************************************************/ | ||
|
||
#include <vector> | ||
#include "Shared.h" | ||
#include "Test.h" | ||
|
||
namespace bt1 | ||
{ | ||
|
||
// ============================================================================ | ||
|
||
enum Status | ||
/** | ||
* Return values of and valid states for behaviors. | ||
*/ | ||
{ | ||
BH_INVALID, | ||
BH_SUCCESS, | ||
BH_FAILURE, | ||
BH_RUNNING, | ||
}; | ||
|
||
class Behavior | ||
/** | ||
* Base class for actions, conditions and composites. | ||
*/ | ||
{ | ||
protected: | ||
virtual Status update() = 0; | ||
|
||
virtual void onInitialize() {} | ||
virtual void onTerminate(Status) {} | ||
|
||
public: | ||
Behavior() | ||
: m_eStatus(BH_INVALID) | ||
{ | ||
} | ||
|
||
Status tick() | ||
{ | ||
if (m_eStatus == BH_INVALID) | ||
{ | ||
onInitialize(); | ||
} | ||
|
||
m_eStatus = update(); | ||
|
||
if (m_eStatus != BH_RUNNING) | ||
{ | ||
onTerminate(m_eStatus); | ||
} | ||
return m_eStatus; | ||
} | ||
|
||
private: | ||
Status m_eStatus; | ||
}; | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
struct MockBehavior : public Behavior | ||
{ | ||
int m_iInitializeCalled; | ||
int m_iTerminateCalled; | ||
int m_iUpdateCalled; | ||
Status m_eReturnStatus; | ||
Status m_eTerminateStatus; | ||
|
||
MockBehavior() | ||
: m_iInitializeCalled(0) | ||
, m_iTerminateCalled(0) | ||
, m_iUpdateCalled(0) | ||
, m_eReturnStatus(BH_RUNNING) | ||
, m_eTerminateStatus(BH_INVALID) | ||
{ | ||
} | ||
|
||
virtual void onInitialize() | ||
{ | ||
++m_iInitializeCalled; | ||
} | ||
|
||
virtual void onTerminate(Status s) | ||
{ | ||
++m_iTerminateCalled; | ||
m_eTerminateStatus = s; | ||
} | ||
|
||
virtual Status update() | ||
{ | ||
++m_iUpdateCalled; | ||
return m_eReturnStatus; | ||
} | ||
}; | ||
|
||
TEST(StarterKit1, TaskInitialize) | ||
{ | ||
MockBehavior t; | ||
CHECK_EQUAL(0, t.m_iInitializeCalled); | ||
|
||
t.tick(); | ||
CHECK_EQUAL(1, t.m_iInitializeCalled); | ||
}; | ||
|
||
TEST(StarterKit1, TaskUpdate) | ||
{ | ||
MockBehavior t; | ||
CHECK_EQUAL(0, t.m_iUpdateCalled); | ||
|
||
t.tick(); | ||
CHECK_EQUAL(1, t.m_iUpdateCalled); | ||
}; | ||
|
||
TEST(StarterKit1, TaskTerminate) | ||
{ | ||
MockBehavior t; | ||
t.tick(); | ||
CHECK_EQUAL(0, t.m_iTerminateCalled); | ||
|
||
t.m_eReturnStatus = BH_SUCCESS; | ||
t.tick(); | ||
CHECK_EQUAL(1, t.m_iTerminateCalled); | ||
}; | ||
|
||
|
||
// ============================================================================ | ||
|
||
class Composite : public Behavior | ||
{ | ||
protected: | ||
typedef std::vector<Behavior*> Behaviors; | ||
Behaviors m_Children; | ||
}; | ||
|
||
class Sequence : public Composite | ||
{ | ||
protected: | ||
virtual void onInitialize() | ||
{ | ||
m_CurrentChild = m_Children.begin(); | ||
} | ||
|
||
virtual Status update() | ||
{ | ||
// Keep going until a child behavior says its running. | ||
for (;;) | ||
{ | ||
Status s = (*m_CurrentChild)->tick(); | ||
|
||
// If the child fails, or keeps running, do the same. | ||
if (s != BH_SUCCESS) | ||
{ | ||
return s; | ||
} | ||
|
||
// Hit the end of the array, job done! | ||
if (++m_CurrentChild == m_Children.end()) | ||
{ | ||
return BH_SUCCESS; | ||
} | ||
} | ||
} | ||
|
||
Behaviors::iterator m_CurrentChild; | ||
}; | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
template <class COMPOSITE> | ||
class MockComposite : public COMPOSITE | ||
{ | ||
public: | ||
MockComposite(size_t size) | ||
{ | ||
for (size_t i=0; i<size; ++i) | ||
{ | ||
COMPOSITE::m_Children.push_back(new MockBehavior); | ||
} | ||
} | ||
|
||
~MockComposite() | ||
{ | ||
for (size_t i=0; i<COMPOSITE::m_Children.size(); ++i) | ||
{ | ||
delete COMPOSITE::m_Children[i]; | ||
} | ||
} | ||
|
||
MockBehavior& operator[](size_t index) | ||
{ | ||
ASSERT(index < COMPOSITE::m_Children.size()); | ||
return *static_cast<MockBehavior*>(COMPOSITE::m_Children[index]); | ||
} | ||
}; | ||
|
||
typedef MockComposite<Sequence> MockSequence; | ||
|
||
TEST(StarterKit1, SequenceTwoChildrenFails) | ||
{ | ||
MockSequence seq(2); | ||
|
||
CHECK_EQUAL(seq.tick(), BH_RUNNING); | ||
CHECK_EQUAL(0, seq[0].m_iTerminateCalled); | ||
|
||
seq[0].m_eReturnStatus = BH_FAILURE; | ||
CHECK_EQUAL(seq.tick(), BH_FAILURE); | ||
CHECK_EQUAL(1, seq[0].m_iTerminateCalled); | ||
CHECK_EQUAL(0, seq[1].m_iInitializeCalled); | ||
} | ||
|
||
TEST(StarterKit1, SequenceTwoChildrenContinues) | ||
{ | ||
MockSequence seq(2); | ||
|
||
CHECK_EQUAL(seq.tick(), BH_RUNNING); | ||
CHECK_EQUAL(0, seq[0].m_iTerminateCalled); | ||
CHECK_EQUAL(0, seq[1].m_iInitializeCalled); | ||
|
||
seq[0].m_eReturnStatus = BH_SUCCESS; | ||
CHECK_EQUAL(seq.tick(), BH_RUNNING); | ||
CHECK_EQUAL(1, seq[0].m_iTerminateCalled); | ||
CHECK_EQUAL(1, seq[1].m_iInitializeCalled); | ||
} | ||
|
||
TEST(StarterKit1, SequenceOneChildPassThrough) | ||
{ | ||
Status status[2] = { BH_SUCCESS, BH_FAILURE }; | ||
for (int i=0; i<2; ++i) | ||
{ | ||
MockSequence seq(1); | ||
|
||
CHECK_EQUAL(seq.tick(), BH_RUNNING); | ||
CHECK_EQUAL(0, seq[0].m_iTerminateCalled); | ||
|
||
seq[0].m_eReturnStatus = status[i]; | ||
CHECK_EQUAL(seq.tick(), status[i]); | ||
CHECK_EQUAL(1, seq[0].m_iTerminateCalled); | ||
} | ||
} | ||
|
||
|
||
// ============================================================================ | ||
|
||
class Selector : public Composite | ||
{ | ||
protected: | ||
virtual void onInitialize() | ||
{ | ||
m_Current = m_Children.begin(); | ||
} | ||
|
||
virtual Status update() | ||
{ | ||
// Keep going until a child behavior says its running. | ||
for (;;) | ||
{ | ||
Status s = (*m_Current)->tick(); | ||
|
||
// If the child succeeds, or keeps running, do the same. | ||
if (s != BH_FAILURE) | ||
{ | ||
return s; | ||
} | ||
|
||
// Hit the end of the array, it didn't end well... | ||
if (++m_Current == m_Children.end()) | ||
{ | ||
return BH_FAILURE; | ||
} | ||
} | ||
} | ||
|
||
Behaviors::iterator m_Current; | ||
}; | ||
|
||
// ---------------------------------------------------------------------------- | ||
|
||
typedef MockComposite<Selector> MockSelector; | ||
|
||
TEST(StarterKit1, SelectorTwoChildrenContinues) | ||
{ | ||
MockSelector seq(2); | ||
|
||
CHECK_EQUAL(seq.tick(), BH_RUNNING); | ||
CHECK_EQUAL(0, seq[0].m_iTerminateCalled); | ||
|
||
seq[0].m_eReturnStatus = BH_FAILURE; | ||
CHECK_EQUAL(seq.tick(), BH_RUNNING); | ||
CHECK_EQUAL(1, seq[0].m_iTerminateCalled); | ||
} | ||
|
||
TEST(StarterKit1, SelectorTwoChildrenSucceeds) | ||
{ | ||
MockSelector seq(2); | ||
|
||
CHECK_EQUAL(seq.tick(), BH_RUNNING); | ||
CHECK_EQUAL(0, seq[0].m_iTerminateCalled); | ||
|
||
seq[0].m_eReturnStatus = BH_SUCCESS; | ||
CHECK_EQUAL(seq.tick(), BH_SUCCESS); | ||
CHECK_EQUAL(1, seq[0].m_iTerminateCalled); | ||
} | ||
|
||
TEST(StarterKit1, SelectorOneChildPassThrough) | ||
{ | ||
Status status[2] = { BH_SUCCESS, BH_FAILURE }; | ||
for (int i=0; i<2; ++i) | ||
{ | ||
MockSelector seq(1); | ||
|
||
CHECK_EQUAL(seq.tick(), BH_RUNNING); | ||
CHECK_EQUAL(0, seq[0].m_iTerminateCalled); | ||
|
||
seq[0].m_eReturnStatus = status[i]; | ||
CHECK_EQUAL(seq.tick(), status[i]); | ||
CHECK_EQUAL(1, seq[0].m_iTerminateCalled); | ||
} | ||
} | ||
|
||
} // namespace bt1 |
Oops, something went wrong.