diff options
Diffstat (limited to 'examples')
14 files changed, 262 insertions, 26 deletions
diff --git a/examples/statemachine/errorstate/gameitem.h b/examples/statemachine/errorstate/gameitem.h index 6ca32b7..9808706 100644 --- a/examples/statemachine/errorstate/gameitem.h +++ b/examples/statemachine/errorstate/gameitem.h @@ -7,13 +7,8 @@ class QLineF; class GameItem: public QGraphicsItem { public: - enum { Type = UserType + 1 }; - - int type() const { return Type; } virtual void idle(qreal elapsed) = 0; - virtual void hitByRocket() = 0; - protected: QPointF tryMove(const QPointF &requestedPosition, QLineF *collidedLine = 0, QGraphicsItem **collidedItem = 0) const; diff --git a/examples/statemachine/errorstate/mainwindow.cpp b/examples/statemachine/errorstate/mainwindow.cpp index e04ca94..daf7be0 100644 --- a/examples/statemachine/errorstate/mainwindow.cpp +++ b/examples/statemachine/errorstate/mainwindow.cpp @@ -105,6 +105,7 @@ void MainWindow::init() QAction *addTankAction = menuBar()->addAction("&Add tank"); QAction *runGameAction = menuBar()->addAction("&Run game"); + runGameAction->setObjectName("runGameAction"); QAction *stopGameAction = menuBar()->addAction("&Stop game"); menuBar()->addSeparator(); QAction *quitAction = menuBar()->addAction("&Quit"); @@ -112,9 +113,7 @@ void MainWindow::init() connect(addTankAction, SIGNAL(triggered()), this, SLOT(addTank())); connect(quitAction, SIGNAL(triggered()), this, SLOT(close())); - m_machine = new QStateMachine(this); - m_machine->setGlobalRestorePolicy(QStateMachine::RestoreProperties); - + m_machine = new QStateMachine(this); QState *stoppedState = new QState(m_machine->rootState()); stoppedState->setObjectName("stoppedState"); stoppedState->assignProperty(runGameAction, "enabled", true); @@ -168,7 +167,11 @@ void MainWindow::runStep() qreal elapsedSecs = elapsed / 1000.0; QList<QGraphicsItem *> items = m_scene->items(); foreach (QGraphicsItem *item, items) { - GameItem *gameItem = qgraphicsitem_cast<GameItem *>(item); + // ### + GameItem *gameItem = qgraphicsitem_cast<TankItem *>(item); + if (gameItem == 0) + gameItem = qgraphicsitem_cast<RocketItem *>(item); + if (gameItem != 0) gameItem->idle(elapsedSecs); } @@ -206,7 +209,13 @@ void MainWindow::addTank() emit mapFull(); QState *region = new QState(m_runningState); - region->setInitialState(plugin->create(region, tankItem)); + QState *pluginState = plugin->create(region, tankItem); + region->setInitialState(pluginState); + + // If the plugin has an error it is disabled + QState *errorState = new QState(region); + errorState->assignProperty(tankItem, "enabled", false); + pluginState->setErrorState(errorState); } } diff --git a/examples/statemachine/errorstate/plugin.h b/examples/statemachine/errorstate/plugin.h index 1ac7e0f..69b9574 100644 --- a/examples/statemachine/errorstate/plugin.h +++ b/examples/statemachine/errorstate/plugin.h @@ -1,6 +1,8 @@ #ifndef PLUGIN_H #define PLUGIN_H +#include <QtPlugin> + class QState; class Tank; class Plugin diff --git a/examples/statemachine/errorstate/rocketitem.cpp b/examples/statemachine/errorstate/rocketitem.cpp index de9eef7..85d436b 100644 --- a/examples/statemachine/errorstate/rocketitem.cpp +++ b/examples/statemachine/errorstate/rocketitem.cpp @@ -1,4 +1,5 @@ #include "rocketitem.h" +#include "tankitem.h" #include <QPainter> #include <QGraphicsScene> @@ -25,10 +26,6 @@ void RocketItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWid painter->drawEllipse(boundingRect()); } -void RocketItem::hitByRocket() -{ -} - void RocketItem::idle(qreal elapsed) { qreal dist = elapsed * speed(); @@ -51,8 +48,8 @@ void RocketItem::idle(qreal elapsed) if (requestedPosition == nextPosition) { setPos(nextPosition); } else { - if (GameItem *gameItem = qgraphicsitem_cast<GameItem *>(collidedItem)) - gameItem->hitByRocket(); + if (TankItem *tankItem = qgraphicsitem_cast<TankItem *>(collidedItem)) + tankItem->hitByRocket(); scene()->removeItem(this); delete this; diff --git a/examples/statemachine/errorstate/rocketitem.h b/examples/statemachine/errorstate/rocketitem.h index 9805a8a..b055b0a 100644 --- a/examples/statemachine/errorstate/rocketitem.h +++ b/examples/statemachine/errorstate/rocketitem.h @@ -6,13 +6,14 @@ class RocketItem: public GameItem { public: + enum { Type = UserType + 2 }; + RocketItem(); + int type() const { return Type; } virtual void idle(qreal elapsed); qreal speed() const { return 100.0; } void setDirection(qreal direction) { m_direction = direction; } - - void hitByRocket(); protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); diff --git a/examples/statemachine/errorstate/tankitem.cpp b/examples/statemachine/errorstate/tankitem.cpp index 814de2b..705623c 100644 --- a/examples/statemachine/errorstate/tankitem.cpp +++ b/examples/statemachine/errorstate/tankitem.cpp @@ -85,17 +85,25 @@ private: bool m_reverse; }; -TankItem::TankItem(QObject *parent) : Tank(parent), m_currentAction(0), m_currentDirection(0.0) +TankItem::TankItem(QObject *parent) + : Tank(parent), m_currentAction(0), m_currentDirection(0.0), m_enabled(true) { connect(this, SIGNAL(fireCannon()), this, SIGNAL(actionCompleted())); } void TankItem::idle(qreal elapsed) { - if (m_currentAction != 0) { - if (!m_currentAction->apply(elapsed)) { - setAction(0); - emit actionCompleted(); + if (m_enabled) { + if (m_currentAction != 0) { + if (!m_currentAction->apply(elapsed)) { + setAction(0); + emit actionCompleted(); + } + + QGraphicsItem *item = 0; + qreal distance = distanceToObstacle(&item); + if (TankItem *tankItem = qgraphicsitem_cast<TankItem *>(item)) + emit tankSpotted(tankItem->direction(), distance); } } } @@ -176,6 +184,17 @@ void TankItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidge QPointF(brect.right() - 2.0, brect.bottom())); painter->fillRect(rightTrackRect, Qt::darkYellow); painter->drawRect(rightTrackRect); + + if (!m_enabled) { + painter->setPen(QPen(Qt::red, 5)); + + painter->drawEllipse(brect); + + QPainterPath path; + path.addEllipse(brect); + painter->setClipPath(path); + painter->drawLine(brect.topRight(), brect.bottomLeft()); + } } QRectF TankItem::boundingRect() const @@ -195,11 +214,32 @@ void TankItem::setDirection(qreal newDirection) rotate(diff); } -qreal TankItem::distanceToObstacle() const +qreal TankItem::distanceToObstacle(QGraphicsItem **obstacle) const { - // ### + qreal dist = sqrt(pow(scene()->sceneRect().width(), 2) + pow(scene()->sceneRect().height(), 2)); + + qreal a = m_currentDirection * M_PI / 180.0; + + qreal yd = dist * sin(a); + qreal xd = dist * sin(M_PI / 2.0 - a); - return 0.0; + QPointF requestedPosition = pos() + QPointF(xd, yd); + QGraphicsItem *collidedItem = 0; + QPointF nextPosition = tryMove(requestedPosition, 0, &collidedItem); + if (collidedItem != 0) { + if (obstacle != 0) + *obstacle = collidedItem; + + QPointF d = nextPosition - pos(); + return sqrt(pow(d.x(), 2) + pow(d.y(), 2)); + } else { + return 0.0; + } +} + +qreal TankItem::distanceToObstacle() const +{ + return distanceToObstacle(0); } diff --git a/examples/statemachine/errorstate/tankitem.h b/examples/statemachine/errorstate/tankitem.h index c9e0d22..e598cfd 100644 --- a/examples/statemachine/errorstate/tankitem.h +++ b/examples/statemachine/errorstate/tankitem.h @@ -10,8 +10,13 @@ class Action; class TankItem: public Tank, public GameItem { Q_OBJECT + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) public: + enum { Type = UserType + 1 }; + TankItem(QObject *parent = 0); + + int type() const { return Type; } virtual void moveForwards(qreal length); virtual void moveBackwards(qreal length); @@ -19,6 +24,7 @@ public: virtual void stop(); virtual qreal direction() const; virtual qreal distanceToObstacle() const; + virtual qreal distanceToObstacle(QGraphicsItem **item) const; void setColor(const QColor &color) { m_color = color; } QColor color() const { return m_color; } @@ -33,6 +39,9 @@ public: void hitByRocket(); + void setEnabled(bool b) { m_enabled = b; } + bool enabled() const { return m_enabled; } + signals: virtual void fireCannon(); @@ -46,6 +55,7 @@ private: Action *m_currentAction; qreal m_currentDirection; QColor m_color; + bool m_enabled; }; #endif diff --git a/examples/statemachine/errorstateplugins/errorstateplugins.pro b/examples/statemachine/errorstateplugins/errorstateplugins.pro new file mode 100644 index 0000000..e7718a9 --- /dev/null +++ b/examples/statemachine/errorstateplugins/errorstateplugins.pro @@ -0,0 +1,10 @@ +TEMPLATE = subdirs +SUBDIRS = random_ai \ + spin_ai_with_error \ + spin_ai + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS errorstateplugins.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins +INSTALLS += target sources diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp new file mode 100644 index 0000000..8452523 --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp @@ -0,0 +1,29 @@ +#include "spin_ai.h" + +#include <QtPlugin> + +QState *SpinAi::create(QState *parentState, Tank *tank) +{ + QState *topLevel = new QState(parentState); + QState *spinState = new SpinState(tank, topLevel); + topLevel->setInitialState(spinState); + + // When tank is spotted, fire two times and go back to spin state + QState *fireState = new QState(topLevel); + + QState *fireOnce = new QState(fireState); + fireState->setInitialState(fireOnce); + connect(fireOnce, SIGNAL(entered()), tank, SLOT(fireCannon())); + + QState *fireTwice = new QState(fireState); + connect(fireTwice, SIGNAL(entered()), tank, SLOT(fireCannon())); + + fireOnce->addTransition(tank, SIGNAL(actionCompleted()), fireTwice); + fireTwice->addTransition(tank, SIGNAL(actionCompleted()), spinState); + + spinState->addTransition(tank, SIGNAL(tankSpotted(qreal,qreal)), fireState); + + return topLevel; +} + +Q_EXPORT_PLUGIN2(spin_ai, SpinAi) diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h new file mode 100644 index 0000000..7336640 --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h @@ -0,0 +1,44 @@ +#ifndef SPIN_AI_H +#define SPIN_AI_H + +#include <errorstate/plugin.h> +#include <errorstate/tank.h> + +#include <QObject> +#include <QState> + +class SpinState: public QState +{ + Q_OBJECT +public: + SpinState(Tank *tank, QState *parent) : QState(parent), m_tank(tank) + { + } + +public slots: + void spin() + { + m_tank->turn(90.0); + } + +protected: + void onEntry() + { + connect(m_tank, SIGNAL(actionCompleted()), this, SLOT(spin())); + spin(); + } + +private: + Tank *m_tank; + +}; + +class SpinAi: public QObject, public Plugin +{ + Q_OBJECT + Q_INTERFACES(Plugin) +public: + virtual QState *create(QState *parentState, Tank *tank); +}; + +#endif diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.pro b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.pro new file mode 100644 index 0000000..c2fd937 --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +CONFIG += plugin +INCLUDEPATH += ../.. +HEADERS = spin_ai.h +SOURCES = spin_ai.cpp +TARGET = $$qtLibraryTarget(spin_ai) +DESTDIR = ../../errorstate/plugins + +#! [0] +# install +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/plugins +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS spin_ai.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins/spin_ai
\ No newline at end of file diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp new file mode 100644 index 0000000..dd73270 --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp @@ -0,0 +1,29 @@ +#include "spin_ai_with_error.h" + +#include <QtPlugin> + +QState *SpinAiWithError::create(QState *parentState, Tank *tank) +{ + QState *topLevel = new QState(parentState); + QState *spinState = new SpinState(tank, topLevel); + topLevel->setInitialState(spinState); + + // When tank is spotted, fire two times and go back to spin state + // (no initial state set for fireState will lead to run-time error in machine) + QState *fireState = new QState(topLevel); + + QState *fireOnce = new QState(fireState); + connect(fireOnce, SIGNAL(entered()), tank, SLOT(fireCannon())); + + QState *fireTwice = new QState(fireState); + connect(fireTwice, SIGNAL(entered()), tank, SLOT(fireCannon())); + + fireOnce->addTransition(tank, SIGNAL(actionCompleted()), fireTwice); + fireTwice->addTransition(tank, SIGNAL(actionCompleted()), spinState); + + spinState->addTransition(tank, SIGNAL(tankSpotted(qreal,qreal)), fireState); + + return topLevel; +} + +Q_EXPORT_PLUGIN2(spin_ai_with_error, SpinAiWithError) diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h new file mode 100644 index 0000000..26def66 --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h @@ -0,0 +1,44 @@ +#ifndef SPIN_AI_WITH_ERROR_H +#define SPIN_AI_WITH_ERROR_H + +#include <errorstate/plugin.h> +#include <errorstate/tank.h> + +#include <QObject> +#include <QState> + +class SpinState: public QState +{ + Q_OBJECT +public: + SpinState(Tank *tank, QState *parent) : QState(parent), m_tank(tank) + { + } + +public slots: + void spin() + { + m_tank->turn(90.0); + } + +protected: + void onEntry() + { + connect(m_tank, SIGNAL(actionCompleted()), this, SLOT(spin())); + spin(); + } + +private: + Tank *m_tank; + +}; + +class SpinAiWithError: public QObject, public Plugin +{ + Q_OBJECT + Q_INTERFACES(Plugin) +public: + virtual QState *create(QState *parentState, Tank *tank); +}; + +#endif diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.pro b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.pro new file mode 100644 index 0000000..31f4c7f --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +CONFIG += plugin +INCLUDEPATH += ../.. +HEADERS = spin_ai_with_error.h +SOURCES = spin_ai_with_error.cpp +TARGET = $$qtLibraryTarget(spin_ai_with_error) +DESTDIR = ../../errorstate/plugins + +#! [0] +# install +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/plugins +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS spin_ai_with_error.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins/spin_ai_with_error
\ No newline at end of file |