StateMachine tweaks.

This commit is contained in:
James Turner 2013-01-25 09:29:31 +01:00
parent 94a6cb2cff
commit 0db8613a21
3 changed files with 65 additions and 7 deletions

View File

@ -71,6 +71,7 @@ public:
SGBindingList _bindings;
std::set<State*> _sourceStates; ///< weak refs to source states
State* _target;
bool _excludeTarget;
SGSharedPtr<SGCondition> _condition;
};
@ -175,6 +176,7 @@ StateMachine::Transition::Transition(const std::string& aName, State* aTarget) :
assert(aTarget);
d->_name = aName;
d->_target = aTarget;
d->_excludeTarget = true;
}
StateMachine::Transition::~Transition()
@ -197,6 +199,13 @@ void StateMachine::Transition::addSourceState(State* aSource)
bool StateMachine::Transition::applicableForState(State* aCurrent) const
{
if (d->_excludeTarget && (aCurrent == d->_target)) {
return false;
}
if (d->_sourceStates.empty()) {
return true;
}
return d->_sourceStates.count(aCurrent);
}
@ -225,6 +234,11 @@ void StateMachine::Transition::addBinding(SGBinding* aBinding)
d->_bindings.push_back(aBinding);
}
void StateMachine::Transition::setExcludeTarget(bool aExclude)
{
d->_excludeTarget = aExclude;
}
///////////////////////////////////////////////////////////////////////////
StateMachine::StateMachine() :
@ -402,10 +416,13 @@ StateMachine::createTransition(const std::string& aName, State_ptr aTarget)
return t;
}
StateMachine* StateMachine::createFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
void StateMachine::initFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
{
StateMachine* sm = new StateMachine;
std::string path = desc->getStringValue("branch");
if (!path.empty()) {
d->_root = root->getNode(path, 0, true);
assert(d->_root);
}
BOOST_FOREACH(SGPropertyNode* stateDesc, desc->getChildren("state")) {
std::string nm = stateDesc->getStringValue("name");
@ -415,28 +432,36 @@ StateMachine* StateMachine::createFromPlist(SGPropertyNode* desc, SGPropertyNode
readBindingList(stateDesc, "exit", root, st->d->_entryBindings);
readBindingList(stateDesc, "update", root, st->d->_exitBindings);
sm->addState(st);
addState(st);
} // of states iteration
BOOST_FOREACH(SGPropertyNode* tDesc, desc->getChildren("transition")) {
std::string nm = tDesc->getStringValue("name");
State_ptr target = sm->findStateByName(tDesc->getStringValue("target"));
State_ptr target = findStateByName(tDesc->getStringValue("target"));
SGCondition* cond = sgReadCondition(root, tDesc->getChild("condition"));
Transition_ptr t(new Transition(nm, target));
t->setTriggerCondition(cond);
t->setExcludeTarget(tDesc->getBoolValue("exclude-target", true));
BOOST_FOREACH(SGPropertyNode* src, desc->getChildren("source")) {
State_ptr srcState = sm->findStateByName(src->getStringValue());
State_ptr srcState = findStateByName(src->getStringValue());
t->addSourceState(srcState);
}
readBindingList(tDesc, "binding", root, t->d->_bindings);
sm->addTransition(t);
addTransition(t);
} // of states iteration
init();
}
StateMachine* StateMachine::createFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
{
StateMachine* sm = new StateMachine;
sm->initFromPlist(desc, root);
return sm;
}

View File

@ -74,6 +74,14 @@ public:
std::string name() const;
/**
* Set if the target state should automatically be excluded
* from the source state. Defaults to true, can be cleared
* to allow a state to re-enter itself
*/
void setExcludeTarget(bool aExclude);
/**
* The state we end in, after this transition fires
*/
@ -116,6 +124,8 @@ public:
typedef SGSharedPtr<State> State_ptr;
typedef SGSharedPtr<Transition> Transition_ptr;
void initFromPlist(SGPropertyNode* desc, SGPropertyNode* root);
/**
* create a state machine from a property list description
*/

View File

@ -147,6 +147,27 @@ void testBasic()
}
}
void testNoSourcesTransition()
{
BUILD_MACHINE_1();
DummyCondition* trigger4 = new DummyCondition;
StateMachine::Transition_ptr t4 = sm->createTransition("alwaysToA", stateA); \
t4->setTriggerCondition(trigger4); \
sm->init();
COMPARE(sm->state()->name(), "a");
trigger1->_state = true;
sm->update(1.0);
trigger1->_state = false;
COMPARE(sm->state()->name(), "b");
trigger4->_state = true;
sm->update(1.0);
trigger4->_state = false;
COMPARE(sm->state()->name(), "a");
}
void testBindings()
{
SGCommandMgr* cmdMgr = SGCommandMgr::instance();
@ -220,6 +241,8 @@ int main(int argc, char* argv[])
testBasic();
testBindings();
testParse();
testNoSourcesTransition();
cout << __FILE__ << ": All tests passed" << endl;
return EXIT_SUCCESS;
}