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