diff options
Diffstat (limited to 'examples/statemachine')
6 files changed, 184 insertions, 5 deletions
diff --git a/examples/statemachine/errorstate/tankitem.cpp b/examples/statemachine/errorstate/tankitem.cpp index ae338fe..1e02171 100644 --- a/examples/statemachine/errorstate/tankitem.cpp +++ b/examples/statemachine/errorstate/tankitem.cpp @@ -141,6 +141,11 @@ void TankItem::turn(qreal degrees) setAction(new TurnAction(this, degrees)); } +void TankItem::turnTo(qreal degrees) +{ + setAction(new TurnAction(this, degrees - direction())); +} + void TankItem::stop() { setAction(0); diff --git a/examples/statemachine/errorstate/tankitem.h b/examples/statemachine/errorstate/tankitem.h index 45016ec..cefed69 100644 --- a/examples/statemachine/errorstate/tankitem.h +++ b/examples/statemachine/errorstate/tankitem.h @@ -10,7 +10,7 @@ class TankItem: public GameItem { Q_OBJECT Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) - Q_PROPERTY(qreal direction READ direction WRITE turn) + Q_PROPERTY(qreal direction READ direction WRITE turnTo) Q_PROPERTY(qreal distanceToObstacle READ distanceToObstacle) public: TankItem(QObject *parent = 0); @@ -42,9 +42,10 @@ signals: void cannonFired(); public slots: - void moveForwards(qreal length); - void moveBackwards(qreal length); - void turn(qreal newDirection); + void moveForwards(qreal length = 10.0); + void moveBackwards(qreal length = 10.0); + void turn(qreal degrees = 30.0); + void turnTo(qreal degrees = 0.0); void stop(); void fireCannon(); diff --git a/examples/statemachine/errorstateplugins/errorstateplugins.pro b/examples/statemachine/errorstateplugins/errorstateplugins.pro index e7718a9..5b6b758 100644 --- a/examples/statemachine/errorstateplugins/errorstateplugins.pro +++ b/examples/statemachine/errorstateplugins/errorstateplugins.pro @@ -1,7 +1,8 @@ TEMPLATE = subdirs SUBDIRS = random_ai \ spin_ai_with_error \ - spin_ai + spin_ai \ + seek_ai # install target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp new file mode 100644 index 0000000..229f83a --- /dev/null +++ b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp @@ -0,0 +1,42 @@ +#include "seek_ai.h" + +QState *SeekAi::create(QState *parentState, QObject *tank) +{ + QState *topLevel = new QState(parentState); + topLevel->setObjectName("topLevel"); + + QState *seek = new QState(topLevel); + seek->setObjectName("seek"); + topLevel->setInitialState(seek); + + QState *lookForNearestWall = new SearchState(tank, seek); + lookForNearestWall->setObjectName("lookForNearestWall"); + seek->setInitialState(lookForNearestWall); + + QState *driveToFirstObstacle = new QState(seek); + driveToFirstObstacle->setObjectName("driveToFirstObstacle"); + lookForNearestWall->addTransition(lookForNearestWall, SIGNAL(nearestObstacleStraightAhead()), + driveToFirstObstacle); + + QState *drive = new QState(driveToFirstObstacle); + drive->setObjectName("drive"); + driveToFirstObstacle->setInitialState(drive); + connect(drive, SIGNAL(entered()), tank, SLOT(moveForwards())); + connect(drive, SIGNAL(exited()), tank, SLOT(stop())); + + // Go in loop + QState *finishedDriving = new QState(driveToFirstObstacle); + finishedDriving->setObjectName("finishedDriving"); + drive->addTransition(tank, SIGNAL(actionCompleted()), finishedDriving); + finishedDriving->addTransition(drive); + + QState *turnTo = new QState(seek); + turnTo->setObjectName("turnTo"); + driveToFirstObstacle->addTransition(new CollisionTransition(tank, turnTo)); + + turnTo->addTransition(tank, SIGNAL(actionCompleted()), driveToFirstObstacle); + + return topLevel; +} + +Q_EXPORT_PLUGIN2(seek_ai, SeekAi) diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h new file mode 100644 index 0000000..f96a68f --- /dev/null +++ b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h @@ -0,0 +1,117 @@ +#ifndef SEEK_AI_H +#define SEEK_AI_H + +#include <errorstate/plugin.h> + +#include <QState> +#include <QSignalTransition> +#include <QSignalEvent> +#include <QVariant> +#include <QLineF> + +class SearchState: public QState +{ + Q_OBJECT +public: + SearchState(QObject *tank, QState *parentState = 0) + : QState(parentState), + m_tank(tank), + m_distanceToTurn(360.0), + m_nearestDistance(-1.0), + m_directionOfNearestObstacle(0.0) + { + } + +public slots: + void turnAlittle() + { + qreal dist = m_tank->property("distanceToObstacle").toDouble(); + + if (m_nearestDistance < 0.0 || dist < m_nearestDistance) { + m_nearestDistance = dist; + m_directionOfNearestObstacle = m_tank->property("direction").toDouble(); + } + + m_distanceToTurn -= 10.0; + if (m_distanceToTurn < 0.0) { + disconnect(m_tank, SIGNAL(actionCompleted()), this, SLOT(turnAlittle())); + connect(m_tank, SIGNAL(actionCompleted()), this, SIGNAL(nearestObstacleStraightAhead())); + m_tank->setProperty("direction", m_directionOfNearestObstacle); + } + + qreal currentDirection = m_tank->property("direction").toDouble(); + m_tank->setProperty("direction", currentDirection + 10.0); + } + +signals: + void nearestObstacleStraightAhead(); + +protected: + void onEntry() + { + connect(m_tank, SIGNAL(actionCompleted()), this, SLOT(turnAlittle())); + turnAlittle(); + } + + void onExit() + { + disconnect(m_tank, SIGNAL(actionCompleted()), this, SLOT(turnAlittle())); + disconnect(m_tank, SIGNAL(actionCompleted()), this, SLOT(nearestObstacleStraightAhead())); + } + +private: + QObject *m_tank; + + qreal m_distanceToTurn; + qreal m_nearestDistance; + qreal m_directionOfNearestObstacle; +}; + +class CollisionTransition: public QSignalTransition +{ +public: + CollisionTransition(QObject *tank, QState *turnTo) + : QSignalTransition(tank, SIGNAL(collision(QLineF)), turnTo), + m_tank(tank), + m_turnTo(turnTo) + { + } + +protected: + bool eventTest(QEvent *event) + { + QSignalEvent *se = static_cast<QSignalEvent *>(event); + m_lastLine = se->arguments().at(0).toLineF(); + + return QSignalTransition::eventTest(event); + } + + void onTransition() + { + qreal currentDirection = m_tank->property("direction").toDouble(); + qreal angleOfWall = m_lastLine.angle(); + + qreal newDirection; + if (qAbs(currentDirection - angleOfWall) < qAbs(angleOfWall - currentDirection)) + newDirection = angleOfWall; + else + newDirection = -angleOfWall; + + m_turnTo->assignProperty(m_tank, "direction", newDirection); + } + +private: + QLineF m_lastLine; + QObject *m_tank; + QState *m_turnTo; +}; + +class SeekAi: public QObject, public Plugin +{ + Q_OBJECT + Q_INTERFACES(Plugin) +public: + virtual QState *create(QState *parentState, QObject *tank); +}; + +#endif diff --git a/examples/statemachine/errorstateplugins/seek_ai/seek_ai.pro b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.pro new file mode 100644 index 0000000..11bd242 --- /dev/null +++ b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +CONFIG += plugin +INCLUDEPATH += ../.. +HEADERS = seek_ai.h +SOURCES = seek_ai.cpp +TARGET = $$qtLibraryTarget(seek_ai) +DESTDIR = ../../errorstate/plugins + +#! [0] +# install +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/plugins +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS seek_ai.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins/seek_ai
\ No newline at end of file |