Fire bullets example
-
wrote on 14 Aug 2010, 17:34 last edited by
Hello,
I just wanted to play a bit with QGraphicsScene. So I made the following simple example inspired by flash like 2D games.
"Fire bullets example on youtube":http://www.youtube.com/watch?v=8b4-mU5_tVU
[YouTubeID:8b4-mU5_tVU]
I post it hoping it can help some (And I hope, I'm in the right place...)
It creates a nice(?) flow of fire bullets, moving from the center of the scene to the cursor position.
The help:
The scene object:
- is a QGraphicsScene
- It reimplements some mouse events
- The press and release events starts and stops the fire bullets Timer.
- The method "fire" creates the "fire bullets".
- The method "advance" removes the bullets from the sceneRect before calling QGraphicsScene::advance();
Bullets are QGraphicsEllipseItem brushed with a radial gradient
The game engine(!) is a QTimer in main.cpp. It asks the scene to advance every 0.01s
Main.cpp
@
#include <QtCore>
#include <QtGui>
#include "scene.h"int main(int argc, char **argv)
{
QApplication app(argc, argv);Scene scene; scene.setSceneRect(0.0, 0.0, 400.0, 400.0); scene.setBackgroundBrush(Qt::black); QTimer *timer = new QTimer(); QObject::connect(timer, SIGNAL(timeout()), &scene, SLOT(advance())); timer->start(10); QGraphicsView window(&scene); window.show(); return app.exec();
}@
scene.h
@#ifndef SCENE_H
#define SCENE_H#include <QGraphicsScene>
class Scene : public QGraphicsScene
{
Q_OBJECT
public:
Scene();
virtual void mousePressEvent ( QGraphicsSceneMouseEvent * mouseEvent );
virtual void mouseMoveEvent ( QGraphicsSceneMouseEvent * mouseEvent );
virtual void mouseReleaseEvent ( QGraphicsSceneMouseEvent * mouseEvent );
public slots:
void fire();
void advance();
private:
QTimer * m_FireTimer;
QPointF m_FireTarget;
};
#endif // SCENE_H@scene.cpp
@#include "scene.h"
#include <QGraphicsEllipseItem>
#include <QGraphicsSceneMouseEvent>
#include <QTimer>
#include <math.h>class GraphicsCircle : public QGraphicsEllipseItem
// class for the fire bullets
{
public:
GraphicsCircle(qreal dirx, qreal diry)
: m_Speed(5.0)
, m_DirX(dirx)
, m_DirY(diry)
{
setRect(-20.0,-20.0,40.0,40.0);
setPos(200,200);
QRadialGradient rGrad( 0.0, 0.0, 20.0, 0.0, 0.0);
rGrad.setColorAt(0.0, QColor(255,255,255));
rGrad.setColorAt(0.7, QColor(200,100,20));
rGrad.setColorAt(1.0, QColor(255,0,0,0));
setBrush(QBrush(rGrad) );
setPen(QPen(Qt::NoPen));
}virtual ~GraphicsCircle() {} void advance(int phase) { setPos(x()+m_Speed*m_DirX, y()+m_Speed*m_DirY); }
private:
QBrush m_Brush;
qreal m_Speed;
qreal m_DirX;
qreal m_DirY;
};Scene::Scene() : QGraphicsScene()
{
// the fire timer has the responsability to create bullets
// it will be started when needed : when mouse is pressed
m_FireTimer= new QTimer();
QObject::connect(m_FireTimer, SIGNAL(timeout()), this, SLOT(fire()));
}void Scene::mousePressEvent ( QGraphicsSceneMouseEvent * mouseEvent )
{
m_FireTarget = mouseEvent->scenePos();
m_FireTimer->start(10);
QGraphicsScene::mousePressEvent(mouseEvent);
}void Scene::mouseMoveEvent ( QGraphicsSceneMouseEvent * mouseEvent )
{
m_FireTarget = mouseEvent->scenePos();
QGraphicsScene::mouseMoveEvent(mouseEvent);
}void Scene::mouseReleaseEvent ( QGraphicsSceneMouseEvent * mouseEvent )
{
m_FireTimer->stop();
QGraphicsScene::mouseReleaseEvent(mouseEvent);
}void Scene::fire()
// creates a fire bullet
// the bullet will move in the direction of the mouse cursor
// the trajectory is sligthly perturbated by a random small angle
{
qreal dirx = m_FireTarget.x()-200.0;
qreal diry = m_FireTarget.y()-200.0;qreal length = sqrt(dirx*dirx+diry*diry); if (length!=0) { // normalized direction vector qreal invLength= 1.0/length; dirx *= invLength; diry *= invLength; // creating an angle perturbation of +/- 3° qreal alphaPerturbation = static_cast<qreal>(qrand()%6-3) * M_PI / 180.0; qreal xPerturbation = cos(alphaPerturbation); qreal yPerturbation = sin(alphaPerturbation); // cos(a+b)=... dirx = dirx*xPerturbation - diry*yPerturbation; // sin(a+b)=... diry = diry*xPerturbation + dirx*yPerturbation; GraphicsCircle * circle = new GraphicsCircle(dirx, diry); addItem(circle); }
}
void Scene::advance()
{
// we first remove the circle out of the sceneRect
for (int i=0; i<items().count(); ++i)
{
QGraphicsItem * item = items().at(i);
qreal x= item->x();
qreal y= item->y();
qreal sx=sceneRect().width();
qreal sy= sceneRect().height();
if ( (x < 0.0) || (y < 0.0) || (x > sx) || (y > sy))
{
removeItem(item);
delete item;
}
}
QGraphicsScene::advance();
}
@ -
wrote on 15 Aug 2010, 15:58 last edited by
Nice! Thank you for posting this.
-
wrote on 17 Aug 2010, 14:23 last edited by
yeah! good for me.
-
wrote on 18 Aug 2010, 06:40 last edited by
too good !
-
wrote on 25 Aug 2010, 14:02 last edited by
Thank you for this post.
-
wrote on 4 Dec 2010, 15:07 last edited by
I can see this being used in one of those 2D tower games.
I'm just wondering: shouldn't the timer be (less than?) 1/refresh rate rather than just 0.01s. To save unnecessary calculations and possibly remove tearing.
-
wrote on 4 Dec 2010, 15:15 last edited by
[quote author="xsacha" date="1291475228"]I can see this being used in one of those 2D tower games.
I'm just wondering: shouldn't the timer be (less than?) 1/refresh rate rather than just 0.01s. To save unnecessary calculations and possibly remove tearing.[/quote]
Which is the game you are referring to? Is the code available.
-
wrote on 4 Dec 2010, 15:24 last edited by
Oh it's a classic game, repeated everywhere. I'm talking about Tower Defence.
Here's an opensource Qt version: http://gitorious.org/open-tower-defence
-
wrote on 4 Dec 2010, 15:39 last edited by
[quote author="xsacha" date="1291476247"]Oh it's a classic game, repeated everywhere. I'm talking about Tower Defence.
Here's an opensource Qt version: http://gitorious.org/open-tower-defence[/quote]
Thank you for the link. I was not aware of this.
-
wrote on 4 Dec 2010, 16:33 last edited by
[quote author="xsacha" date="1291475228"]I'm just wondering: shouldn't the timer be (less than?) 1/refresh rate rather than just 0.01s. To save unnecessary calculations and possibly remove tearing.[/quote]
Yes, you are right.
How do you retrieve the refresh rate with Qt ? -
wrote on 4 Dec 2010, 16:53 last edited by
Avoiding tearing in Qt by sticking with the screens refresh rate is discussed by Gunnar "here":http://labs.qt.nokia.com/2010/12/02/velvet-and-the-qml-scene-graph/
-
wrote on 4 Dec 2010, 17:25 last edited by
I read that post when it came out but it doesn't really explain the code behind it. I guess it's in the repository, but that's a fair bit of reading.
That blog was more about 'what not to do' really.I would be interested in finding out how to discover refresh rate in Qt. Is there something in Qt for system information?
Obviously using 16.66ms wasn't working in that QML Scene Graph example ;).
-
wrote on 25 Jan 2011, 15:42 last edited by
I tested your code... and that's really good!
-
wrote on 29 Jan 2011, 12:08 last edited by
Tried too, very cool!
-
wrote on 25 Jun 2011, 11:16 last edited by
i tried to, thanks for sharing
-
wrote on 30 Aug 2011, 13:32 last edited by
Great Initiative! Thanks
-
wrote on 30 Aug 2011, 17:29 last edited by
Cool one.. Liked it :)