summaryrefslogtreecommitdiffstats
path: root/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h
blob: 7f108a1f122f895af5d8811e330cb9e9281cb28b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#ifndef SEEK_AI_H
#define SEEK_AI_H

#include <errorstate/plugin.h>

#include <QState>
#include <QSignalTransition>
#include <QSignalEvent>
#include <QVariant>
#include <QLineF>
#include <QDebug>

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)
    {
        setTargetState(turnTo);
    }

protected:
    bool eventTest(QEvent *event) const
    {
        if (event->type() == QEvent::Signal) {
            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:
    mutable 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