I'm developing a shoot'em up with qt creator and my problem is the link with the keyPressEvent function of my scene:
void Scene::keyPressEvent(QKeyEvent *event){
liste_event << event->key();
if (liste_event.contains(Qt::Key_Left)) {
vaisseau->MoveX(-1);
}
if (liste_event.contains(Qt::Key_Right)) {
vaisseau->MoveX(1);
}
}
It compiles, but my sprite (vasisseau) moves very slowly. How can I improve the code so it moves faster?
Well, the problem is that you are leaving the animation of the game to the keyPressEvent, which is not triggered as often as you would like.
To solve this problem I suggest you use the traditional approach, which involves having an function to draw() the scene (and it's objects). The idea is that this function is called every X miliseconds, and the drawing will work independently of a key being pressed or not.
So in this case, inside keyPressEvent you would just store the key that was pressed, and in Scene::draw() you will implement the logic that will call MoveX() with the appropriate parameter, based on the stored key.
Related
I am currently working on a simple CAD-like drawing program using Qt and openGL.
What I am doing is that I maintain a list of objects which is on the canvas. The paintGL() function is just loop through the list and render the objects one by one.
objects are fed to the list via slot drawObject(Object obj), in which there is an update() function to schedule an update event to update the scene.
Now, I want to do some rubberband drawing of lines:
After pick one endpoint of the line, whenever I move the cursor, a mouseMoveEvent() is triggered and it will generate an object for the line and emit a signal to drawObject(Object) slot. what the slot does is to erase the old line by doing xor drawing, and draw the new line in xor mode as well.
What I expect to happen is that every time the mouse is Moved, a new object is rendered to the scene. However, it is not. For example, if I move the mouse
fast, then before the update() function actually update the scene, multiple mouseMove events has been triggered and it seems that these events are never been handled, i.e., the correspondence objects never goes to screen. What the program actually does is that a lot of random artifacts is left on the screen after a fast rubberband dragging.
It seems that this is due to the fact that what update() function of QOpenGLWidget does is that it generate an event to inform the widget to redraw later for performance purpose.
During the course of me writing this question, I discovered the repaint() function which do an immediate update. However, the lagging is quite significant: when I move the mouse fast, the rubberband line is not following.
So, my question is, how to implement the rubberband drawing so that it could take advantage of the update() machanism to boost the performance while not having those glitches on the screen?
I have searching around on this but I could find a single article talking about this fast-moving mouse stuff.
Thank you in advance!
I'm trying to time an application to see how long it takes to load up some information, and paint a graph. My function loads up the data first, then draws the graph.
The timing is fairly simple, it calls an external function that gets msecs since some date.
The problem is even if I set t1 in the beginning and t2 right after I call the draw function, t2 will return before the QGraphicsView is actually updated. (I know, it makes sense why this should be asynchronous)
For instance when I load a large file, it will return with 700 msecs after I subtract the two values, but the actual rendering doesn't finish until a few seconds later.
I've looked all over the web and scoured the Qt documentation. I can find tons of information on updating widgets yourself, but nothing on any kind of signal or event that is fired off after rendering finishes.
Even the QGraphicsScene::changed signal appears to only be fired off when the scene changes underneath, not when rendering is done and the user can SEE the changes.
Any help on how to do this?
Does a signal or event exist for when a QGraphicsView or QWidget is done being painted or rendered?
As far as I know, it does not exist. (looked for something similar)
user can SEE the changes
As far as I know, Qt uses double buffering, so if painting is finished, it doesn't mean that user can see the changes.
Any help on how to do this?
If you want to know when painting has finished, then...
You can subclass QGraphicsScene and implement your own drawItems, drawBackground or drawForeground. This is NOT simple (because item painting algorithm is complicated), but you'll be able to tell when every item has finished painted.
You can fire/emit signals from within paintEvent (QWidget-based classes) or paint() (QGraphicsItem/QGraphicsObject-based classes). You'll need to use your own classes, obviously, and you'll have to subclass either QGraphicsView, or items you're drawing within view, or QGraphicsScene.
You could also create proxy QPainter class, and this way you'll be able to know what exactly is being paitned and when.
Having said that I suspect you're approaching your problem incorrectly.
If you're only trying to draw a graph, then there's no reason for you to know when painting is finished.
If painting is finished, it doesn't mean user can see the result.
Paint events might be called more than once.
Recommended approach:
Receive/read the data (you're drawing in your graph) from external source using threads or timer events (you'll need to read it in small chunks if you're using timer events, obviously), then update the graph from time to time, and let Qt handle repainting.
How exactly does this allow me to detect the amount of time it takes from when I choose to open a file to when all the data is loaded and the graph is drawn and is visible?
You can detect when paintEvent has finished painting by subclassing whatever widget you're using to paint Graph, overriding paintEvent and firing signal from within paintEvent, calling a subroutine or doing whatever you want.
There is no warranty that paintEvent will be called only once.
To measure how slow individual routine is and locate bottlenecks, use profilers. VerySleepy, AQTime, and so on.
Instead of measuring how long it takes to load AND display data, it will make much more sense to measure separately loading time and display time. This is a GUI application, not a game engine, so you do not control precisely when something is being drawn.
I have not testet it, but I think by subclassing QGraphicsScene and reimplementing the render method you can measure the render time.
#include <QGraphicsScene>
#include <QTime>
class MyGraphicsScene : public QGraphicsScene
{
Q_OBJECT
public:
void render ( QPainter * painter, const QRectF & target = QRectF(), const QRectF & source = QRectF(), Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio ) {
QTime t;
t.start();
QGraphicsScene::render (painter, target, source, aspectRatioMode);
qDebug("render time %d msec", t.elapsed());
}
};
I have the following code:
paintGL()
{
if(mouse_was_clicked)
{
... do the color picking with openGL to identify a clicked element
... !!! now I need to call again paintGL() to switch the selected element from the
old one to the new one but I can't create a recursive cycle!
}
else
{
... normal code to draw the scene and the selected element in red ...
}
}
As the lines suggest, I need a way to call once more the paint event.. is there any way to accomplish this without creating a potential livelock? Something like deferring a new paint event?
If the control flow within your paintGL() is that simple, just make sure that the contens currently being in the else block are executed in every case:
void MyWidget::paintGL()
{
if(mouse_was_clicked)
{
... do the color picking with openGL to identify a clicked element
}
... normal code to draw the scene and the selected element in red ...
}
It's a bit hard to tell exactly what you're doing here.
If you're trying to setup a display widget (a color picker) when paintGL detects a mouse button has been clicked, you've mixed up your events. You should make a separate action for handling a mouseclick, which sets up flags/variables and triggers a repaint. IE, move the mouse-event handling out of the repaint callback.
I could easily have misunderstood your problem here, however... if so I apologize.
As a general rule, though, if you find yourself needing a recursive repaint in QT, you're probably working against, rather than with, the system.
This happens in Qt Simulator (for phones). I'm trying to update only a portion of a widget's area, but the entire widget is updated instead.
To illustrate, the following code:
void Widget::mousePressEvent(QMouseEvent *event)
{
update(0, 0, 10, 10);
}
void Widget::paintEvent(QPaintEvent *event)
{
qDebug() << event->rect();
}
Gives the following debug output when I click on the widget:
QRect(0,0 458x832)
Which is the entire area of the widget.
What am I doing wrong here?
Edit
I ran the same code on Linux, and it worked as it should, the debug output was
QRect(0,0 10x10)
In most GUI framework I've seen you can't update just some part of the application window/widget. Even if there's some function in API to update some rectangle - like update(x,y,x,y) you're using - it's just to inform the Framework that it needs to update at least the given rectangle, and framework can update a bigger part of the screen.
I'm not sure how it works in phone Qt but it's done this way in desktop version because in most OSes GUI application doesn't store its 'image' anywhere, and if you minimize and then show your window you need to recreate entire surface.
All this means that you can't rely on the assumption, that you'll paint something and then you'll be adding other paint operations in some custom rectangle when you need. You should implement some general 'paint' function, that can redraw everything from scratch and leave the painting optimization to the framework.
I am not familiar with Qt on the phones. But maybe something else is triggering the update of the whole widget. Qt sends one paintEvent for all update() called during one event loop processing. So your code may be calling for a partial update but somewhere in the window system may somehow get touched and calls for a full update.
Try repaint() and see if that sends your paintEvent the right region.
It turned out that this bug was present only in Qt Simulator. On the actual phone itself, the update region was being passed correctly. I tested this by displaying a QMessageBox with the coordinates of event->rect.
How does one handle multiple elements of a game at once?
In a scroller which the background/tilemap moves every gameloop how is the user input handled at the same time?
The map needs to be moved in the game loop and collision needs to be checked for the player object and parts of the map which it shouldnt hit, and there also needs to be code which takes the user input, moves the player on the map and checks for collisions too?
Should these be threaded or how are these done in cocos2d?
Are there any built in methods?
Register a step method with a specified interval.
[self schedule:#selector(step:) interval:1.0/60.0];
// Main loop of the application
-(void) step:(ccTime)delta
{
// do your step actions here
}
Try and avoid registering multiple step methods. You can do everything you need in one step method. You don't need to use threading.
It is prefer to register the update method
[self scheduleUpdate];
Then override the update method as you like
-(void) update:(ccTime)delta
{
//All steps happen here
}
this will be called in every frame of your game more accurately by the cocos2d than schedule a new one.
(Cocos2dx version: this->scheduleUdate(), void update(float delta);)