0

Let's say I have a pack of robots that run a QStateMachine. All state machines of those robots have the same basic structure:

  • States:
    • Sleep
    • Search
    • Destroy
    • Return
  • Transitions (from -> to on signal:
    • Sleep -> Search on "next"
    • Search -> Destroy on "next"
    • Destroy -> Search on "next"
    • Destroy -> Return on "back"
    • Search -> Return on "back"
    • Return -> Search on "next"
    • Return -> Sleep on "back"

// base.h

#include <QObject>
#include <QState>
#include <QStateMachine>

class Base : public QObject
{
    Q_OBJECT
public:
    Base(QObject* parent = 0);
    ~Base();

signals:
    void next();
    void back();

private:
    QStateMachine m_machine;
    QState* m_sleep;
    QState* m_search;
    QState* m_destroy;
    QState* m_return;
};

// base.cpp

Base::Base(QObject* parent) : QObject(parent)
{
    m_sleep = new QState(&m_machine);
    m_search = new QState(&m_machine);
    m_destroy = new QState(&m_machine);
    m_return = new QState(&m_machine);

    m_machine.setInitialState(m_sleep);

    m_sleep->addTransition(this, &Base::next, m_search);
    m_search->addTransition(this, &Base::next, m_destroy);
    m_search->addTransition(this, &Base::back, m_return);
    m_destroy->addTransition(this, &Base::next, m_search);
    m_destroy->addTransition(this, &Base::back, m_return);
    m_return->addTransition(this, &Base::next, m_search);
    m_return->addTransition(this, &Base::back, m_sleep);

    m_machine.start();
}

Now I want to have a robot that is maybe a bit more concrete. Let's say he is more detailed in the process of destruction, featuring a couple of substates, e.g. dismantel -> sprayWithAcid -> blowUp -> desintegrate, where he moves on with each next-signal, or he goes on to return upon the back-signal.

As mentioned, my plan was to just add them as substates to the state destroy, but as the signal next will not only continue the substatemachine until finished, but also leave the parent state.

How can I avoid this? or is there another nice way to do similar?

1 Answers1

0

I got it now.

The trick is to create the transitions explicitly, having them as members of the class. You can set them up like this:

m_sleepSearch = new QSignalTransition(this, &Base::next, m_sleep);
m_searchDestroy = new QSignalTransition(this, &Base::next, m_search);
m_searchReturn = new QSignalTransition(this, &Base::back, m_search);
m_destroySearch = new QSignalTransition(this, &Base::next, m_destroy);
m_destroyReturn = new QSignalTransition(this, &Base::back, m_destroy);
m_returnSearch = new QSignalTransition(this, &Base::next, m_return);
m_returnSleep = new QSignalTransition(this, &Base::back, m_return);

m_sleepSearch->setTargetState(m_search);
m_searchDestroy->setTargetState(m_destroy);
m_searchReturn->setTargetState(m_return);
m_destroySearch->setTargetState(m_search);
m_destroyReturn->setTargetState(m_return);
m_returnSearch->setTargetState(m_search);
m_returnSleep->setTargetState(m_sleep);

What I first got wrong was having the wrong parameters for the QSignalTransition(sender, signal, source_state) constructor as it is too similar to the syntax of ->addTransition(sender, signal, target_state) so I mixed up source and target.

After having them created like this, it should be easy to re-route or disable some of those transitions, when subclassing this object.