StateMachine tweaks.
This commit is contained in:
parent
94a6cb2cff
commit
0db8613a21
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user