To explore Qt's State machine framework I thought to use it with sprite animation, as a complex sprite also holds many state and maintaining sprite state and transition from one state to another can become pain if not done properly.
So following is my sample code for prince sprite which use QStateMachine to maintain sprite's state and transition from one state to another. From somewhere in Internet I found sprite sheet for Prince of Persia, to make it easy for sample code I created another simple version of original sprite sheet.
PrinceSprite::PrinceSprite(QGraphicsItem * parent) :QGraphicsObject(parent) { mSpriteImage = new QPixmap(":/prince.png"); changeDir(this); //creating different state object , //which are derived from QState and l //istening to timer's timeout signal //and also modify frame according to animation StandingState* standing = new StandingState(this); RunningState* running = new RunningState(this); PrepareForAttack* prepareForAttack = new PrepareForAttack(this); Attack* attack = new Attack(this); InAttackMode* inAttackMode = new InAttackMode(this); //adding transition to state //goto running state from stating state at left click standing->addTransition(this,SIGNAL(leftClick()),running); running->addTransition(this,SIGNAL(leftClick()),standing); standing->addTransition(this,SIGNAL(rightClick()) ,prepareForAttack); prepareForAttack->addTransition(prepareForAttack, SIGNAL(exited()),inAttackMode); inAttackMode->addTransition(this,SIGNAL(leftClick()),attack); attack->addTransition(attack,SIGNAL(exited()),inAttackMode); inAttackMode->addTransition(this, SIGNAL(rightClick()),standing); //adding all state to QStateMachine _stateMachine.addState(standing); _stateMachine.addState(running); _stateMachine.addState(prepareForAttack); _stateMachine.addState(attack); _stateMachine.addState(inAttackMode); //setting initial state and then starting state machine _stateMachine.setInitialState( standing); _stateMachine.start(); }
In above code I have create different state object for different sprite state, like for StandingState or Attack state.
This state classes are derived from QState class and listen to QTimer's timeout signal to change frame according to animation.
For example following code for Attack state.
#include <QState> class Attack : public QState { Q_OBJECT public: Attack(PrinceSprite* prince); void onEntry ( QEvent * event ); void onExit ( QEvent * event ); signals: void exited(); private slots: void nextFrame(); }; #include "attack.h" Attack::Attack(PrinceSprite* prince) :QState() {} void Attack::nextFrame() { _prince->_x += 1; _prince->setX(_prince->x() + 7); if (_prince->_x >= 4 ) { emit exited(); } } void Attack::onEntry ( QEvent * event ) { QObject::connect(_prince,SIGNAL(tick()), this,SLOT(nextFrame())); _prince->_x = 0; _prince->_y = 2; } void Attack::onExit ( QEvent * event ) { QObject::disconnect(_prince,SIGNAL(tick()), this,SLOT(nextFrame())); }
So finally, I am not sure if this is correct approach to implement sprite or not, but using Qt's State machine framework is helping a lot to make it simpler.
Follwing is demo of my implementation.
Is there a repo where we can download the code for this?
ReplyDelete