diff options
author | Michael Brasser <michael.brasser@nokia.com> | 2009-05-07 23:41:10 (GMT) |
---|---|---|
committer | Michael Brasser <michael.brasser@nokia.com> | 2009-05-07 23:41:10 (GMT) |
commit | f3164b608e83a3e2c54643aea984095edc275346 (patch) | |
tree | 14b532e90e2a15b8d2ac5d46738971b0bedc561e /examples | |
parent | b7ac7f5b4d4c8e08b4ded43c9720c712a3663810 (diff) | |
parent | 90057dabcb99759bcb42c1c21db7151c69d98706 (diff) | |
download | Qt-f3164b608e83a3e2c54643aea984095edc275346.zip Qt-f3164b608e83a3e2c54643aea984095edc275346.tar.gz Qt-f3164b608e83a3e2c54643aea984095edc275346.tar.bz2 |
Merge branch 'kinetic-animations' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
Conflicts:
src/corelib/animation/qabstractanimation.cpp
src/corelib/animation/qabstractanimation_p.h
src/corelib/animation/qpropertyanimation.cpp
Diffstat (limited to 'examples')
60 files changed, 1855 insertions, 252 deletions
diff --git a/examples/animation/appchooser/main.cpp b/examples/animation/appchooser/main.cpp index 7573347..1c63aba 100644 --- a/examples/animation/appchooser/main.cpp +++ b/examples/animation/appchooser/main.cpp @@ -90,15 +90,16 @@ void createStates(const QObjectList &objects, for (int i = 0; i < objects.size(); ++i) { QState *state = new QState(parent); state->assignProperty(objects.at(i), "geometry", selectedRect); - QAbstractTransition *trans = parent->addTransition(objects.at(i), SIGNAL(clicked()), state); - for (int j = 0; j < objects.size(); ++j) { - QPropertyAnimation *animation = new QPropertyAnimation(objects.at(j), "geometry"); - animation->setDuration(2000); - trans->addAnimation(animation); - } + parent->addTransition(objects.at(i), SIGNAL(clicked()), state); } } +void createAnimations(const QObjectList &objects, QStateMachine *machine) +{ + for (int i=0; i<objects.size(); ++i) + machine->addDefaultAnimation(new QPropertyAnimation(objects.at(i), "geometry")); +} + int main(int argc, char **argv) { Q_INIT_RESOURCE(appchooser); @@ -134,7 +135,7 @@ int main(int argc, char **argv) window.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); QStateMachine machine; - machine.setGlobalRestorePolicy(QState::RestoreProperties); + machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); QState *group = new QState(machine.rootState()); group->setObjectName("group"); @@ -143,7 +144,10 @@ int main(int argc, char **argv) QState *idleState = new QState(group); group->setInitialState(idleState); - createStates(QObjectList() << p1 << p2 << p3 << p4, selectedRect, group); + QObjectList objects; + objects << p1 << p2 << p3 << p4; + createStates(objects, selectedRect, group); + createAnimations(objects, &machine); machine.setInitialState(group); machine.start(); diff --git a/examples/animation/example/mainwindow.cpp b/examples/animation/example/mainwindow.cpp index 3770513..4aff384 100644 --- a/examples/animation/example/mainwindow.cpp +++ b/examples/animation/example/mainwindow.cpp @@ -203,9 +203,9 @@ MainWindow::MainWindow() : QMainWindow(0) setCentralWidget(view); - state3->invokeMethodOnEntry(this, "onEnterState3"); - state2->invokeMethodOnEntry(this, "onEnterState2"); - state1->invokeMethodOnEntry(this, "onEnterState1"); + QObject::connect(state3, SIGNAL(entered()), this, SLOT(onEnterState3())); + QObject::connect(state2, SIGNAL(entered()), this, SLOT(onEnterState2())); + QObject::connect(state1, SIGNAL(entered()), this, SLOT(onEnterState1())); connect(listWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(onItemClicked(QListWidgetItem*))); connect(button3, SIGNAL(clicked()), this, SLOT(onRemoveClicked())); diff --git a/examples/animation/moveblocks/main.cpp b/examples/animation/moveblocks/main.cpp index 076da59..06ed3dd 100644 --- a/examples/animation/moveblocks/main.cpp +++ b/examples/animation/moveblocks/main.cpp @@ -101,7 +101,7 @@ protected: && (static_cast<StateSwitchEvent *>(event)->rand() == m_rand); } - virtual void onTransition() {} + virtual void onTransition(QEvent *) {} private: int m_rand; @@ -116,7 +116,7 @@ public: m_stateCount(0), m_lastIndex(0) { } - virtual void onEntry() + virtual void onEntry(QEvent *) { int n; while ((n = (qrand() % m_stateCount + 1)) == m_lastIndex) @@ -124,7 +124,7 @@ public: m_lastIndex = n; m_machine->postEvent(new StateSwitchEvent(n)); } - virtual void onExit() {} + virtual void onExit(QEvent *) {} void addState(QState *state, QAbstractAnimation *animation) { StateSwitchTransition *trans = new StateSwitchTransition(++m_stateCount); @@ -202,7 +202,7 @@ int main(int argc, char **argv) QTimer timer; timer.setInterval(1250); timer.setSingleShot(true); - group->invokeMethodOnEntry(&timer, "start"); + QObject::connect(group, SIGNAL(entered()), &timer, SLOT(start())); QState *state1; QState *state2; diff --git a/examples/animation/stickman/lifecycle.cpp b/examples/animation/stickman/lifecycle.cpp index 4f2ac6d..b22af55 100644 --- a/examples/animation/stickman/lifecycle.cpp +++ b/examples/animation/stickman/lifecycle.cpp @@ -111,14 +111,12 @@ LifeCycle::LifeCycle(StickMan *stickMan, GraphicsView *keyReceiver) // Set up intial state graph m_machine = new QStateMachine(); - m_machine->setGlobalRestorePolicy(QState::RestoreProperties); m_alive = new QState(m_machine->rootState()); m_alive->setObjectName("alive"); // Make it blink when lightning strikes before entering dead animation QState *lightningBlink = new QState(m_machine->rootState()); - lightningBlink->setRestorePolicy(QState::DoNotRestoreProperties); lightningBlink->assignProperty(m_stickMan->scene(), "backgroundBrush", Qt::white); lightningBlink->assignProperty(m_stickMan, "penColor", Qt::black); lightningBlink->assignProperty(m_stickMan, "fillColor", Qt::white); @@ -127,11 +125,10 @@ LifeCycle::LifeCycle(StickMan *stickMan, GraphicsView *keyReceiver) QTimer *timer = new QTimer(lightningBlink); timer->setSingleShot(true); timer->setInterval(100); - lightningBlink->invokeMethodOnEntry(timer, "start"); - lightningBlink->invokeMethodOnExit(timer, "stop"); + QObject::connect(lightningBlink, SIGNAL(entered()), timer, SLOT(start())); + QObject::connect(lightningBlink, SIGNAL(exited()), timer, SLOT(stop())); m_dead = new QState(m_machine->rootState()); - m_dead->setRestorePolicy(QState::DoNotRestoreProperties); m_dead->assignProperty(m_stickMan->scene(), "backgroundBrush", Qt::black); m_dead->assignProperty(m_stickMan, "penColor", Qt::white); m_dead->assignProperty(m_stickMan, "fillColor", Qt::black); @@ -151,15 +148,6 @@ LifeCycle::LifeCycle(StickMan *stickMan, GraphicsView *keyReceiver) m_machine->setInitialState(m_alive); } -void LifeCycle::setResetKey(Qt::Key resetKey) -{ - // When resetKey is pressed, enter the idle state and do a restoration animation - // (requires no animation pointer, since no property is being set in the idle state) - KeyPressTransition *trans = new KeyPressTransition(m_keyReceiver, resetKey, m_idle); - trans->addAnimation(m_animationGroup); - m_alive->addTransition(trans); -} - void LifeCycle::setDeathAnimation(const QString &fileName) { QState *deathAnimation = makeState(m_dead, fileName); @@ -215,14 +203,14 @@ QState *LifeCycle::makeState(QState *parentState, const QString &animationFileNa topLevel->setInitialState(frameState); } else { connectByAnimation(previousState, frameState, - new QSignalTransition(m_machine, SIGNAL(animationsFinished()))); + new QSignalTransition(previousState, SIGNAL(polished()))); } previousState = frameState; } // Loop connectByAnimation(previousState, topLevel->initialState(), - new QSignalTransition(m_machine, SIGNAL(animationsFinished()))); + new QSignalTransition(previousState, SIGNAL(polished()))); return topLevel; diff --git a/examples/animation/stickman/lifecycle.h b/examples/animation/stickman/lifecycle.h index 4ca6ffd..e520402 100644 --- a/examples/animation/stickman/lifecycle.h +++ b/examples/animation/stickman/lifecycle.h @@ -58,7 +58,6 @@ public: ~LifeCycle(); void setDeathAnimation(const QString &fileName); - void setResetKey(Qt::Key key); void addActivity(const QString &fileName, Qt::Key key); void start(); diff --git a/examples/animation/stickman/main.cpp b/examples/animation/stickman/main.cpp index 6ff437d..62d8252 100644 --- a/examples/animation/stickman/main.cpp +++ b/examples/animation/stickman/main.cpp @@ -64,7 +64,6 @@ int main(int argc, char **argv) "<li>Press <font color=\"purple\">J</font> to make the stickman jump.</li>" "<li>Press <font color=\"purple\">D</font> to make the stickman dance.</li>" "<li>Press <font color=\"purple\">C</font> to make him chill out.</li>" - "<li>Press <font color=\"purple\">Return</font> to make him return to his original position.</li>" "<li>When you are done, press <font color=\"purple\">Escape</font>.</li>" "</i></p>" "<p>If he is unlucky, the stickman will get struck by lightning, and never jump, dance or chill out again." @@ -87,7 +86,6 @@ int main(int argc, char **argv) view->setSceneRect(scene->sceneRect()); LifeCycle *cycle = new LifeCycle(stickMan, view); - cycle->setResetKey(Qt::Key_Return); cycle->setDeathAnimation("animations/dead"); cycle->addActivity("animations/jumping", Qt::Key_J); diff --git a/examples/animation/sub-attaq/animationmanager.cpp b/examples/animation/sub-attaq/animationmanager.cpp index 9f99426..5b9282a 100644 --- a/examples/animation/sub-attaq/animationmanager.cpp +++ b/examples/animation/sub-attaq/animationmanager.cpp @@ -48,7 +48,7 @@ #else # include <QtCore/QAbstractAnimation> #endif -#include <QDebug> +#include <QtCore/QDebug> // the universe's only animation manager AnimationManager *AnimationManager::instance = 0; diff --git a/examples/animation/sub-attaq/animationmanager.h b/examples/animation/sub-attaq/animationmanager.h index fe92680..69ec3d7 100644 --- a/examples/animation/sub-attaq/animationmanager.h +++ b/examples/animation/sub-attaq/animationmanager.h @@ -42,7 +42,7 @@ #ifndef ANIMATIONMANAGER_H #define ANIMATIONMANAGER_H -#include <QObject> +#include <QtCore/QObject> class QAbstractAnimation; diff --git a/examples/animation/sub-attaq/boat.cpp b/examples/animation/sub-attaq/boat.cpp index 5721485..143cf94 100644 --- a/examples/animation/sub-attaq/boat.cpp +++ b/examples/animation/sub-attaq/boat.cpp @@ -59,12 +59,12 @@ # include "qpauseanimation.h" #include "qsequentialanimationgroup.h" #else -#include <QPropertyAnimation> -#include <QStateMachine> -#include <QHistoryState> -#include <QFinalState> -#include <QState> -#include <QSequentialAnimationGroup> +#include <QtCore/QPropertyAnimation> +#include <QtCore/QStateMachine> +#include <QtCore/QHistoryState> +#include <QtCore/QFinalState> +#include <QtCore/QState> +#include <QtCore/QSequentialAnimationGroup> #endif static QAbstractAnimation *setupDestroyAnimation(Boat *boat) @@ -99,10 +99,30 @@ static QAbstractAnimation *setupDestroyAnimation(Boat *boat) anim4->setMemberFunctions((QGraphicsItem*)step4, &QGraphicsItem::opacity, &QGraphicsItem::setOpacity); anim4->setDuration(100); anim4->setEndValue(1); + CustomPropertyAnimation *anim5 = new CustomPropertyAnimation(boat); + anim5->setMemberFunctions((QGraphicsItem*)step1, &QGraphicsItem::opacity, &QGraphicsItem::setOpacity); + anim5->setDuration(100); + anim5->setEndValue(0); + CustomPropertyAnimation *anim6 = new CustomPropertyAnimation(boat); + anim6->setMemberFunctions((QGraphicsItem*)step2, &QGraphicsItem::opacity, &QGraphicsItem::setOpacity); + anim6->setDuration(100); + anim6->setEndValue(0); + CustomPropertyAnimation *anim7 = new CustomPropertyAnimation(boat); + anim7->setMemberFunctions((QGraphicsItem*)step3, &QGraphicsItem::opacity, &QGraphicsItem::setOpacity); + anim7->setDuration(100); + anim7->setEndValue(0); + CustomPropertyAnimation *anim8 = new CustomPropertyAnimation(boat); + anim8->setMemberFunctions((QGraphicsItem*)step4, &QGraphicsItem::opacity, &QGraphicsItem::setOpacity); + anim8->setDuration(100); + anim8->setEndValue(0); group->addAnimation(anim1); group->addAnimation(anim2); group->addAnimation(anim3); group->addAnimation(anim4); + group->addAnimation(anim5); + group->addAnimation(anim6); + group->addAnimation(anim7); + group->addAnimation(anim8); #else // work around for a bug where we don't transition if the duration is zero. QtPauseAnimation *anim = new QtPauseAnimation(group); @@ -126,37 +146,39 @@ Boat::Boat(QGraphicsItem * parent, Qt::WindowFlags wFlags) //The movement animation used to animate the boat movementAnimation = new QPropertyAnimation(this, "pos"); - AnimationManager::self()->registerAnimation(movementAnimation); + + //The movement animation used to animate the boat + destroyAnimation = setupDestroyAnimation(this); //We setup the state machien of the boat - QStateMachine *machine = new QStateMachine(this); + machine = new QStateMachine(this); QState *moving = new QState(machine->rootState()); - StopState *stopState = new StopState(this,moving); + StopState *stopState = new StopState(this, moving); machine->setInitialState(moving); moving->setInitialState(stopState); - MoveStateRight *moveStateRight = new MoveStateRight(this,moving); - MoveStateLeft *moveStateLeft = new MoveStateLeft(this,moving); - LaunchStateRight *launchStateRight = new LaunchStateRight(this,machine->rootState()); - LaunchStateLeft *launchStateLeft = new LaunchStateLeft(this,machine->rootState()); + MoveStateRight *moveStateRight = new MoveStateRight(this, moving); + MoveStateLeft *moveStateLeft = new MoveStateLeft(this, moving); + LaunchStateRight *launchStateRight = new LaunchStateRight(this, machine->rootState()); + LaunchStateLeft *launchStateLeft = new LaunchStateLeft(this, machine->rootState()); //then setup the transitions for the rightMove state - KeyStopTransition *leftStopRight = new KeyStopTransition(this,QEvent::KeyPress,Qt::Key_Left); + KeyStopTransition *leftStopRight = new KeyStopTransition(this, QEvent::KeyPress, Qt::Key_Left); leftStopRight->setTargetState(stopState); - KeyMoveTransition *leftMoveRight = new KeyMoveTransition(this,QEvent::KeyPress,Qt::Key_Left); + KeyMoveTransition *leftMoveRight = new KeyMoveTransition(this, QEvent::KeyPress, Qt::Key_Left); leftMoveRight->setTargetState(moveStateRight); - KeyMoveTransition *rightMoveRight = new KeyMoveTransition(this,QEvent::KeyPress,Qt::Key_Right); + KeyMoveTransition *rightMoveRight = new KeyMoveTransition(this, QEvent::KeyPress, Qt::Key_Right); rightMoveRight->setTargetState(moveStateRight); - KeyMoveTransition *rightMoveStop = new KeyMoveTransition(this,QEvent::KeyPress,Qt::Key_Right); + KeyMoveTransition *rightMoveStop = new KeyMoveTransition(this, QEvent::KeyPress, Qt::Key_Right); rightMoveStop->setTargetState(moveStateRight); //then setup the transitions for the leftMove state - KeyStopTransition *rightStopLeft = new KeyStopTransition(this,QEvent::KeyPress,Qt::Key_Right); + KeyStopTransition *rightStopLeft = new KeyStopTransition(this, QEvent::KeyPress, Qt::Key_Right); rightStopLeft->setTargetState(stopState); - KeyMoveTransition *rightMoveLeft = new KeyMoveTransition(this,QEvent::KeyPress,Qt::Key_Right); + KeyMoveTransition *rightMoveLeft = new KeyMoveTransition(this, QEvent::KeyPress, Qt::Key_Right); rightMoveLeft->setTargetState(moveStateLeft); - KeyMoveTransition *leftMoveLeft = new KeyMoveTransition(this,QEvent::KeyPress,Qt::Key_Left); + KeyMoveTransition *leftMoveLeft = new KeyMoveTransition(this, QEvent::KeyPress,Qt::Key_Left); leftMoveLeft->setTargetState(moveStateLeft); - KeyMoveTransition *leftMoveStop = new KeyMoveTransition(this,QEvent::KeyPress,Qt::Key_Left); + KeyMoveTransition *leftMoveStop = new KeyMoveTransition(this, QEvent::KeyPress,Qt::Key_Left); leftMoveStop->setTargetState(moveStateLeft); //We set up the right move state @@ -176,17 +198,17 @@ Boat::Boat(QGraphicsItem * parent, Qt::WindowFlags wFlags) moveStateRight->addTransition(movementAnimation, SIGNAL(finished()), stopState); //We set up the keys for dropping bombs - KeyLaunchTransition *upFireLeft = new KeyLaunchTransition(this,QEvent::KeyPress,Qt::Key_Up); + KeyLaunchTransition *upFireLeft = new KeyLaunchTransition(this, QEvent::KeyPress, Qt::Key_Up); upFireLeft->setTargetState(launchStateRight); - KeyLaunchTransition *upFireRight = new KeyLaunchTransition(this,QEvent::KeyPress,Qt::Key_Up); + KeyLaunchTransition *upFireRight = new KeyLaunchTransition(this, QEvent::KeyPress, Qt::Key_Up); upFireRight->setTargetState(launchStateRight); - KeyLaunchTransition *upFireStop = new KeyLaunchTransition(this,QEvent::KeyPress,Qt::Key_Up); + KeyLaunchTransition *upFireStop = new KeyLaunchTransition(this, QEvent::KeyPress, Qt::Key_Up); upFireStop->setTargetState(launchStateRight); - KeyLaunchTransition *downFireLeft = new KeyLaunchTransition(this,QEvent::KeyPress,Qt::Key_Down); + KeyLaunchTransition *downFireLeft = new KeyLaunchTransition(this, QEvent::KeyPress, Qt::Key_Down); downFireLeft->setTargetState(launchStateLeft); - KeyLaunchTransition *downFireRight = new KeyLaunchTransition(this,QEvent::KeyPress,Qt::Key_Down); + KeyLaunchTransition *downFireRight = new KeyLaunchTransition(this, QEvent::KeyPress, Qt::Key_Down); downFireRight->setTargetState(launchStateLeft); - KeyLaunchTransition *downFireMove = new KeyLaunchTransition(this,QEvent::KeyPress,Qt::Key_Down); + KeyLaunchTransition *downFireMove = new KeyLaunchTransition(this, QEvent::KeyPress, Qt::Key_Down); downFireMove->setTargetState(launchStateLeft); //We set up transitions for fire up @@ -200,7 +222,7 @@ Boat::Boat(QGraphicsItem * parent, Qt::WindowFlags wFlags) stopState->addTransition(downFireMove); //Finally the launch state should come back to its original state - QHistoryState *historyState = moving->addHistoryState(); + QHistoryState *historyState = new QHistoryState(moving); launchStateLeft->addTransition(historyState); launchStateRight->addTransition(historyState); @@ -208,7 +230,7 @@ Boat::Boat(QGraphicsItem * parent, Qt::WindowFlags wFlags) //This state play the destroyed animation QAnimationState *destroyedState = new QAnimationState(machine->rootState()); - destroyedState->setAnimation(setupDestroyAnimation(this)); + destroyedState->setAnimation(destroyAnimation); //Play a nice animation when the boat is destroyed moving->addTransition(this, SIGNAL(boatDestroyed()),destroyedState); @@ -219,9 +241,22 @@ Boat::Boat(QGraphicsItem * parent, Qt::WindowFlags wFlags) //The machine has finished to be executed, then the boat is dead connect(machine,SIGNAL(finished()),this, SIGNAL(boatExecutionFinished())); +} + +void Boat::run() +{ + //We register animations + AnimationManager::self()->registerAnimation(movementAnimation); + AnimationManager::self()->registerAnimation(destroyAnimation); machine->start(); } +void Boat::stop() +{ + movementAnimation->stop(); + machine->stop(); +} + void Boat::updateBoatMovement() { if (speed == 0 || direction == Boat::None) { diff --git a/examples/animation/sub-attaq/boat.h b/examples/animation/sub-attaq/boat.h index b8d5772..b28cf20 100644 --- a/examples/animation/sub-attaq/boat.h +++ b/examples/animation/sub-attaq/boat.h @@ -43,10 +43,8 @@ #define __BOAT__H__ //Qt -#include <QObject> -#include <QKeyEvent> - -#include <QDebug> +#include <QtCore/QObject> +#include <QtGui/QKeyEvent> #if defined(QT_EXPERIMENTAL_SOLUTION) # include "qtgraphicswidget.h" @@ -57,6 +55,8 @@ class PixmapItem; class Bomb; class QVariantAnimation; +class QAbstractAnimation; +class QStateMachine; class Boat : public QGraphicsWidget { @@ -71,6 +71,8 @@ public: enum { Type = UserType + 2 }; Boat(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0); void destroy(); + void run(); + void stop(); int bombsLaunched() const; void setBombsLaunched(int number); @@ -94,6 +96,8 @@ private: int bombsAlreadyLaunched; Movement direction; QVariantAnimation *movementAnimation; + QAbstractAnimation *destroyAnimation; + QStateMachine *machine; PixmapItem *pixmapItem; }; diff --git a/examples/animation/sub-attaq/boat_p.h b/examples/animation/sub-attaq/boat_p.h index 8dacaba..17fbe5c 100644 --- a/examples/animation/sub-attaq/boat_p.h +++ b/examples/animation/sub-attaq/boat_p.h @@ -61,13 +61,10 @@ class KeyStopTransition : public QKeyEventTransition { public: KeyStopTransition(Boat *boat, QEvent::Type type, int key) - : QKeyEventTransition(boat,type, key) + : QKeyEventTransition(boat, type, key) { this->boat = boat; this->key = key; -#if defined(Q_OS_MAC) - setModifiers(Qt::KeypadModifier); -#endif } protected: virtual bool eventTest(QEvent *event) const @@ -90,13 +87,10 @@ private: { public: KeyMoveTransition(Boat *boat, QEvent::Type type, int key) - : QKeyEventTransition(boat,type, key) + : QKeyEventTransition(boat, type, key) { this->boat = boat; this->key = key; -#if defined(Q_OS_MAC) - setModifiers(Qt::KeypadModifier); -#endif } protected: virtual bool eventTest(QEvent *event) const @@ -110,7 +104,7 @@ protected: return false; } - void onTransition() + void onTransition(QEvent *) { //We decrease the speed if needed if (key == Qt::Key_Left && boat->currentDirection() == Boat::Right) @@ -131,13 +125,10 @@ private: { public: KeyLaunchTransition(Boat *boat, QEvent::Type type, int key) - : QKeyEventTransition(boat,type, key) + : QKeyEventTransition(boat, type, key) { this->boat = boat; this->key = key; -#if defined(Q_OS_MAC) - setModifiers(Qt::KeypadModifier); -#endif } protected: virtual bool eventTest(QEvent *event) const @@ -165,7 +156,7 @@ public: this->boat = boat; } protected: - void onEntry() + void onEntry(QEvent *) { boat->setCurrentDirection(Boat::Right); boat->updateBoatMovement(); @@ -183,7 +174,7 @@ public: this->boat = boat; } protected: - void onEntry() + void onEntry(QEvent *) { boat->setCurrentDirection(Boat::Left); boat->updateBoatMovement(); @@ -201,7 +192,7 @@ public: this->boat = boat; } protected: - void onEntry() + void onEntry(QEvent *) { boat->setCurrentSpeed(0); boat->setCurrentDirection(Boat::None); @@ -220,7 +211,7 @@ public: this->boat = boat; } protected: - void onEntry() + void onEntry(QEvent *) { Bomb *b = new Bomb(); b->setPos(boat->x()+boat->size().width(),boat->y()); @@ -242,7 +233,7 @@ public: this->boat = boat; } protected: - void onEntry() + void onEntry(QEvent *) { Bomb *b = new Bomb(); b->setPos(boat->x() - b->size().width(), boat->y()); diff --git a/examples/animation/sub-attaq/graphicsscene.cpp b/examples/animation/sub-attaq/graphicsscene.cpp index 5dcc034..2a6f83c 100644 --- a/examples/animation/sub-attaq/graphicsscene.cpp +++ b/examples/animation/sub-attaq/graphicsscene.cpp @@ -50,6 +50,7 @@ #include "custompropertyanimation.h" #include "animationmanager.h" #include "qanimationstate.h" +#include "progressitem.h" //Qt #if defined(QT_EXPERIMENTAL_SOLUTION) @@ -60,20 +61,20 @@ #include "qfinalstate.h" #include "qpauseanimation.h" #else -#include <QPropertyAnimation> -#include <QSequentialAnimationGroup> -#include <QParallelAnimationGroup> -#include <QStateMachine> -#include <QFinalState> -#include <QPauseAnimation> +#include <QtCore/QPropertyAnimation> +#include <QtCore/QSequentialAnimationGroup> +#include <QtCore/QParallelAnimationGroup> +#include <QtCore/QStateMachine> +#include <QtCore/QFinalState> +#include <QtCore/QPauseAnimation> #endif -#include <QAction> -#include <QDir> -#include <QApplication> -#include <QMessageBox> -#include <QGraphicsView> -#include <QGraphicsSceneMouseEvent> -#include <QXmlStreamReader> +#include <QtGui/QAction> +#include <QtCore/QDir> +#include <QtGui/QApplication> +#include <QtGui/QMessageBox> +#include <QtGui/QGraphicsView> +#include <QtGui/QGraphicsSceneMouseEvent> +#include <QtCore/QXmlStreamReader> //helper function that creates an animation for position and inserts it into group static CustomPropertyAnimation *addGraphicsItemPosAnimation(QSequentialAnimationGroup *group, @@ -117,6 +118,15 @@ GraphicsScene::GraphicsScene(int x, int y, int width, int height, Mode mode) surfaceItem->setPos(0,sealLevel() - surfaceItem->boundingRect().height()/2); addItem(surfaceItem); + //The item that display score and level + progressItem = new ProgressItem(backgroundItem); + + //We create the boat + boat = new Boat(); + addItem(boat); + boat->setPos(this->width()/2, sealLevel() - boat->size().height()); + boat->hide(); + //parse the xml that contain all data of the game QXmlStreamReader reader; QFile file(QDir::currentPath() + "/data.xml"); @@ -335,17 +345,17 @@ void GraphicsScene::clearScene() { foreach (SubMarine *sub,submarines) { sub->destroy(); - delete sub; + sub->deleteLater(); } foreach (Torpedo *torpedo,torpedos) { torpedo->destroy(); - delete torpedo; + torpedo->deleteLater(); } foreach (Bomb *bomb,bombs) { bomb->destroy(); - delete bomb; + bomb->deleteLater(); } submarines.clear(); @@ -354,10 +364,8 @@ void GraphicsScene::clearScene() AnimationManager::self()->unregisterAllAnimations(); - if (boat) { - delete boat; - boat = 0; - } + boat->stop(); + boat->hide(); } QGraphicsPixmapItem *GraphicsScene::addWelcomeItem(const QPixmap &pm) diff --git a/examples/animation/sub-attaq/graphicsscene.h b/examples/animation/sub-attaq/graphicsscene.h index 875f59f..0840564 100644 --- a/examples/animation/sub-attaq/graphicsscene.h +++ b/examples/animation/sub-attaq/graphicsscene.h @@ -43,13 +43,13 @@ #define __GRAPHICSSCENE__H__ //Qt -#include <QGraphicsScene> -#include <QSet> +#include <QtGui/QGraphicsScene> +#include <QtCore/QSet> #if defined(QT_EXPERIMENTAL_SOLUTION) # include "qstate.h" #else -# include <QState> +# include <QtCore/QState> #endif @@ -58,6 +58,7 @@ class SubMarine; class Torpedo; class Bomb; class PixmapItem; +class ProgressItem; class QAction; class GraphicsScene : public QGraphicsScene @@ -109,6 +110,7 @@ private slots: private: Mode mode; PixmapItem *backgroundItem; + ProgressItem *progressItem; QAction * newAction; QAction * quitAction; Boat *boat; @@ -121,8 +123,11 @@ private: friend class PauseState; friend class PlayState; + friend class LevelState; friend class LostState; friend class WinState; + friend class WinTransition; + friend class UpdateScoreTransition; }; #endif //__GRAPHICSSCENE__H__ diff --git a/examples/animation/sub-attaq/mainwindow.cpp b/examples/animation/sub-attaq/mainwindow.cpp index c25b9ef..a166241 100644 --- a/examples/animation/sub-attaq/mainwindow.cpp +++ b/examples/animation/sub-attaq/mainwindow.cpp @@ -47,7 +47,7 @@ #include <QtOpenGL/QtOpenGL> #endif //Qt -#include <QGraphicsView> +#include <QtGui/QGraphicsView> MainWindow::MainWindow() : QMainWindow(0) { diff --git a/examples/animation/sub-attaq/mainwindow.h b/examples/animation/sub-attaq/mainwindow.h index 6289b3f..72d1324 100644 --- a/examples/animation/sub-attaq/mainwindow.h +++ b/examples/animation/sub-attaq/mainwindow.h @@ -43,7 +43,7 @@ #define __MAINWINDOW__H__ //Qt -#include <QMainWindow> +#include <QtGui/QMainWindow> class GraphicsScene; class QGraphicsView; diff --git a/examples/animation/sub-attaq/pixmapitem.cpp b/examples/animation/sub-attaq/pixmapitem.cpp index aa8b552..22a363f 100644 --- a/examples/animation/sub-attaq/pixmapitem.cpp +++ b/examples/animation/sub-attaq/pixmapitem.cpp @@ -43,7 +43,7 @@ #include "pixmapitem.h" //Qt -#include <QDir> +#include <QtCore/QDir> PixmapItem::PixmapItem(const QString &fileName,GraphicsScene::Mode mode, QGraphicsItem * parent) : QGraphicsPixmapItem(parent),name(fileName) { diff --git a/examples/animation/sub-attaq/pixmapitem.h b/examples/animation/sub-attaq/pixmapitem.h index f3c1a41..31022c1 100644 --- a/examples/animation/sub-attaq/pixmapitem.h +++ b/examples/animation/sub-attaq/pixmapitem.h @@ -46,7 +46,7 @@ #include "graphicsscene.h" //Qt -#include <QGraphicsPixmapItem> +#include <QtGui/QGraphicsPixmapItem> class PixmapItem : public QGraphicsPixmapItem { diff --git a/examples/animation/sub-attaq/progressitem.cpp b/examples/animation/sub-attaq/progressitem.cpp new file mode 100644 index 0000000..59ccb9a --- /dev/null +++ b/examples/animation/sub-attaq/progressitem.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "progressitem.h" +#include "pixmapitem.h" + +ProgressItem::ProgressItem (QGraphicsItem * parent) + : QGraphicsTextItem(parent), currentLevel(1), currentScore(0) +{ + setFont(QFont("Comic Sans MS")); + setPos(parentItem()->boundingRect().topRight() - QPointF(180, -5)); +} + +void ProgressItem::setLevel(int level) +{ + currentLevel = level; + updateProgress(); +} + +void ProgressItem::setScore(int score) +{ + currentScore = score; + updateProgress(); +} + +void ProgressItem::updateProgress() +{ + setHtml(QString("Level : %1 Score : %2").arg(currentLevel).arg(currentScore)); +} diff --git a/examples/animation/sub-attaq/progressitem.h b/examples/animation/sub-attaq/progressitem.h new file mode 100644 index 0000000..7b8db4d --- /dev/null +++ b/examples/animation/sub-attaq/progressitem.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PROGRESSITEM_H +#define PROGRESSITEM_H + +//Qt +#include <QtGui/QGraphicsTextItem> + +class ProgressItem : public QGraphicsTextItem +{ +public: + ProgressItem(QGraphicsItem * parent = 0); + void setLevel(int level); + void setScore(int score); + +private: + void updateProgress(); + int currentLevel; + int currentScore; +}; + +#endif // PROGRESSITEM_H diff --git a/examples/animation/sub-attaq/qanimationstate.cpp b/examples/animation/sub-attaq/qanimationstate.cpp index 3659657..0f30ac2 100644 --- a/examples/animation/sub-attaq/qanimationstate.cpp +++ b/examples/animation/sub-attaq/qanimationstate.cpp @@ -146,7 +146,7 @@ QAbstractAnimation* QAnimationState::animation() const /*! \reimp */ -void QAnimationState::onEntry() +void QAnimationState::onEntry(QEvent *) { Q_D(QAnimationState); if (d->animation) @@ -156,7 +156,7 @@ void QAnimationState::onEntry() /*! \reimp */ -void QAnimationState::onExit() +void QAnimationState::onExit(QEvent *) { Q_D(QAnimationState); if (d->animation) diff --git a/examples/animation/sub-attaq/qanimationstate.h b/examples/animation/sub-attaq/qanimationstate.h index ddf5681..88c0a6d 100644 --- a/examples/animation/sub-attaq/qanimationstate.h +++ b/examples/animation/sub-attaq/qanimationstate.h @@ -74,8 +74,8 @@ Q_SIGNALS: void animationFinished(); protected: - void onEntry(); - void onExit(); + void onEntry(QEvent *); + void onExit(QEvent *); bool event(QEvent *e); private: diff --git a/examples/animation/sub-attaq/states.cpp b/examples/animation/sub-attaq/states.cpp index f476f55..c6af924 100644 --- a/examples/animation/sub-attaq/states.cpp +++ b/examples/animation/sub-attaq/states.cpp @@ -46,10 +46,11 @@ #include "submarine.h" #include "torpedo.h" #include "animationmanager.h" +#include "progressitem.h" //Qt -#include <QMessageBox> -#include <QGraphicsView> +#include <QtGui/QMessageBox> +#include <QtGui/QGraphicsView> #if defined(QT_EXPERIMENTAL_SOLUTION) #include "qstatemachine.h" #include "qkeyeventtransition.h" @@ -59,7 +60,7 @@ #include <QtCore/QStateMachine> #include <QtGui/QKeyEventTransition> #include <QtCore/QSignalEvent> -#include <QFinalState> +#include <QtCore/QFinalState> #endif PlayState::PlayState(GraphicsScene *scene, QState *parent) @@ -75,33 +76,37 @@ PlayState::~PlayState() { } -void PlayState::onEntry() +void PlayState::onEntry(QEvent *) { //We are now playing? if (machine) { machine->stop(); scene->clearScene(); + currentLevel = 0; + score = 0; delete machine; } machine = new QStateMachine(this); //This state is when player is playing - QState *playState = new QState(machine->rootState()); + LevelState *levelState = new LevelState(scene, this, machine->rootState()); - initializeLevel(); + //This state is when the player is actually playing but the game is not paused + QState *playingState = new QState(levelState); + levelState->setInitialState(playingState); //This state is when the game is paused - PauseState *pauseState = new PauseState(scene, machine->rootState()); + PauseState *pauseState = new PauseState(scene, levelState); //We have one view, it receive the key press event QKeyEventTransition *pressPplay = new QKeyEventTransition(scene->views().at(0), QEvent::KeyPress, Qt::Key_P); pressPplay->setTargetState(pauseState); QKeyEventTransition *pressPpause = new QKeyEventTransition(scene->views().at(0), QEvent::KeyPress, Qt::Key_P); - pressPpause->setTargetState(playState); + pressPpause->setTargetState(playingState); //Pause "P" is triggered, the player pause the game - playState->addTransition(pressPplay); + playingState->addTransition(pressPplay); //To get back playing when the game has been paused pauseState->addTransition(pressPpause); @@ -113,49 +118,67 @@ void PlayState::onEntry() WinState *winState = new WinState(scene, this, machine->rootState()); //The boat has been destroyed then the game is finished - playState->addTransition(scene->boat, SIGNAL(boatExecutionFinished()),lostState); + levelState->addTransition(scene->boat, SIGNAL(boatExecutionFinished()),lostState); //This transition check if we won or not WinTransition *winTransition = new WinTransition(scene, this, winState); //The boat has been destroyed then the game is finished - playState->addTransition(winTransition); + levelState->addTransition(winTransition); //This state is an animation when the score changed - UpdateScoreState *scoreState = new UpdateScoreState(this, machine->rootState()); + UpdateScoreState *scoreState = new UpdateScoreState(this, levelState); //This transition update the score when a submarine die - UpdateScoreTransition *scoreTransition = new UpdateScoreTransition(scene, this, scoreState); + UpdateScoreTransition *scoreTransition = new UpdateScoreTransition(scene, this, levelState); + scoreTransition->setTargetState(scoreState); //The boat has been destroyed then the game is finished - playState->addTransition(scoreTransition); + playingState->addTransition(scoreTransition); //We go back to play state - scoreState->addTransition(playState); + scoreState->addTransition(playingState); //We start playing!!! - machine->setInitialState(playState); + machine->setInitialState(levelState); //Final state QFinalState *final = new QFinalState(machine->rootState()); - //We win we should reach the final state - winState->addFinishedTransition(final); + //This transition is triggered when the player press space after completing a level + CustomSpaceTransition *spaceTransition = new CustomSpaceTransition(scene->views().at(0), this, QEvent::KeyPress, Qt::Key_Space); + spaceTransition->setTargetState(levelState); + winState->addTransition(spaceTransition); //We lost we should reach the final state - lostState->addFinishedTransition(final); + lostState->addTransition(lostState, SIGNAL(finished()), final); machine->start(); } -void PlayState::initializeLevel() +LevelState::LevelState(GraphicsScene *scene, PlayState *game, QState *parent) : QState(parent), scene(scene), game(game) { - scene->boat = new Boat(); - scene->addItem(scene->boat); - scene->setFocusItem(scene->boat,Qt::OtherFocusReason); +} +void LevelState::onEntry(QEvent *) +{ + initializeLevel(); +} + +void LevelState::initializeLevel() +{ + //we re-init the boat scene->boat->setPos(scene->width()/2, scene->sealLevel() - scene->boat->size().height()); + scene->boat->setCurrentSpeed(0); + scene->boat->setCurrentDirection(Boat::None); + scene->boat->setBombsLaunched(0); + scene->boat->show(); + scene->setFocusItem(scene->boat,Qt::OtherFocusReason); + scene->boat->run(); + + scene->progressItem->setScore(game->score); + scene->progressItem->setLevel(game->currentLevel + 1); - GraphicsScene::LevelDescription currentLevelDescription = scene->levelsData.value(currentLevel); + GraphicsScene::LevelDescription currentLevelDescription = scene->levelsData.value(game->currentLevel); for (int i = 0; i < currentLevelDescription.submarines.size(); ++i ) { @@ -179,12 +202,12 @@ void PlayState::initializeLevel() PauseState::PauseState(GraphicsScene *scene, QState *parent) : QState(parent),scene(scene) { } -void PauseState::onEntry() +void PauseState::onEntry(QEvent *) { AnimationManager::self()->pauseAll(); scene->boat->setEnabled(false); } -void PauseState::onExit() +void PauseState::onExit(QEvent *) { AnimationManager::self()->resumeAll(); scene->boat->setEnabled(true); @@ -196,7 +219,7 @@ LostState::LostState(GraphicsScene *scene, PlayState *game, QState *parent) : QS { } -void LostState::onEntry() +void LostState::onEntry(QEvent *) { //The message to display QString message = QString("You lose on level %1. Your score is %2.").arg(game->currentLevel+1).arg(game->score); @@ -219,14 +242,14 @@ WinState::WinState(GraphicsScene *scene, PlayState *game, QState *parent) : QSta { } -void WinState::onEntry() +void WinState::onEntry(QEvent *) { //We clear the scene scene->clearScene(); QString message; if (scene->levelsData.size() - 1 != game->currentLevel) { - message = QString("You win the level %1. Your score is %2.").arg(game->currentLevel+1).arg(game->score); + message = QString("You win the level %1. Your score is %2.\nPress Space to continue after closing this dialog.").arg(game->currentLevel+1).arg(game->score); //We increment the level number game->currentLevel++; } else { @@ -246,16 +269,15 @@ UpdateScoreState::UpdateScoreState(PlayState *game, QState *parent) : QState(par { this->game = game; } -void UpdateScoreState::onEntry() +void UpdateScoreState::onEntry(QEvent *e) { - //### Make a nice anim to update the score in the scene - QState::onEntry(); + QState::onEntry(e); } /** Win transition */ UpdateScoreTransition::UpdateScoreTransition(GraphicsScene *scene, PlayState *game, QAbstractState *target) : QSignalTransition(scene,SIGNAL(subMarineDestroyed(int)), QList<QAbstractState*>() << target), - game(game) + game(game), scene(scene) { } @@ -266,6 +288,7 @@ bool UpdateScoreTransition::eventTest(QEvent *event) const else { QSignalEvent *se = static_cast<QSignalEvent*>(event); game->score += se->arguments().at(0).toInt(); + scene->progressItem->setScore(game->score); return true; } } @@ -273,7 +296,7 @@ bool UpdateScoreTransition::eventTest(QEvent *event) const /** Win transition */ WinTransition::WinTransition(GraphicsScene *scene, PlayState *game, QAbstractState *target) : QSignalTransition(scene,SIGNAL(allSubMarineDestroyed(int)), QList<QAbstractState*>() << target), - game(game) + game(game), scene(scene) { } @@ -284,6 +307,26 @@ bool WinTransition::eventTest(QEvent *event) const else { QSignalEvent *se = static_cast<QSignalEvent*>(event); game->score += se->arguments().at(0).toInt(); + scene->progressItem->setScore(game->score); return true; } } + +/** Space transition */ +CustomSpaceTransition::CustomSpaceTransition(QWidget *widget, PlayState *game, QEvent::Type type, int key) + : QKeyEventTransition(widget, type, key), + game(game) +{ +} + +bool CustomSpaceTransition::eventTest(QEvent *event) const +{ + Q_UNUSED(event); + if (!QKeyEventTransition::eventTest(event)) + return false; + if (game->currentLevel != 0) + return true; + else + return false; + +} diff --git a/examples/animation/sub-attaq/states.h b/examples/animation/sub-attaq/states.h index 52d4ffa..27beb71 100644 --- a/examples/animation/sub-attaq/states.h +++ b/examples/animation/sub-attaq/states.h @@ -47,12 +47,14 @@ #include "qstate.h" #include "qsignaltransition.h" #include "qpropertyanimation.h" +#include "qkeyeventtransition.h" #else -#include <QState> -#include <QSignalTransition> -#include <QPropertyAnimation> +#include <QtCore/QState> +#include <QtCore/QSignalTransition> +#include <QtCore/QPropertyAnimation> +# include <QtGui/QKeyEventTransition> #endif -#include <QSet> +#include <QtCore/QSet> class GraphicsScene; class Boat; @@ -64,10 +66,9 @@ class PlayState : public QState public: PlayState(GraphicsScene *scene, QState *parent = 0); ~PlayState(); - void initializeLevel(); protected: - void onEntry(); + void onEntry(QEvent *); private : GraphicsScene *scene; @@ -79,8 +80,22 @@ private : friend class UpdateScoreState; friend class UpdateScoreTransition; friend class WinTransition; + friend class CustomSpaceTransition; friend class WinState; friend class LostState; + friend class LevelState; +}; + +class LevelState : public QState +{ +public: + LevelState(GraphicsScene *scene, PlayState *game, QState *parent = 0); +protected: + void onEntry(QEvent *); +private : + void initializeLevel(); + GraphicsScene *scene; + PlayState *game; }; class PauseState : public QState @@ -89,8 +104,8 @@ public: PauseState(GraphicsScene *scene, QState *parent = 0); protected: - void onEntry(); - void onExit(); + void onEntry(QEvent *); + void onExit(QEvent *); private : GraphicsScene *scene; Boat *boat; @@ -102,7 +117,7 @@ public: LostState(GraphicsScene *scene, PlayState *game, QState *parent = 0); protected: - void onEntry(); + void onEntry(QEvent *); private : GraphicsScene *scene; PlayState *game; @@ -114,7 +129,7 @@ public: WinState(GraphicsScene *scene, PlayState *game, QState *parent = 0); protected: - void onEntry(); + void onEntry(QEvent *); private : GraphicsScene *scene; PlayState *game; @@ -125,7 +140,7 @@ class UpdateScoreState : public QState public: UpdateScoreState(PlayState *game, QState *parent); protected: - void onEntry(); + void onEntry(QEvent *); private: QPropertyAnimation *scoreAnimation; PlayState *game; @@ -140,6 +155,7 @@ protected: virtual bool eventTest(QEvent *event) const; private: PlayState * game; + GraphicsScene *scene; }; //These transtion test if we have won the game @@ -151,6 +167,19 @@ protected: virtual bool eventTest(QEvent *event) const; private: PlayState * game; + GraphicsScene *scene; +}; + +//These transtion is true if one level has been completed and the player want to continue + class CustomSpaceTransition : public QKeyEventTransition +{ +public: + CustomSpaceTransition(QWidget *widget, PlayState *game, QEvent::Type type, int key); +protected: + virtual bool eventTest(QEvent *event) const; +private: + PlayState *game; + int key; }; #endif // STATES_H diff --git a/examples/animation/sub-attaq/sub-attaq.pro b/examples/animation/sub-attaq/sub-attaq.pro index 1456d0e..961a9b5 100644 --- a/examples/animation/sub-attaq/sub-attaq.pro +++ b/examples/animation/sub-attaq/sub-attaq.pro @@ -2,10 +2,10 @@ # Automatically generated by qmake (2.01a) Thu Oct 9 10:53:30 2008 # ##################################################################### TEMPLATE = app -TARGET = +TARGET = DEPENDPATH += . INCLUDEPATH += . -QT+= xml +QT += xml contains(QT_CONFIG, opengl):QT += opengl # Input @@ -21,7 +21,8 @@ HEADERS += boat.h \ boat_p.h \ submarine_p.h \ custompropertyanimation.h \ - qanimationstate.h + qanimationstate.h \ + progressitem.h SOURCES += boat.cpp \ bomb.cpp \ main.cpp \ @@ -33,6 +34,6 @@ SOURCES += boat.cpp \ animationmanager.cpp \ states.cpp \ custompropertyanimation.cpp \ - qanimationstate.cpp - + qanimationstate.cpp \ + progressitem.cpp RESOURCES += subattaq.qrc diff --git a/examples/animation/sub-attaq/submarine.cpp b/examples/animation/sub-attaq/submarine.cpp index 555617c..0f03efc 100644 --- a/examples/animation/sub-attaq/submarine.cpp +++ b/examples/animation/sub-attaq/submarine.cpp @@ -56,10 +56,10 @@ # include "qsequentialanimationgroup.h" # include "qpauseanimation.h" #else -#include <QPropertyAnimation> -#include <QStateMachine> -#include <QFinalState> -#include <QSequentialAnimationGroup> +#include <QtCore/QPropertyAnimation> +#include <QtCore/QStateMachine> +#include <QtCore/QFinalState> +#include <QtCore/QSequentialAnimationGroup> #endif static QAbstractAnimation *setupDestroyAnimation(SubMarine *sub) @@ -126,15 +126,15 @@ SubMarine::SubMarine(int type, const QString &name, int points, QGraphicsItem * QState *moving = new QState(machine->rootState()); //This state is when the boat is moving from left to right - MovementState *movement = new MovementState(this,moving); + MovementState *movement = new MovementState(this, moving); //This state is when the boat is moving from left to right - ReturnState *rotation = new ReturnState(this,moving); + ReturnState *rotation = new ReturnState(this, moving); //This is the initial state of the moving root state moving->setInitialState(movement); - movement->addTransition(this, SIGNAL(subMarineStateChanged()),moving); + movement->addTransition(this, SIGNAL(subMarineStateChanged()), moving); //This is the initial state of the machine machine->setInitialState(moving); @@ -153,7 +153,7 @@ SubMarine::SubMarine(int type, const QString &name, int points, QGraphicsItem * destroyedState->setAnimation(setupDestroyAnimation(this)); //Play a nice animation when the submarine is destroyed - moving->addTransition(this, SIGNAL(subMarineDestroyed()),destroyedState); + moving->addTransition(this, SIGNAL(subMarineDestroyed()), destroyedState); //Transition to final state when the destroyed animation is finished destroyedState->addTransition(destroyedState, SIGNAL(animationFinished()), final); diff --git a/examples/animation/sub-attaq/submarine.h b/examples/animation/sub-attaq/submarine.h index 562b4cf..7ee587d 100644 --- a/examples/animation/sub-attaq/submarine.h +++ b/examples/animation/sub-attaq/submarine.h @@ -47,8 +47,8 @@ #include "qvariantanimation.h" #include "qgraphicswidget.h" #else -#include <QVariantAnimation> -#include <QGraphicsWidget> +#include <QtCore/QVariantAnimation> +#include <QtGui/QGraphicsWidget> #endif class PixmapItem; diff --git a/examples/animation/sub-attaq/submarine_p.h b/examples/animation/sub-attaq/submarine_p.h index 354a406..c76d991 100644 --- a/examples/animation/sub-attaq/submarine_p.h +++ b/examples/animation/sub-attaq/submarine_p.h @@ -51,9 +51,9 @@ #if defined(QT_EXPERIMENTAL_SOLUTION) #include "qpropertyanimation.h" #else -#include <QPropertyAnimation> +#include <QtCore/QPropertyAnimation> #endif -#include <QGraphicsScene> +#include <QtGui/QGraphicsScene> //This state is describing when the boat is moving right class MovementState : public QAnimationState @@ -77,7 +77,7 @@ protected slots: } protected: - void onEntry() + void onEntry(QEvent *e) { if (submarine->currentDirection() == SubMarine::Left) { movementAnimation->setEndValue(QPointF(0,submarine->y())); @@ -88,7 +88,7 @@ protected: movementAnimation->setDuration((submarine->scene()->width()-submarine->size().width()-submarine->x())/submarine->currentSpeed()*12); } movementAnimation->setStartValue(submarine->pos()); - QAnimationState::onEntry(); + QAnimationState::onEntry(e); } private: @@ -109,19 +109,19 @@ public: } protected: - void onEntry() + void onEntry(QEvent *e) { returnAnimation->stop(); returnAnimation->setStartValue(submarine->yRotation()); returnAnimation->setEndValue(submarine->currentDirection() == SubMarine::Right ? 360. : 180.); returnAnimation->setDuration(500); - QAnimationState::onEntry(); + QAnimationState::onEntry(e); } - void onExit() + void onExit(QEvent *e) { submarine->currentDirection() == SubMarine::Right ? submarine->setCurrentDirection(SubMarine::Left) : submarine->setCurrentDirection(SubMarine::Right); - QAnimationState::onExit(); + QAnimationState::onExit(e); } private: diff --git a/examples/animation/sub-attaq/torpedo.cpp b/examples/animation/sub-attaq/torpedo.cpp index b24948d..88f1112 100644 --- a/examples/animation/sub-attaq/torpedo.cpp +++ b/examples/animation/sub-attaq/torpedo.cpp @@ -52,9 +52,9 @@ #include "qstatemachine.h" #include "qfinalstate.h" #else -#include <QPropertyAnimation> -#include <QStateMachine> -#include <QFinalState> +#include <QtCore/QPropertyAnimation> +#include <QtCore/QStateMachine> +#include <QtCore/QFinalState> #endif Torpedo::Torpedo(QGraphicsItem * parent, Qt::WindowFlags wFlags) diff --git a/examples/animation/sub-attaq/torpedo.h b/examples/animation/sub-attaq/torpedo.h index 33bbc04..2e44e41 100644 --- a/examples/animation/sub-attaq/torpedo.h +++ b/examples/animation/sub-attaq/torpedo.h @@ -43,13 +43,13 @@ #define __TORPEDO__H__ //Qt -#include <QObject> +#include <QtCore/QObject> #if defined(QT_EXPERIMENTAL_SOLUTION) # include "qvariantanimation.h" # include "qgraphicswidget.h" #else -# include <QVariantAnimation> +# include <QtCore/QVariantAnimation> # include <QtGui/QGraphicsWidget> #endif diff --git a/examples/statemachine/clockticking/main.cpp b/examples/statemachine/clockticking/main.cpp index 5501e2c..ea8e692 100644 --- a/examples/statemachine/clockticking/main.cpp +++ b/examples/statemachine/clockticking/main.cpp @@ -57,51 +57,43 @@ public: class ClockState : public QState { public: - ClockState(QStateMachine *machine, QState *parent) - : QState(parent), m_machine(machine) {} + ClockState(QState *parent) + : QState(parent) {} protected: - virtual void onEntry() + virtual void onEntry(QEvent *) { fprintf(stdout, "ClockState entered; posting the initial tick\n"); - m_machine->postEvent(new ClockEvent()); + machine()->postEvent(new ClockEvent()); } - -private: - QStateMachine *m_machine; }; class ClockTransition : public QAbstractTransition { public: - ClockTransition(QStateMachine *machine) - : QAbstractTransition(), m_machine(machine) { } + ClockTransition() {} protected: virtual bool eventTest(QEvent *e) const { return (e->type() == QEvent::User+2); } - virtual void onTransition() + virtual void onTransition(QEvent *) { fprintf(stdout, "ClockTransition triggered; posting another tick with a delay of 1 second\n"); - m_machine->postEvent(new ClockEvent(), 1000); + machine()->postEvent(new ClockEvent(), 1000); } - -private: - QStateMachine *m_machine; }; class ClockListener : public QAbstractTransition { public: - ClockListener() - : QAbstractTransition() {} + ClockListener() {} protected: virtual bool eventTest(QEvent *e) const { return (e->type() == QEvent::User+2); } - virtual void onTransition() + virtual void onTransition(QEvent *) { fprintf(stdout, "ClockListener heard a tick!\n"); } @@ -112,12 +104,12 @@ int main(int argc, char **argv) QCoreApplication app(argc, argv); QStateMachine machine; - QState *group = new QState(QState::ParallelGroup); + QState *group = new QState(QState::ParallelStates); group->setObjectName("group"); - ClockState *clock = new ClockState(&machine, group); + ClockState *clock = new ClockState(group); clock->setObjectName("clock"); - clock->addTransition(new ClockTransition(&machine)); + clock->addTransition(new ClockTransition()); QState *listener = new QState(group); listener->setObjectName("listener"); diff --git a/examples/statemachine/composition/main.cpp b/examples/statemachine/composition/main.cpp index 24b823c..0afff66 100644 --- a/examples/statemachine/composition/main.cpp +++ b/examples/statemachine/composition/main.cpp @@ -63,7 +63,7 @@ int main(int argc, char **argv) s1_timer->setObjectName("s1_timer"); QTimer t1; t1.setInterval(2000); - s1_timer->invokeMethodOnEntry(&t1, "start"); + QObject::connect(s1_timer, SIGNAL(entered()), &t1, SLOT(start())); QFinalState *s1_done = new QFinalState(s1); s1_done->setObjectName("s1_done"); s1_timer->addTransition(&t1, SIGNAL(timeout()), s1_done); @@ -80,17 +80,17 @@ int main(int argc, char **argv) s2_timer->setObjectName("s2_timer"); QTimer t2; t2.setInterval(2000); - s2_timer->invokeMethodOnEntry(&t2, "start"); + QObject::connect(s2_timer, SIGNAL(entered()), &t2, SLOT(start())); QFinalState *s2_done = new QFinalState(s2); s2_done->setObjectName("s2_done"); s2_timer->addTransition(&t2, SIGNAL(timeout()), s2_done); s2->setInitialState(s2_timer); - s1->addFinishedTransition(s2); + s1->addTransition(s1, SIGNAL(finished()), s2); QFinalState *s3 = new QFinalState(); s3->setObjectName("s3"); - s2->addFinishedTransition(s3); + s2->addTransition(s2, SIGNAL(finished()), s3); machine.addState(s1); machine.addState(s2); diff --git a/examples/statemachine/errorstate/errorstate.pro b/examples/statemachine/errorstate/errorstate.pro new file mode 100644 index 0000000..b93a691 --- /dev/null +++ b/examples/statemachine/errorstate/errorstate.pro @@ -0,0 +1,13 @@ +###################################################################### +# Automatically generated by qmake (2.01a) on 22. apr 14:11:33 2009 +###################################################################### + +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += C:/dev/kinetic/examples/statemachine/errorstate/. . + +# Input +HEADERS += mainwindow.h plugin.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..1a2af71 --- /dev/null +++ b/examples/statemachine/errorstate/gameitem.cpp @@ -0,0 +1,88 @@ +#include "gameitem.h" + +#include <QGraphicsScene> +#include <QDebug> + +GameItem::GameItem(QObject *parent) : QObject(parent) +{ +} + +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 (collidedLine != 0) + *collidedLine = QLineF(scene()->sceneRect().topLeft(), scene()->sceneRect().bottomLeft()); + } + + if (nextPoint.x() > sceneRect.right()) { + nextPoint.rx() = sceneRect.right(); + if (collidedLine != 0) + *collidedLine = QLineF(scene()->sceneRect().topRight(), scene()->sceneRect().bottomRight()); + } + + if (nextPoint.y() < sceneRect.top()) { + nextPoint.ry() = sceneRect.top(); + if (collidedLine != 0) + *collidedLine = QLineF(scene()->sceneRect().topLeft(), scene()->sceneRect().topRight()); + } + + if (nextPoint.y() > sceneRect.bottom()) { + nextPoint.ry() = sceneRect.bottom(); + if (collidedLine != 0) + *collidedLine = QLineF(scene()->sceneRect().bottomLeft(), scene()->sceneRect().bottomRight()); + } + + return nextPoint; +} + diff --git a/examples/statemachine/errorstate/gameitem.h b/examples/statemachine/errorstate/gameitem.h new file mode 100644 index 0000000..43b8785 --- /dev/null +++ b/examples/statemachine/errorstate/gameitem.h @@ -0,0 +1,23 @@ +#ifndef GAMEITEM_H +#define GAMEITEM_H + +#include <QGraphicsItem> + +class QLineF; +class GameItem: public QObject, public QGraphicsItem +{ + Q_OBJECT +public: + enum { Type = UserType + 1 }; + int type() const { return Type; } + + GameItem(QObject *parent = 0); + + virtual void idle(qreal elapsed) = 0; + +protected: + QPointF tryMove(const QPointF &requestedPosition, QLineF *collidedLine = 0, + QGraphicsItem **collidedItem = 0) const; +}; + +#endif diff --git a/examples/statemachine/errorstate/main.cpp b/examples/statemachine/errorstate/main.cpp new file mode 100644 index 0000000..26fc1bb --- /dev/null +++ b/examples/statemachine/errorstate/main.cpp @@ -0,0 +1,12 @@ +#include <QApplication> +#include "mainwindow.h" + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + MainWindow mainWindow; + mainWindow.show(); + + return app.exec(); +} diff --git a/examples/statemachine/errorstate/mainwindow.cpp b/examples/statemachine/errorstate/mainwindow.cpp new file mode 100644 index 0000000..39b8663 --- /dev/null +++ b/examples/statemachine/errorstate/mainwindow.cpp @@ -0,0 +1,217 @@ +#include "mainwindow.h" +#include "tankitem.h" +#include "rocketitem.h" +#include "plugin.h" + +#include <QStateMachine> +#include <QGraphicsView> +#include <QAction> +#include <QMenuBar> +#include <QState> +#include <QHistoryState> +#include <QTimer> +#include <QFileDialog> +#include <QPluginLoader> + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent), m_scene(0), m_machine(0), m_runningState(0), m_started(false) +{ + init(); +} + +MainWindow::~MainWindow() +{ +} + +void MainWindow::addWall(const QRectF &wall) +{ + QGraphicsRectItem *item = new QGraphicsRectItem; + item->setRect(wall); + item->setBrush(Qt::darkGreen); + item->setPen(QPen(Qt::black, 0)); + + m_scene->addItem(item); +} + +void MainWindow::init() +{ + setWindowTitle("Pluggable Tank Game"); + + QGraphicsView *view = new QGraphicsView(this); + view->setRenderHints(QPainter::Antialiasing); + setCentralWidget(view); + + m_scene = new QGraphicsScene(this); + view->setScene(m_scene); + + QRectF sceneRect = QRectF(-200.0, -200.0, 400.0, 400.0); + m_scene->setSceneRect(sceneRect); + + { + TankItem *item = new TankItem(this); + + item->setPos(m_scene->sceneRect().topLeft() + QPointF(15.0, 15.0)); + item->setDirection(45.0); + item->setColor(Qt::red); + + m_spawns.append(item); + } + + { + TankItem *item = new TankItem(this); + + item->setPos(m_scene->sceneRect().topRight() + QPointF(-15.0, 15.0)); + item->setDirection(135.0); + item->setColor(Qt::green); + + m_spawns.append(item); + } + + { + TankItem *item = new TankItem(this); + + item->setPos(m_scene->sceneRect().bottomRight() + QPointF(-15.0, -15.0)); + item->setDirection(225.0); + item->setColor(Qt::blue); + + m_spawns.append(item); + } + + { + TankItem *item = new TankItem(this); + + item->setPos(m_scene->sceneRect().bottomLeft() + QPointF(15.0, -15.0)); + item->setDirection(315.0); + item->setColor(Qt::yellow); + + m_spawns.append(item); + } + + QPointF centerOfMap = sceneRect.center(); + + addWall(QRectF(centerOfMap + QPointF(-50.0, -60.0), centerOfMap + QPointF(50.0, -50.0))); + addWall(QRectF(centerOfMap - QPointF(-50.0, -60.0), centerOfMap - QPointF(50.0, -50.0))); + addWall(QRectF(centerOfMap + QPointF(-50.0, -50.0), centerOfMap + QPointF(-40.0, 50.0))); + addWall(QRectF(centerOfMap - QPointF(-50.0, -50.0), centerOfMap - QPointF(-40.0, 50.0))); + + addWall(QRectF(sceneRect.topLeft() + QPointF(sceneRect.width() / 2.0 - 5.0, -10.0), + sceneRect.topLeft() + QPointF(sceneRect.width() / 2.0 + 5.0, 100.0))); + addWall(QRectF(sceneRect.bottomLeft() + QPointF(sceneRect.width() / 2.0 - 5.0, 10.0), + sceneRect.bottomLeft() + QPointF(sceneRect.width() / 2.0 + 5.0, -100.0))); + addWall(QRectF(sceneRect.topLeft() + QPointF(-10.0, sceneRect.height() / 2.0 - 5.0), + sceneRect.topLeft() + QPointF(100.0, sceneRect.height() / 2.0 + 5.0))); + addWall(QRectF(sceneRect.topRight() + QPointF(10.0, sceneRect.height() / 2.0 - 5.0), + sceneRect.topRight() + QPointF(-100.0, sceneRect.height() / 2.0 + 5.0))); + + + QAction *addTankAction = menuBar()->addAction("&Add tank"); + QAction *runGameAction = menuBar()->addAction("&Run game"); + runGameAction->setObjectName("runGameAction"); + QAction *stopGameAction = menuBar()->addAction("&Stop game"); + menuBar()->addSeparator(); + QAction *quitAction = menuBar()->addAction("&Quit"); + + connect(addTankAction, SIGNAL(triggered()), this, SLOT(addTank())); + connect(quitAction, SIGNAL(triggered()), this, SLOT(close())); + + m_machine = new QStateMachine(this); + QState *stoppedState = new QState(m_machine->rootState()); + stoppedState->setObjectName("stoppedState"); + stoppedState->assignProperty(runGameAction, "enabled", true); + stoppedState->assignProperty(stopGameAction, "enabled", false); + stoppedState->assignProperty(this, "started", false); + m_machine->setInitialState(stoppedState); + + QState *spawnsAvailable = new QState(stoppedState); + spawnsAvailable->setObjectName("spawnsAvailable"); + spawnsAvailable->assignProperty(addTankAction, "enabled", true); + + QState *noSpawnsAvailable = new QState(stoppedState); + noSpawnsAvailable->setObjectName("noSpawnsAvailable"); + noSpawnsAvailable->assignProperty(addTankAction, "enabled", false); + + spawnsAvailable->addTransition(this, SIGNAL(mapFull()), noSpawnsAvailable); + + QHistoryState *hs = new QHistoryState(stoppedState); + hs->setDefaultState(spawnsAvailable); + + stoppedState->setInitialState(hs); + + m_runningState = new QState(QState::ParallelStates, m_machine->rootState()); + m_runningState->setObjectName("runningState"); + m_runningState->assignProperty(addTankAction, "enabled", false); + m_runningState->assignProperty(runGameAction, "enabled", false); + m_runningState->assignProperty(stopGameAction, "enabled", true); + + stoppedState->addTransition(runGameAction, SIGNAL(triggered()), m_runningState); + m_runningState->addTransition(stopGameAction, SIGNAL(triggered()), stoppedState); + + QTimer *timer = new QTimer(this); + 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())); + + m_machine->start(); + m_time.start(); +} + +void MainWindow::runStep() +{ + if (!m_started) { + m_time.restart(); + 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) { + if (GameItem *gameItem = qgraphicsitem_cast<GameItem *>(item)) + 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); + } +} + +void MainWindow::addTank() +{ + Q_ASSERT(!m_spawns.isEmpty()); + + QString fileName = QFileDialog::getOpenFileName(this, "Select plugin file", "plugins/", "*.dll"); + QPluginLoader loader(fileName); + + Plugin *plugin = qobject_cast<Plugin *>(loader.instance()); + if (plugin != 0) { + TankItem *tankItem = m_spawns.takeLast(); + m_scene->addItem(tankItem); + connect(tankItem, SIGNAL(cannonFired()), this, SLOT(addRocket())); + if (m_spawns.isEmpty()) + emit mapFull(); + + QState *region = new QState(m_runningState); + QState *pluginState = plugin->create(region, tankItem); + region->setInitialState(pluginState); + + // If the plugin has an error it is disabled + QState *errorState = new QState(region); + errorState->assignProperty(tankItem, "enabled", false); + pluginState->setErrorState(errorState); + } +} + diff --git a/examples/statemachine/errorstate/mainwindow.h b/examples/statemachine/errorstate/mainwindow.h new file mode 100644 index 0000000..622dabe --- /dev/null +++ b/examples/statemachine/errorstate/mainwindow.h @@ -0,0 +1,46 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QMainWindow> +#include <QTime> + +class QGraphicsScene; +class QStateMachine; +class QState; +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: + void mapFull(); + +private: + void init(); + void addWall(const QRectF &wall); + + QGraphicsScene *m_scene; + + QStateMachine *m_machine; + QState *m_runningState; + + QList<TankItem *> m_spawns; + QTime m_time; + + bool m_started : 1; +}; + +#endif + diff --git a/examples/statemachine/errorstate/plugin.h b/examples/statemachine/errorstate/plugin.h new file mode 100644 index 0000000..2b48d43 --- /dev/null +++ b/examples/statemachine/errorstate/plugin.h @@ -0,0 +1,17 @@ +#ifndef PLUGIN_H +#define PLUGIN_H + +#include <QtPlugin> + +class QState; +class Plugin +{ +public: + virtual ~Plugin() {} + + virtual QState *create(QState *parentState, QObject *tank) = 0; +}; + +Q_DECLARE_INTERFACE(Plugin, "TankPlugin") + +#endif diff --git a/examples/statemachine/errorstate/rocketitem.cpp b/examples/statemachine/errorstate/rocketitem.cpp new file mode 100644 index 0000000..c324980 --- /dev/null +++ b/examples/statemachine/errorstate/rocketitem.cpp @@ -0,0 +1,60 @@ +#include "rocketitem.h" +#include "tankitem.h" + +#include <QPainter> +#include <QGraphicsScene> + +#include <math.h> + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +RocketItem::RocketItem(QObject *parent) + : GameItem(parent), 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::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)) { + TankItem *tankItem = qobject_cast<TankItem *>(gameItem); + if (tankItem != 0) + tankItem->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..189a1dd --- /dev/null +++ b/examples/statemachine/errorstate/rocketitem.h @@ -0,0 +1,26 @@ +#ifndef ROCKETITEM_H +#define ROCKETITEM_H + +#include "gameitem.h" + +class RocketItem: public GameItem +{ + Q_OBJECT +public: + RocketItem(QObject *parent = 0); + + virtual void idle(qreal elapsed); + qreal speed() const { return 100.0; } + void setDirection(qreal direction) { m_direction = direction; } + +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/tankitem.cpp b/examples/statemachine/errorstate/tankitem.cpp new file mode 100644 index 0000000..5506a7e --- /dev/null +++ b/examples/statemachine/errorstate/tankitem.cpp @@ -0,0 +1,262 @@ +#include "tankitem.h" + +#include <QPainter> +#include <QGraphicsScene> +#include <QDebug> + +#include <math.h> + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +class Action +{ +public: + Action(TankItem *item) : m_item(item) + { + } + + TankItem *item() const { return m_item; } + void setItem(TankItem *item) { m_item = item; } + + virtual bool apply(qreal timeDelta) = 0; + +private: + TankItem *m_item; +}; + +class MoveAction: public Action +{ +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() * (m_reverse ? -1.0 : 1.0); + + bool done = false; + if (qAbs(m_distance) < qAbs(dist)) { + done = true; + dist = m_distance; + } + m_distance -= dist; + + qreal a = item()->direction() * M_PI / 180.0; + + qreal yd = dist * sin(a); + qreal xd = dist * sin(M_PI / 2.0 - a); + + item()->setPos(item()->pos() + QPointF(xd, yd)); + return !done; + } + +private: + qreal m_distance; + bool m_reverse; +}; + +class TurnAction: public Action +{ +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() * (m_reverse ? -1.0 : 1.0); + bool done = false; + if (qAbs(m_distance) < qAbs(dist)) { + done = true; + dist = m_distance; + } + m_distance -= dist; + + item()->setDirection(item()->direction() + dist); + return !done; + } + +private: + qreal m_distance; + bool m_reverse; +}; + +TankItem::TankItem(QObject *parent) + : GameItem(parent), m_currentAction(0), m_currentDirection(0.0), m_enabled(true) +{ + connect(this, SIGNAL(cannonFired()), this, SIGNAL(actionCompleted())); +} + +void TankItem::idle(qreal elapsed) +{ + if (m_enabled) { + if (m_currentAction != 0) { + if (!m_currentAction->apply(elapsed)) { + setAction(0); + emit actionCompleted(); + } + + QGraphicsItem *item = 0; + qreal distance = distanceToObstacle(&item); + if (TankItem *tankItem = qgraphicsitem_cast<TankItem *>(item)) + emit tankSpotted(tankItem->direction(), distance); + } + } +} + +void TankItem::hitByRocket() +{ + deleteLater(); +} + +void TankItem::setAction(Action *newAction) +{ + if (m_currentAction != 0) + delete m_currentAction; + + m_currentAction = newAction; +} + +void TankItem::fireCannon() +{ + emit cannonFired(); +} + +void TankItem::moveForwards(qreal length) +{ + setAction(new MoveAction(this, length)); +} + +void TankItem::moveBackwards(qreal length) +{ + setAction(new MoveAction(this, -length)); +} + +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); +} + +QVariant TankItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) +{ + 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); + } +} + + +void TankItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +{ + QRectF brect = boundingRect(); + + painter->setBrush(m_color); + painter->setPen(Qt::black); + + // body + painter->drawRect(brect.adjusted(0.0, 4.0, -2.0, -4.0)); + + // cannon + QRectF cannonBase = brect.adjusted(10.0, 6.0, -12.0, -6.0); + painter->drawEllipse(cannonBase); + + painter->drawRect(QRectF(QPointF(cannonBase.center().x(), cannonBase.center().y() - 2.0), + QPointF(brect.right(), cannonBase.center().y() + 2.0))); + + // left track + painter->setBrush(QBrush(Qt::black, Qt::VerPattern)); + QRectF leftTrackRect = QRectF(brect.topLeft(), QPointF(brect.right() - 2.0, brect.top() + 4.0)); + painter->fillRect(leftTrackRect, Qt::darkYellow); + painter->drawRect(leftTrackRect); + + // right track + QRectF rightTrackRect = QRectF(QPointF(brect.left(), brect.bottom() - 4.0), + QPointF(brect.right() - 2.0, brect.bottom())); + painter->fillRect(rightTrackRect, Qt::darkYellow); + painter->drawRect(rightTrackRect); + + if (!m_enabled) { + painter->setPen(QPen(Qt::red, 5)); + + painter->drawEllipse(brect); + + QPainterPath path; + path.addEllipse(brect); + painter->setClipPath(path); + painter->drawLine(brect.topRight(), brect.bottomLeft()); + } +} + +QRectF TankItem::boundingRect() const +{ + return QRectF(-20.0, -10.0, 40.0, 20.0); +} + +qreal TankItem::direction() const +{ + return m_currentDirection; +} + +void TankItem::setDirection(qreal newDirection) +{ + int fullRotations = int(newDirection) / 360; + newDirection -= fullRotations * 360.0; + + qreal diff = newDirection - m_currentDirection; + m_currentDirection = newDirection; + rotate(diff); +} + +qreal TankItem::distanceToObstacle(QGraphicsItem **obstacle) const +{ + qreal dist = sqrt(pow(scene()->sceneRect().width(), 2) + pow(scene()->sceneRect().height(), 2)); + + qreal a = m_currentDirection * 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 (collidedItem != 0) { + if (obstacle != 0) + *obstacle = collidedItem; + + QPointF d = nextPosition - pos(); + return sqrt(pow(d.x(), 2) + pow(d.y(), 2)); + } else { + return 0.0; + } +} + +qreal TankItem::distanceToObstacle() const +{ + return distanceToObstacle(0); +} + + + diff --git a/examples/statemachine/errorstate/tankitem.h b/examples/statemachine/errorstate/tankitem.h new file mode 100644 index 0000000..cefed69 --- /dev/null +++ b/examples/statemachine/errorstate/tankitem.h @@ -0,0 +1,65 @@ +#ifndef TANKITEM_H +#define TANKITEM_H + +#include "gameitem.h" + +#include <QColor> + +class Action; +class TankItem: public GameItem +{ + Q_OBJECT + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) + Q_PROPERTY(qreal direction READ direction WRITE turnTo) + Q_PROPERTY(qreal distanceToObstacle READ distanceToObstacle) +public: + TankItem(QObject *parent = 0); + + void setColor(const QColor &color) { m_color = color; } + QColor color() const { return m_color; } + + void idle(qreal elapsed); + void setDirection(qreal newDirection); + + qreal speed() const { return 90.0; } + qreal angularSpeed() const { return 90.0; } + + QRectF boundingRect() const; + + void hitByRocket(); + + void setEnabled(bool b) { m_enabled = b; } + bool enabled() const { return m_enabled; } + + qreal direction() const; + qreal distanceToObstacle() const; + qreal distanceToObstacle(QGraphicsItem **item) const; + +signals: + void tankSpotted(qreal direction, qreal distance); + void collision(const QLineF &collidedLine); + void actionCompleted(); + void cannonFired(); + +public slots: + 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(); + +protected: + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value); + +private: + void setAction(Action *newAction); + + Action *m_currentAction; + qreal m_currentDirection; + QColor m_color; + bool m_enabled; +}; + +#endif diff --git a/examples/statemachine/errorstateplugins/errorstateplugins.pro b/examples/statemachine/errorstateplugins/errorstateplugins.pro new file mode 100644 index 0000000..5b6b758 --- /dev/null +++ b/examples/statemachine/errorstateplugins/errorstateplugins.pro @@ -0,0 +1,11 @@ +TEMPLATE = subdirs +SUBDIRS = random_ai \ + spin_ai_with_error \ + spin_ai \ + seek_ai + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS errorstateplugins.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins +INSTALLS += target sources diff --git a/examples/statemachine/errorstateplugins/random_ai/random_ai.pro b/examples/statemachine/errorstateplugins/random_ai/random_ai.pro new file mode 100644 index 0000000..f290250 --- /dev/null +++ b/examples/statemachine/errorstateplugins/random_ai/random_ai.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +CONFIG += plugin +INCLUDEPATH += ../.. +HEADERS = random_ai_plugin.h +SOURCES = random_ai_plugin.cpp +TARGET = $$qtLibraryTarget(random_ai) +DESTDIR = ../../errorstate/plugins + +#! [0] +# install +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/plugins +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS random_ai.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins/random_ai
\ No newline at end of file diff --git a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp b/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp new file mode 100644 index 0000000..c196247 --- /dev/null +++ b/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.cpp @@ -0,0 +1,38 @@ +#include "random_ai_plugin.h" + +#include <QState> +#include <QtPlugin> + +#include <time.h> + +QState *RandomAiPlugin::create(QState *parentState, QObject *tank) +{ + qsrand(uint(time(NULL))); + + QState *topLevel = new QState(parentState); + + QState *selectNextActionState = new SelectActionState(topLevel); + topLevel->setInitialState(selectNextActionState); + + QState *fireState = new RandomDistanceState(topLevel); + connect(fireState, SIGNAL(distanceComputed(qreal)), tank, SLOT(fireCannon())); + selectNextActionState->addTransition(selectNextActionState, SIGNAL(fireSelected()), fireState); + + QState *moveForwardsState = new RandomDistanceState(topLevel); + connect(moveForwardsState, SIGNAL(distanceComputed(qreal)), tank, SLOT(moveForwards(qreal))); + selectNextActionState->addTransition(selectNextActionState, SIGNAL(moveForwardsSelected()), moveForwardsState); + + QState *moveBackwardsState = new RandomDistanceState(topLevel); + connect(moveBackwardsState, SIGNAL(distanceComputed(qreal)), tank, SLOT(moveBackwards(qreal))); + selectNextActionState->addTransition(selectNextActionState, SIGNAL(moveBackwardsSelected()), moveBackwardsState); + + QState *turnState = new RandomDistanceState(topLevel); + connect(turnState, SIGNAL(distanceComputed(qreal)), tank, SLOT(turn(qreal))); + selectNextActionState->addTransition(selectNextActionState, SIGNAL(turnSelected()), turnState); + + topLevel->addTransition(tank, SIGNAL(actionCompleted()), selectNextActionState); + + return topLevel; +} + +Q_EXPORT_PLUGIN2(random_ai, RandomAiPlugin) diff --git a/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h b/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h new file mode 100644 index 0000000..3db464b --- /dev/null +++ b/examples/statemachine/errorstateplugins/random_ai/random_ai_plugin.h @@ -0,0 +1,62 @@ +#ifndef RANDOM_AI_PLUGIN_H +#define RANDOM_AI_PLUGIN_H + +#include <QObject> +#include <QState> + +#include <errorstate/plugin.h> + +class SelectActionState: public QState +{ + Q_OBJECT +public: + SelectActionState(QState *parent = 0) : QState(parent) + { + } + +signals: + void fireSelected(); + void moveForwardsSelected(); + void moveBackwardsSelected(); + void turnSelected(); + +protected: + void onEntry(QEvent *) + { + int rand = qrand() % 4; + switch (rand) { + case 0: emit fireSelected(); break; + case 1: emit moveForwardsSelected(); break; + case 2: emit moveBackwardsSelected(); break; + case 3: emit turnSelected(); break; + }; + } +}; + +class RandomDistanceState: public QState +{ + Q_OBJECT +public: + RandomDistanceState(QState *parent = 0) : QState(parent) + { + } + +signals: + void distanceComputed(qreal distance); + +protected: + void onEntry(QEvent *) + { + emit distanceComputed(qreal(qrand() % 180)); + } +}; + +class RandomAiPlugin: public QObject, public Plugin +{ + Q_OBJECT + Q_INTERFACES(Plugin) +public: + virtual QState *create(QState *parentState, QObject *tank); +}; + +#endif // RANDOM_AI_PLUGIN_H 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..2fb05d4 --- /dev/null +++ b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.cpp @@ -0,0 +1,48 @@ +#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); + + ChaseState *chase = new ChaseState(tank, topLevel); + chase->setObjectName("chase"); + seek->addTransition(new TankSpottedTransition(tank, chase)); + chase->addTransition(chase, SIGNAL(finished()), driveToFirstObstacle); + chase->addTransition(new TankSpottedTransition(tank, chase)); + + 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..34d203e --- /dev/null +++ b/examples/statemachine/errorstateplugins/seek_ai/seek_ai.h @@ -0,0 +1,202 @@ +#ifndef SEEK_AI_H +#define SEEK_AI_H + +#include <errorstate/plugin.h> + +#include <QState> +#include <QFinalState> +#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(QEvent *) + { + connect(m_tank, SIGNAL(actionCompleted()), this, SLOT(turnAlittle())); + turnAlittle(); + } + + void onExit(QEvent *) + { + 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))), + m_tank(tank), + m_turnTo(turnTo) + { + setTargetState(turnTo); + } + +protected: + bool eventTest(QEvent *event) const + { + bool b = QSignalTransition::eventTest(event); + if (b) { + QSignalEvent *se = static_cast<QSignalEvent *>(event); + m_lastLine = se->arguments().at(0).toLineF(); + } + return b; + } + + void onTransition(QEvent *) + { + qreal angleOfWall = m_lastLine.angle(); + + qreal newDirection; + if (qrand() % 2 == 0) + newDirection = angleOfWall; + else + newDirection = angleOfWall - 180.0; + + m_turnTo->assignProperty(m_tank, "direction", newDirection); + } + +private: + mutable QLineF m_lastLine; + QObject *m_tank; + QState *m_turnTo; +}; + +class ChaseState: public QState +{ + class GoToLocationState: public QState + { + public: + GoToLocationState(QObject *tank, QState *parentState = 0) + : QState(parentState), m_tank(tank), m_distance(0.0) + { + } + + void setDistance(qreal distance) { m_distance = distance; } + + protected: + void onEntry() + { + QMetaObject::invokeMethod(m_tank, "moveForwards", Q_ARG(qreal, m_distance)); + } + + private: + QObject *m_tank; + qreal m_distance; + }; + +public: + ChaseState(QObject *tank, QState *parentState = 0) : QState(parentState), m_tank(tank) + { + QState *fireCannon = new QState(this); + connect(fireCannon, SIGNAL(entered()), tank, SLOT(fireCannon())); + setInitialState(fireCannon); + + m_goToLocation = new GoToLocationState(this); + fireCannon->addTransition(tank, SIGNAL(actionCompleted()), m_goToLocation); + + m_turnToDirection = new QState(this); + m_goToLocation->addTransition(tank, SIGNAL(actionCompleted()), m_turnToDirection); + + QFinalState *finalState = new QFinalState(this); + m_turnToDirection->addTransition(tank, SIGNAL(actionCompleted()), finalState); + } + + void setDirection(qreal direction) + { + m_turnToDirection->assignProperty(m_tank, "direction", direction); + } + + void setDistance(qreal distance) + { + m_goToLocation->setDistance(distance); + } + +private: + QObject *m_tank; + GoToLocationState *m_goToLocation; + QState *m_turnToDirection; + +}; + +class TankSpottedTransition: public QSignalTransition +{ +public: + TankSpottedTransition(QObject *tank, ChaseState *target) : QSignalTransition(tank, SIGNAL(tankSpotted(qreal,qreal))), m_chase(target) + { + setTargetState(target); + } + +protected: + bool eventTest(QEvent *event) const + { + bool b = QSignalTransition::eventTest(event); + if (b) { + QSignalEvent *se = static_cast<QSignalEvent *>(event); + m_chase->setDirection(se->arguments().at(0).toDouble()); + m_chase->setDistance(se->arguments().at(1).toDouble()); + } + return b; + } + +private: + ChaseState *m_chase; +}; + +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 diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp new file mode 100644 index 0000000..de95f41 --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.cpp @@ -0,0 +1,29 @@ +#include "spin_ai.h" + +#include <QtPlugin> + +QState *SpinAi::create(QState *parentState, QObject *tank) +{ + QState *topLevel = new QState(parentState); + QState *spinState = new SpinState(tank, topLevel); + topLevel->setInitialState(spinState); + + // When tank is spotted, fire two times and go back to spin state + QState *fireState = new QState(topLevel); + + QState *fireOnce = new QState(fireState); + fireState->setInitialState(fireOnce); + connect(fireOnce, SIGNAL(entered()), tank, SLOT(fireCannon())); + + QState *fireTwice = new QState(fireState); + connect(fireTwice, SIGNAL(entered()), tank, SLOT(fireCannon())); + + fireOnce->addTransition(tank, SIGNAL(actionCompleted()), fireTwice); + fireTwice->addTransition(tank, SIGNAL(actionCompleted()), spinState); + + spinState->addTransition(tank, SIGNAL(tankSpotted(qreal,qreal)), fireState); + + return topLevel; +} + +Q_EXPORT_PLUGIN2(spin_ai, SpinAi) diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h new file mode 100644 index 0000000..4b4629c --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.h @@ -0,0 +1,44 @@ +#ifndef SPIN_AI_H +#define SPIN_AI_H + +#include <errorstate/plugin.h> + +#include <QObject> +#include <QState> +#include <QVariant> + +class SpinState: public QState +{ + Q_OBJECT +public: + SpinState(QObject *tank, QState *parent) : QState(parent), m_tank(tank) + { + } + +public slots: + void spin() + { + m_tank->setProperty("direction", 90.0); + } + +protected: + void onEntry(QEvent *) + { + connect(m_tank, SIGNAL(actionCompleted()), this, SLOT(spin())); + spin(); + } + +private: + QObject *m_tank; + +}; + +class SpinAi: public QObject, public Plugin +{ + Q_OBJECT + Q_INTERFACES(Plugin) +public: + virtual QState *create(QState *parentState, QObject *tank); +}; + +#endif diff --git a/examples/statemachine/errorstateplugins/spin_ai/spin_ai.pro b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.pro new file mode 100644 index 0000000..c2fd937 --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai/spin_ai.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +CONFIG += plugin +INCLUDEPATH += ../.. +HEADERS = spin_ai.h +SOURCES = spin_ai.cpp +TARGET = $$qtLibraryTarget(spin_ai) +DESTDIR = ../../errorstate/plugins + +#! [0] +# install +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/plugins +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS spin_ai.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins/spin_ai
\ No newline at end of file diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp new file mode 100644 index 0000000..5499ba3 --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.cpp @@ -0,0 +1,29 @@ +#include "spin_ai_with_error.h" + +#include <QtPlugin> + +QState *SpinAiWithError::create(QState *parentState, QObject *tank) +{ + QState *topLevel = new QState(parentState); + QState *spinState = new SpinState(tank, topLevel); + topLevel->setInitialState(spinState); + + // When tank is spotted, fire two times and go back to spin state + // (no initial state set for fireState will lead to run-time error in machine) + QState *fireState = new QState(topLevel); + + QState *fireOnce = new QState(fireState); + connect(fireOnce, SIGNAL(entered()), tank, SLOT(fireCannon())); + + QState *fireTwice = new QState(fireState); + connect(fireTwice, SIGNAL(entered()), tank, SLOT(fireCannon())); + + fireOnce->addTransition(tank, SIGNAL(actionCompleted()), fireTwice); + fireTwice->addTransition(tank, SIGNAL(actionCompleted()), spinState); + + spinState->addTransition(tank, SIGNAL(tankSpotted(qreal,qreal)), fireState); + + return topLevel; +} + +Q_EXPORT_PLUGIN2(spin_ai_with_error, SpinAiWithError) diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h new file mode 100644 index 0000000..9a96a8b --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.h @@ -0,0 +1,44 @@ +#ifndef SPIN_AI_WITH_ERROR_H +#define SPIN_AI_WITH_ERROR_H + +#include <errorstate/plugin.h> + +#include <QObject> +#include <QState> +#include <QVariant> + +class SpinState: public QState +{ + Q_OBJECT +public: + SpinState(QObject *tank, QState *parent) : QState(parent), m_tank(tank) + { + } + +public slots: + void spin() + { + m_tank->setProperty("direction", 90.0); + } + +protected: + void onEntry(QEvent *) + { + connect(m_tank, SIGNAL(actionCompleted()), this, SLOT(spin())); + spin(); + } + +private: + QObject *m_tank; + +}; + +class SpinAiWithError: public QObject, public Plugin +{ + Q_OBJECT + Q_INTERFACES(Plugin) +public: + virtual QState *create(QState *parentState, QObject *tank); +}; + +#endif diff --git a/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.pro b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.pro new file mode 100644 index 0000000..31f4c7f --- /dev/null +++ b/examples/statemachine/errorstateplugins/spin_ai_with_error/spin_ai_with_error.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +CONFIG += plugin +INCLUDEPATH += ../.. +HEADERS = spin_ai_with_error.h +SOURCES = spin_ai_with_error.cpp +TARGET = $$qtLibraryTarget(spin_ai_with_error) +DESTDIR = ../../errorstate/plugins + +#! [0] +# install +target.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstate/plugins +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS spin_ai_with_error.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/statemachine/errorstateplugins/spin_ai_with_error
\ No newline at end of file diff --git a/examples/statemachine/factorial/main.cpp b/examples/statemachine/factorial/main.cpp index 9e39ced..2b63690 100644 --- a/examples/statemachine/factorial/main.cpp +++ b/examples/statemachine/factorial/main.cpp @@ -104,7 +104,7 @@ public: return m_fact->property("x").toInt() > 1; } - virtual void onTransition() + virtual void onTransition(QEvent *) { int x = m_fact->property("x").toInt(); int fac = m_fact->property("fac").toInt(); @@ -128,7 +128,7 @@ public: return m_fact->property("x").toInt() <= 1; } - virtual void onTransition() + virtual void onTransition(QEvent *) { fprintf(stdout, "%d\n", m_fact->property("fac").toInt()); } diff --git a/examples/statemachine/helloworld/main.cpp b/examples/statemachine/helloworld/main.cpp index 13486d4..fbe34b5 100644 --- a/examples/statemachine/helloworld/main.cpp +++ b/examples/statemachine/helloworld/main.cpp @@ -52,7 +52,7 @@ public: S0(QState *parent = 0) : QState(parent) {} - virtual void onEntry() + virtual void onEntry(QEvent *) { fprintf(stdout, "Hello world!\n"); } diff --git a/examples/statemachine/pauseandresume/main.cpp b/examples/statemachine/pauseandresume/main.cpp index e0ebbff..5bacb41 100644 --- a/examples/statemachine/pauseandresume/main.cpp +++ b/examples/statemachine/pauseandresume/main.cpp @@ -73,7 +73,7 @@ public: s1->addTransition(pb, SIGNAL(clicked()), s2); s2->addTransition(pb, SIGNAL(clicked()), s1); - QHistoryState *h = process->addHistoryState(); + QHistoryState *h = new QHistoryState(process); h->setDefaultState(s1); QState *interrupted = new QState(machine->rootState()); diff --git a/examples/statemachine/pingpong/main.cpp b/examples/statemachine/pingpong/main.cpp index 00ff643..eb8fd5d 100644 --- a/examples/statemachine/pingpong/main.cpp +++ b/examples/statemachine/pingpong/main.cpp @@ -64,58 +64,47 @@ public: class Pinger : public QState { public: - Pinger(QStateMachine *machine, QState *parent) - : QState(parent), m_machine(machine) {} + Pinger(QState *parent) + : QState(parent) {} protected: - virtual void onEntry() + virtual void onEntry(QEvent *) { - m_machine->postEvent(new PingEvent()); + machine()->postEvent(new PingEvent()); fprintf(stdout, "ping?\n"); } - -private: - QStateMachine *m_machine; }; class PongTransition : public QAbstractTransition { public: - PongTransition(QStateMachine *machine) - : QAbstractTransition(), m_machine(machine) {} + PongTransition() {} protected: virtual bool eventTest(QEvent *e) const { return (e->type() == QEvent::User+3); } - virtual void onTransition() + virtual void onTransition(QEvent *) { - m_machine->postEvent(new PingEvent(), 500); + machine()->postEvent(new PingEvent(), 500); fprintf(stdout, "ping?\n"); } - -private: - QStateMachine *m_machine; }; class PingTransition : public QAbstractTransition { public: - PingTransition(QStateMachine *machine) - : QAbstractTransition(), m_machine(machine) {} + PingTransition() {} protected: virtual bool eventTest(QEvent *e) const { return (e->type() == QEvent::User+2); } - virtual void onTransition() + virtual void onTransition(QEvent *) { - m_machine->postEvent(new PongEvent(), 500); + machine()->postEvent(new PongEvent(), 500); fprintf(stdout, "pong!\n"); } - -private: - QStateMachine *m_machine; }; int main(int argc, char **argv) @@ -123,16 +112,16 @@ int main(int argc, char **argv) QCoreApplication app(argc, argv); QStateMachine machine; - QState *group = new QState(QState::ParallelGroup); + QState *group = new QState(QState::ParallelStates); group->setObjectName("group"); - Pinger *pinger = new Pinger(&machine, group); + Pinger *pinger = new Pinger(group); pinger->setObjectName("pinger"); - pinger->addTransition(new PongTransition(&machine)); + pinger->addTransition(new PongTransition()); QState *ponger = new QState(group); ponger->setObjectName("ponger"); - ponger->addTransition(new PingTransition(&machine)); + ponger->addTransition(new PingTransition()); machine.addState(group); machine.setInitialState(group); diff --git a/examples/statemachine/trafficlight/main.cpp b/examples/statemachine/trafficlight/main.cpp index 528ed00..3c47a51 100644 --- a/examples/statemachine/trafficlight/main.cpp +++ b/examples/statemachine/trafficlight/main.cpp @@ -97,9 +97,9 @@ public: timer->setInterval(duration); timer->setSingleShot(true); QState *timing = new QState(this); - timing->invokeMethodOnEntry(light, "turnOn"); - timing->invokeMethodOnEntry(timer, "start"); - timing->invokeMethodOnExit(light, "turnOff"); + QObject::connect(timing, SIGNAL(entered()), light, SLOT(turnOn())); + QObject::connect(timing, SIGNAL(entered()), timer, SLOT(start())); + QObject::connect(timing, SIGNAL(exited()), light, SLOT(turnOff())); QFinalState *done = new QFinalState(this); timing->addTransition(timer, SIGNAL(timeout()), done); setInitialState(timing); @@ -151,20 +151,21 @@ public: QVBoxLayout *vbox = new QVBoxLayout(this); TrafficLightWidget *widget = new TrafficLightWidget(); vbox->addWidget(widget); + vbox->setMargin(0); QStateMachine *machine = new QStateMachine(this); LightState *redGoingYellow = new LightState(widget->redLight(), 3000); redGoingYellow->setObjectName("redGoingYellow"); LightState *yellowGoingGreen = new LightState(widget->yellowLight(), 1000); yellowGoingGreen->setObjectName("yellowGoingGreen"); - redGoingYellow->addFinishedTransition(yellowGoingGreen); + redGoingYellow->addTransition(redGoingYellow, SIGNAL(finished()), yellowGoingGreen); LightState *greenGoingYellow = new LightState(widget->greenLight(), 3000); greenGoingYellow->setObjectName("greenGoingYellow"); - yellowGoingGreen->addFinishedTransition(greenGoingYellow); + yellowGoingGreen->addTransition(yellowGoingGreen, SIGNAL(finished()), greenGoingYellow); LightState *yellowGoingRed = new LightState(widget->yellowLight(), 1000); yellowGoingRed->setObjectName("yellowGoingRed"); - greenGoingYellow->addFinishedTransition(yellowGoingRed); - yellowGoingRed->addFinishedTransition(redGoingYellow); + greenGoingYellow->addTransition(greenGoingYellow, SIGNAL(finished()), yellowGoingRed); + yellowGoingRed->addTransition(yellowGoingRed, SIGNAL(finished()), redGoingYellow); machine->addState(redGoingYellow); machine->addState(yellowGoingGreen); @@ -182,7 +183,7 @@ int main(int argc, char **argv) QApplication app(argc, argv); TrafficLight widget; - widget.resize(120, 300); + widget.resize(110, 300); widget.show(); return app.exec(); |