diff options
author | Eskil Abrahamsen Blomfeldt <eblomfel@trolltech.com> | 2009-04-27 13:24:41 (GMT) |
---|---|---|
committer | Eskil Abrahamsen Blomfeldt <eblomfel@trolltech.com> | 2009-04-28 13:37:55 (GMT) |
commit | a3e862a07bd724c02d1860eb106dfb245659775b (patch) | |
tree | 2e3f388783f1919b6d270935adce0219e63da1b5 /examples/statemachine | |
parent | 77ed0fdc4a74113982dbcd70b689b2addf30516c (diff) | |
download | Qt-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')
-rw-r--r-- | examples/statemachine/errorstate/errorstate.pro | 4 | ||||
-rw-r--r-- | examples/statemachine/errorstate/gameitem.cpp | 67 | ||||
-rw-r--r-- | examples/statemachine/errorstate/gameitem.h | 22 | ||||
-rw-r--r-- | examples/statemachine/errorstate/mainwindow.cpp | 42 | ||||
-rw-r--r-- | examples/statemachine/errorstate/mainwindow.h | 8 | ||||
-rw-r--r-- | examples/statemachine/errorstate/rocketitem.cpp | 60 | ||||
-rw-r--r-- | examples/statemachine/errorstate/rocketitem.h | 28 | ||||
-rw-r--r-- | examples/statemachine/errorstate/tank.h | 4 | ||||
-rw-r--r-- | examples/statemachine/errorstate/tankitem.cpp | 136 | ||||
-rw-r--r-- | examples/statemachine/errorstate/tankitem.h | 21 | ||||
-rw-r--r-- | examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp | 2 | ||||
-rw-r--r-- | examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h | 2 |
12 files changed, 270 insertions, 126 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 diff --git a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp b/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp index 429e3ca..135c7b6 100644 --- a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp +++ b/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp @@ -17,7 +17,7 @@ QState *RandomAiPlugin::create(QState *parentState, Tank *tank) topLevel->setInitialState(selectNextActionState); QState *fireState = new RandomDistanceState(topLevel); - connect(fireState, SIGNAL(distanceComputed(qreal)), tank, SLOT(fireCannon(qreal))); + connect(fireState, SIGNAL(distanceComputed(qreal)), tank, SLOT(fireCannon())); selectNextActionState->addTransition(selectNextActionState, SIGNAL(fireSelected()), fireState); QState *moveForwardsState = new RandomDistanceState(topLevel); diff --git a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h b/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h index 27c9b92..758b3e8 100644 --- a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h +++ b/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h @@ -47,7 +47,7 @@ signals: protected: void onEntry() { - emit distanceComputed(qreal(qrand() % 10)); + emit distanceComputed(qreal(qrand() % 180)); } }; |