From 1e4e05144dd8a0c642b6a7f77aa53fa6975d89d9 Mon Sep 17 00:00:00 2001
From: Eskil Abrahamsen Blomfeldt <eblomfel@trolltech.com>
Date: Thu, 30 Apr 2009 12:49:14 +0200
Subject: Add unfinished "more advanced" AI for errorstate.

---
 examples/statemachine/errorstate/tankitem.cpp      |   5 +
 examples/statemachine/errorstate/tankitem.h        |   9 +-
 .../errorstateplugins/errorstateplugins.pro        |   3 +-
 .../errorstateplugins/seek_ai/seek_ai.cpp          |  42 ++++++++
 .../errorstateplugins/seek_ai/seek_ai.h            | 117 +++++++++++++++++++++
 .../errorstateplugins/seek_ai/seek_ai.pro          |  13 +++
 6 files changed, 184 insertions(+), 5 deletions(-)
 create mode 100644 examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp
 create mode 100644 examples/statemachine/errorstateplugins/seek_ai/seek_ai.h
 create mode 100644 examples/statemachine/errorstateplugins/seek_ai/seek_ai.pro

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
-- 
cgit v0.12