summaryrefslogtreecommitdiffstats
path: root/examples/statemachine/errorstate
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eblomfel@trolltech.com>2009-04-27 13:24:41 (GMT)
committerEskil Abrahamsen Blomfeldt <eblomfel@trolltech.com>2009-04-28 13:37:55 (GMT)
commita3e862a07bd724c02d1860eb106dfb245659775b (patch)
tree2e3f388783f1919b6d270935adce0219e63da1b5 /examples/statemachine/errorstate
parent77ed0fdc4a74113982dbcd70b689b2addf30516c (diff)
downloadQt-a3e862a07bd724c02d1860eb106dfb245659775b.zip
Qt-a3e862a07bd724c02d1860eb106dfb245659775b.tar.gz
Qt-a3e862a07bd724c02d1860eb106dfb245659775b.tar.bz2
Some updates to the errorstate example.
Added cannon firing. There are some problems left: For some reason the parallel state group does not work properly, so only one tank moves even if you add more. There also seems to be something wrong with historyState->setDefaultState().
Diffstat (limited to 'examples/statemachine/errorstate')
-rw-r--r--examples/statemachine/errorstate/errorstate.pro4
-rw-r--r--examples/statemachine/errorstate/gameitem.cpp67
-rw-r--r--examples/statemachine/errorstate/gameitem.h22
-rw-r--r--examples/statemachine/errorstate/mainwindow.cpp42
-rw-r--r--examples/statemachine/errorstate/mainwindow.h8
-rw-r--r--examples/statemachine/errorstate/rocketitem.cpp60
-rw-r--r--examples/statemachine/errorstate/rocketitem.h28
-rw-r--r--examples/statemachine/errorstate/tank.h4
-rw-r--r--examples/statemachine/errorstate/tankitem.cpp136
-rw-r--r--examples/statemachine/errorstate/tankitem.h21
10 files changed, 268 insertions, 124 deletions
diff --git a/examples/statemachine/errorstate/errorstate.pro b/examples/statemachine/errorstate/errorstate.pro
index d937b02..c159f94 100644
--- a/examples/statemachine/errorstate/errorstate.pro
+++ b/examples/statemachine/errorstate/errorstate.pro
@@ -8,6 +8,6 @@ DEPENDPATH += .
INCLUDEPATH += C:/dev/kinetic/examples/statemachine/errorstate/. .
# Input
-HEADERS += mainwindow.h plugin.h tank.h tankitem.h
-SOURCES += main.cpp mainwindow.cpp tankitem.cpp
+HEADERS += mainwindow.h plugin.h tank.h tankitem.h rocketitem.h gameitem.h
+SOURCES += main.cpp mainwindow.cpp tankitem.cpp rocketitem.cpp gameitem.cpp
CONFIG += console
diff --git a/examples/statemachine/errorstate/gameitem.cpp b/examples/statemachine/errorstate/gameitem.cpp
new file mode 100644
index 0000000..786cf51
--- /dev/null
+++ b/examples/statemachine/errorstate/gameitem.cpp
@@ -0,0 +1,67 @@
+#include "gameitem.h"
+
+#include <QGraphicsScene>
+
+QPointF GameItem::tryMove(const QPointF &requestedPosition, QLineF *collidedLine,
+ QGraphicsItem **collidedItem) const
+{
+ QLineF movementPath(pos(), requestedPosition);
+
+ qreal cannonLength = 0.0;
+ {
+ QPointF p1 = boundingRect().center();
+ QPointF p2 = QPointF(boundingRect().right() + 10.0, p1.y());
+
+ cannonLength = QLineF(mapToScene(p1), mapToScene(p2)).length();
+ }
+
+ movementPath.setLength(movementPath.length() + cannonLength);
+
+ QRectF boundingRectPath(QPointF(qMin(movementPath.x1(), movementPath.x2()), qMin(movementPath.y1(), movementPath.y2())),
+ QPointF(qMax(movementPath.x1(), movementPath.x2()), qMax(movementPath.y1(), movementPath.y2())));
+
+ QList<QGraphicsItem *> itemsInRect = scene()->items(boundingRectPath, Qt::IntersectsItemBoundingRect);
+
+ QPointF nextPoint = requestedPosition;
+ QRectF sceneRect = scene()->sceneRect();
+
+ foreach (QGraphicsItem *item, itemsInRect) {
+ if (item == static_cast<const QGraphicsItem *>(this))
+ continue;
+
+ QPolygonF mappedBoundingRect = item->mapToScene(item->boundingRect());
+ for (int i=0; i<mappedBoundingRect.size(); ++i) {
+ QPointF p1 = mappedBoundingRect.at(i == 0 ? mappedBoundingRect.size()-1 : i-1);
+ QPointF p2 = mappedBoundingRect.at(i);
+
+ QLineF rectLine(p1, p2);
+ QPointF intersectionPoint;
+ QLineF::IntersectType intersectType = movementPath.intersect(rectLine, &intersectionPoint);
+
+ if (intersectType == QLineF::BoundedIntersection) {
+ movementPath.setP2(intersectionPoint);
+ movementPath.setLength(movementPath.length() - cannonLength);
+ nextPoint = movementPath.p2();
+
+ if (collidedLine != 0)
+ *collidedLine = rectLine;
+
+ if (collidedItem != 0)
+ *collidedItem = item;
+ }
+ }
+ }
+
+ // Don't go outside of map
+ if (nextPoint.x() < sceneRect.left())
+ nextPoint.rx() = sceneRect.left();
+ if (nextPoint.x() > sceneRect.right())
+ nextPoint.rx() = sceneRect.right();
+ if (nextPoint.y() < sceneRect.top())
+ nextPoint.ry() = sceneRect.top();
+ if (nextPoint.y() > sceneRect.bottom())
+ nextPoint.ry() = sceneRect.bottom();
+
+ return nextPoint;
+}
+
diff --git a/examples/statemachine/errorstate/gameitem.h b/examples/statemachine/errorstate/gameitem.h
new file mode 100644
index 0000000..6ca32b7
--- /dev/null
+++ b/examples/statemachine/errorstate/gameitem.h
@@ -0,0 +1,22 @@
+#ifndef GAMEITEM_H
+#define GAMEITEM_H
+
+#include <QGraphicsItem>
+
+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;
+};
+
+#endif
diff --git a/examples/statemachine/errorstate/mainwindow.cpp b/examples/statemachine/errorstate/mainwindow.cpp
index 598756f..c0af62d 100644
--- a/examples/statemachine/errorstate/mainwindow.cpp
+++ b/examples/statemachine/errorstate/mainwindow.cpp
@@ -1,5 +1,6 @@
#include "mainwindow.h"
#include "tankitem.h"
+#include "rocketitem.h"
#include "plugin.h"
#include <QStateMachine>
@@ -13,7 +14,7 @@
#include <QPluginLoader>
MainWindow::MainWindow(QWidget *parent)
- : QMainWindow(parent)
+ : QMainWindow(parent), m_scene(0), m_machine(0), m_runningState(0), m_started(false)
{
init();
}
@@ -37,6 +38,7 @@ void MainWindow::init()
setWindowTitle("Pluggable Tank Game");
QGraphicsView *view = new QGraphicsView(this);
+ view->setRenderHints(QPainter::Antialiasing);
setCentralWidget(view);
m_scene = new QGraphicsScene(this);
@@ -118,6 +120,7 @@ void MainWindow::init()
stoppedState->assignProperty(runGameAction, "enabled", true);
stoppedState->assignProperty(stopGameAction, "enabled", false);
+ stoppedState->assignProperty(this, "started", false);
m_machine->setInitialState(stoppedState);
QState *spawnsAvailable = new QState(stoppedState);
@@ -146,20 +149,42 @@ void MainWindow::init()
timer->setInterval(100);
connect(timer, SIGNAL(timeout()), this, SLOT(runStep()));
connect(m_runningState, SIGNAL(entered()), timer, SLOT(start()));
- connect(m_runningState, SIGNAL(exited()), timer, SLOT(stop()));
+ connect(m_runningState, SIGNAL(exited()), timer, SLOT(stop()));
m_time.start();
}
void MainWindow::runStep()
{
- int elapsed = m_time.elapsed();
- if (elapsed > 0) {
+ if (!m_started) {
m_time.restart();
- qreal elapsedSecs = elapsed / 1000.0;
- QList<TankItem *> tankItems = qFindChildren<TankItem *>(this);
- foreach (TankItem *tankItem, tankItems)
- tankItem->idle(elapsedSecs);
+ m_started = true;
+ } else {
+ int elapsed = m_time.elapsed();
+ if (elapsed > 0) {
+ m_time.restart();
+ qreal elapsedSecs = elapsed / 1000.0;
+ QList<QGraphicsItem *> items = m_scene->items();
+ foreach (QGraphicsItem *item, items) {
+ GameItem *gameItem = qgraphicsitem_cast<GameItem *>(item);
+ if (gameItem != 0)
+ gameItem->idle(elapsedSecs);
+ }
+ }
+ }
+}
+
+void MainWindow::addRocket()
+{
+ TankItem *tankItem = qobject_cast<TankItem *>(sender());
+ if (tankItem != 0) {
+ RocketItem *rocketItem = new RocketItem;
+
+ QPointF s = tankItem->mapToScene(QPointF(tankItem->boundingRect().right() + 10.0,
+ tankItem->boundingRect().center().y()));
+ rocketItem->setPos(s);
+ rocketItem->setDirection(tankItem->direction());
+ m_scene->addItem(rocketItem);
}
}
@@ -175,6 +200,7 @@ void MainWindow::addTank()
if (plugin != 0) {
TankItem *tankItem = m_spawns.takeLast();
m_scene->addItem(tankItem);
+ connect(tankItem, SIGNAL(fireCannon()), this, SLOT(addRocket()));
if (m_spawns.isEmpty())
emit mapFull();
diff --git a/examples/statemachine/errorstate/mainwindow.h b/examples/statemachine/errorstate/mainwindow.h
index 2bd574d..33122eb 100644
--- a/examples/statemachine/errorstate/mainwindow.h
+++ b/examples/statemachine/errorstate/mainwindow.h
@@ -11,12 +11,17 @@ class TankItem;
class MainWindow: public QMainWindow
{
Q_OBJECT
+ Q_PROPERTY(bool started READ started WRITE setStarted)
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
+ void setStarted(bool b) { m_started = b; }
+ bool started() const { return m_started; }
+
public slots:
void addTank();
+ void addRocket();
void runStep();
signals:
@@ -34,7 +39,8 @@ private:
QList<TankItem *> m_spawns;
QTime m_time;
-
+
+ bool m_started : 1;
};
#endif
diff --git a/examples/statemachine/errorstate/rocketitem.cpp b/examples/statemachine/errorstate/rocketitem.cpp
new file mode 100644
index 0000000..de9eef7
--- /dev/null
+++ b/examples/statemachine/errorstate/rocketitem.cpp
@@ -0,0 +1,60 @@
+#include "rocketitem.h"
+
+#include <QPainter>
+#include <QGraphicsScene>
+
+#include <math.h>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+RocketItem::RocketItem()
+ : m_direction(0.0), m_distance(300.0)
+{
+}
+
+QRectF RocketItem::boundingRect() const
+{
+ return QRectF(-1.0, -1.0, 2.0, 2.0);
+}
+
+void RocketItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
+{
+ painter->setBrush(Qt::black);
+ painter->drawEllipse(boundingRect());
+}
+
+void RocketItem::hitByRocket()
+{
+}
+
+void RocketItem::idle(qreal elapsed)
+{
+ qreal dist = elapsed * speed();
+
+ m_distance -= dist;
+ if (m_distance < 0.0) {
+ scene()->removeItem(this);
+ delete this;
+ return;
+ }
+
+ qreal a = m_direction * M_PI / 180.0;
+
+ qreal yd = dist * sin(a);
+ qreal xd = dist * sin(M_PI / 2.0 - a);
+
+ QPointF requestedPosition = pos() + QPointF(xd, yd);
+ QGraphicsItem *collidedItem = 0;
+ QPointF nextPosition = tryMove(requestedPosition, 0, &collidedItem);
+ if (requestedPosition == nextPosition) {
+ setPos(nextPosition);
+ } else {
+ if (GameItem *gameItem = qgraphicsitem_cast<GameItem *>(collidedItem))
+ gameItem->hitByRocket();
+
+ scene()->removeItem(this);
+ delete this;
+ }
+}
diff --git a/examples/statemachine/errorstate/rocketitem.h b/examples/statemachine/errorstate/rocketitem.h
new file mode 100644
index 0000000..9805a8a
--- /dev/null
+++ b/examples/statemachine/errorstate/rocketitem.h
@@ -0,0 +1,28 @@
+#ifndef ROCKETITEM_H
+#define ROCKETITEM_H
+
+#include "gameitem.h"
+
+class RocketItem: public GameItem
+{
+public:
+ RocketItem();
+
+ 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);
+ QRectF boundingRect() const;
+
+
+private:
+ qreal m_direction;
+ qreal m_distance;
+};
+
+
+#endif
diff --git a/examples/statemachine/errorstate/tank.h b/examples/statemachine/errorstate/tank.h
index 9def6df..49c5daf 100644
--- a/examples/statemachine/errorstate/tank.h
+++ b/examples/statemachine/errorstate/tank.h
@@ -23,9 +23,9 @@ signals:
public slots:
virtual void moveForwards(qreal length) = 0;
virtual void moveBackwards(qreal length) = 0;
- virtual void turn(qreal newDirection) = 0;
+ virtual void turn(qreal degrees) = 0;
virtual void stop() = 0;
- virtual void fireCannon(qreal distance) = 0;
+ virtual void fireCannon() = 0;
};
#endif
diff --git a/examples/statemachine/errorstate/tankitem.cpp b/examples/statemachine/errorstate/tankitem.cpp
index 21d4a25..814de2b 100644
--- a/examples/statemachine/errorstate/tankitem.cpp
+++ b/examples/statemachine/errorstate/tankitem.cpp
@@ -31,14 +31,18 @@ public:
MoveAction(TankItem *item, qreal distance)
: Action(item), m_distance(distance)
{
+ m_reverse = m_distance < 0.0;
}
bool apply(qreal timeDelta)
{
- qreal dist = timeDelta * item()->speed();
+ qreal dist = timeDelta * item()->speed() * (m_reverse ? -1.0 : 1.0);
+
m_distance -= dist;
- if (qFuzzyCompare(m_distance, 0.0))
- return false;
+ if (m_reverse && m_distance > 0.0)
+ return false;
+ else if (m_distance < 0.0)
+ return false;
qreal a = item()->direction() * M_PI / 180.0;
@@ -51,6 +55,7 @@ public:
private:
qreal m_distance;
+ bool m_reverse;
};
class TurnAction: public Action
@@ -59,14 +64,17 @@ public:
TurnAction(TankItem *item, qreal distance)
: Action(item), m_distance(distance)
{
+ m_reverse = m_distance < 0.0;
}
bool apply(qreal timeDelta)
{
- qreal dist = timeDelta * item()->angularSpeed();
+ qreal dist = timeDelta * item()->angularSpeed() * (m_reverse ? -1.0 : 1.0);
m_distance -= dist;
- if (qFuzzyCompare(m_distance, 0.0))
- return false;
+ if (m_reverse && m_distance > 0.0)
+ return false;
+ else if (m_distance < 0.0)
+ return false;
item()->setDirection(item()->direction() + dist);
return true;
@@ -74,27 +82,12 @@ public:
private:
qreal m_distance;
-};
-
-class FireCannonAction: public Action
-{
-public:
- FireCannonAction(TankItem *item, qreal distance)
- : Action(item), m_distance(distance)
- {
- }
-
- bool apply(qreal )
- {
- return false;
- }
-
-private:
- qreal m_distance;
+ bool m_reverse;
};
TankItem::TankItem(QObject *parent) : Tank(parent), m_currentAction(0), m_currentDirection(0.0)
{
+ connect(this, SIGNAL(fireCannon()), this, SIGNAL(actionCompleted()));
}
void TankItem::idle(qreal elapsed)
@@ -107,6 +100,11 @@ void TankItem::idle(qreal elapsed)
}
}
+void TankItem::hitByRocket()
+{
+ deleteLater();
+}
+
void TankItem::setAction(Action *newAction)
{
if (m_currentAction != 0)
@@ -125,9 +123,9 @@ void TankItem::moveBackwards(qreal length)
setAction(new MoveAction(this, -length));
}
-void TankItem::turn(qreal newDirection)
+void TankItem::turn(qreal degrees)
{
- setAction(new TurnAction(this, m_currentDirection - newDirection));
+ setAction(new TurnAction(this, degrees));
}
void TankItem::stop()
@@ -135,81 +133,18 @@ void TankItem::stop()
setAction(0);
}
-void TankItem::fireCannon(qreal distance)
-{
- setAction(new FireCannonAction(this, distance));
-}
-
-QPointF TankItem::tryMove(const QPointF &requestedPosition) const
-{
- QLineF movementPath(pos(), requestedPosition);
-
- qreal cannonLength = 0.0;
- {
- QPointF p1 = boundingRect().center();
- QPointF p2 = QPointF(boundingRect().right() + 10.0, p1.y());
-
- cannonLength = QLineF(mapToScene(p1), mapToScene(p2)).length();
- }
-
- movementPath.setLength(movementPath.length() + cannonLength);
-
- QRectF boundingRectPath(QPointF(qMin(movementPath.x1(), movementPath.x2()), qMin(movementPath.y1(), movementPath.y2())),
- QPointF(qMax(movementPath.x1(), movementPath.x2()), qMax(movementPath.y1(), movementPath.y2())));
-
- m_brp = mapFromScene(boundingRectPath);
-
- QList<QGraphicsItem *> itemsInRect = scene()->items(boundingRectPath, Qt::IntersectsItemBoundingRect);
-
- QPointF nextPoint = requestedPosition;
- QRectF sceneRect = scene()->sceneRect();
-
- QLineF collidedLine;
- foreach (QGraphicsItem *item, itemsInRect) {
- if (item == static_cast<const QGraphicsItem *>(this))
- continue;
-
- QPolygonF mappedBoundingRect = item->mapToScene(item->boundingRect());
- for (int i=0; i<mappedBoundingRect.size(); ++i) {
- QPointF p1 = mappedBoundingRect.at(i == 0 ? mappedBoundingRect.size()-1 : i-1);
- QPointF p2 = mappedBoundingRect.at(i);
-
- QLineF rectLine(p1, p2);
- QPointF intersectionPoint;
- QLineF::IntersectType intersectType = movementPath.intersect(rectLine, &intersectionPoint);
-
- if (intersectType == QLineF::BoundedIntersection) {
- movementPath.setP2(intersectionPoint);
- movementPath.setLength(movementPath.length() - cannonLength);
- nextPoint = movementPath.p2();
- collidedLine = rectLine;
- }
- }
- }
-
- // Don't go outside of map
- if (nextPoint.x() < sceneRect.left())
- nextPoint.rx() = sceneRect.left();
- if (nextPoint.x() > sceneRect.right())
- nextPoint.rx() = sceneRect.right();
- if (nextPoint.y() < sceneRect.top())
- nextPoint.ry() = sceneRect.top();
- if (nextPoint.y() > sceneRect.bottom())
- nextPoint.ry() = sceneRect.bottom();
-
- if (nextPoint != requestedPosition) {
- emit collision(collidedLine);
- }
-
- return nextPoint;
-}
-
QVariant TankItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
- if (change == ItemPositionChange && scene())
- return tryMove(value.toPointF());
- else
+ if (change == ItemPositionChange && scene()) {
+ QPointF requestedPosition = value.toPointF();
+ QLineF collidedLine;
+ QPointF nextPoint = tryMove(requestedPosition, &collidedLine);
+ if (nextPoint != requestedPosition)
+ emit collision(collidedLine);
+ return nextPoint;
+ } else {
return QGraphicsItem::itemChange(change, value);
+ }
}
@@ -241,10 +176,6 @@ void TankItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidge
QPointF(brect.right() - 2.0, brect.bottom()));
painter->fillRect(rightTrackRect, Qt::darkYellow);
painter->drawRect(rightTrackRect);
-
- painter->setBrush(QColor::fromRgb(255, 0, 0, 128));
- painter->drawPolygon(m_brp);
-
}
QRectF TankItem::boundingRect() const
@@ -259,8 +190,9 @@ qreal TankItem::direction() const
void TankItem::setDirection(qreal newDirection)
{
+ qreal diff = newDirection - m_currentDirection;
m_currentDirection = newDirection;
- rotate(newDirection);
+ rotate(diff);
}
qreal TankItem::distanceToObstacle() const
diff --git a/examples/statemachine/errorstate/tankitem.h b/examples/statemachine/errorstate/tankitem.h
index df13689..c9e0d22 100644
--- a/examples/statemachine/errorstate/tankitem.h
+++ b/examples/statemachine/errorstate/tankitem.h
@@ -2,12 +2,12 @@
#define TANKITEM_H
#include "tank.h"
+#include "gameitem.h"
-#include <QGraphicsItem>
#include <QColor>
class Action;
-class TankItem: public Tank, public QGraphicsItem
+class TankItem: public Tank, public GameItem
{
Q_OBJECT
public:
@@ -17,7 +17,6 @@ public:
virtual void moveBackwards(qreal length);
virtual void turn(qreal newDirection);
virtual void stop();
- virtual void fireCannon(qreal distance);
virtual qreal direction() const;
virtual qreal distanceToObstacle() const;
@@ -27,22 +26,26 @@ public:
void idle(qreal elapsed);
void setDirection(qreal newDirection);
- qreal speed() const { return 20.0; }
- qreal angularSpeed() const { return 1.0; }
+ qreal speed() const { return 90.0; }
+ qreal angularSpeed() const { return 90.0; }
-protected:
- virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
QRectF boundingRect() const;
+
+ void hitByRocket();
+
+signals:
+ virtual void fireCannon();
+
+protected:
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value);
private:
- QPointF tryMove(const QPointF &requestedPosition) const;
void setAction(Action *newAction);
Action *m_currentAction;
qreal m_currentDirection;
QColor m_color;
- mutable QPolygonF m_brp;
};
#endif