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

View File

@ -74,6 +74,14 @@ public:
std::string name() const; 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 * The state we end in, after this transition fires
*/ */
@ -116,6 +124,8 @@ public:
typedef SGSharedPtr<State> State_ptr; typedef SGSharedPtr<State> State_ptr;
typedef SGSharedPtr<Transition> Transition_ptr; typedef SGSharedPtr<Transition> Transition_ptr;
void initFromPlist(SGPropertyNode* desc, SGPropertyNode* root);
/** /**
* create a state machine from a property list description * 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() void testBindings()
{ {
SGCommandMgr* cmdMgr = SGCommandMgr::instance(); SGCommandMgr* cmdMgr = SGCommandMgr::instance();
@ -220,6 +241,8 @@ int main(int argc, char* argv[])
testBasic(); testBasic();
testBindings(); testBindings();
testParse(); testParse();
testNoSourcesTransition();
cout << __FILE__ << ": All tests passed" << endl; cout << __FILE__ << ": All tests passed" << endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }