I have no experience in writing a game and this week I'm trying writing a player of a music game's map (finally may become a game?) in QT; met problem and I think I need some help.
I want to show animation in 60 FPS on QOpenGLWidget. It's just some circles move in the widget, and CPU usage is low. But it looks laggy.
I enabled VSync by set the default surface format's swap behavior to doublebuffer/triplebuffer and has an interval of 1 which I think it means 60 FPS.
I implement the paintGL() method and draw the content by QPainter which QT's 2D drawing example does.
The step to compute the positions of each circle is placed outsides the paintGL method, and will run before paintGL is called.
This is the flow of the program runs:
- read the script
- start a timer
- post a event to call "tick" procedure
- "tick" procedure runs, and request update the window.
- paintGL runs, draw the frame
- before exit the paintGL method, a event to call "tick" is posted
- I think now it waits for VSync and swap buffer
- "tick" is called, go to step 4
the code:
class CgssFumenPlayer : public QOpenGLWidget
{
Q_OBJECT
...
bool Load();
public slots:
void onTick();
protected:
....
void paintGL() override;
QElapsedTimer elapsedTimer;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSurfaceFormat fmt;
fmt.setSwapBehavior(QSurfaceFormat::TripleBuffer);
fmt.setSwapInterval(1);
QSurfaceFormat::setDefaultFormat(fmt);
CgssFumenPlayer w;
w.Load();
w.setFixedSize(704, 396);
w.show();
return a.exec();
}
bool CgssFumenPlayer::Load()
{
....
elapsedTimer.start();
QMetaObject::invokeMethod(this, "onTick", Qt::QueuedConnection);
}
void CgssFumenPlayer::onTick()
{
playerContext.currentTime = elapsedTimer.elapsed() / 1000.0;
double f = playerContext.currentTime / (1.0 / 60);
playerContext.currentTime = (int)f * (1.0 / 60);
fumen->Compute(&playerContext);
update();
}
void CgssFumenPlayer::paintGL()
{
QPainter painter;
painter.begin(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setWindow(0, 0, windowWidth, windowHeight);
painter.fillRect(QRectF(0, 0, windowWidth, windowHeight), QColor().black());
DrawButtons(painter);
DrawIcons(painter, &playerContext);
painter.end();
QMetaObject::invokeMethod(this, "onTick", Qt::QueuedConnection);
}
I tried these ways to get more information:
- print current time by qDebug() each time entering the paintGL method.
It seems sometimes frame is dropped; it looks very obvious, and he interval to last time it's called is more than 30ms. - move the mouse in/out the window duration animation. It became laggy in higher possibility.
- collect the time cost in compute position, seems only a very short time.
- run this program in android, just the same or even more laggy.
- game which are much more complex runs fluently on my computer. I think the hardware is fast enough. ( i7-4800M, GTX 765M )
- restart the program again and again. it's now fluent (less or no frame-dropping happened), now laggy... I can't find the pattern.
Also, adjust the animation to 30 FPS cause it always looks laggy.
How can I deal with the problem?
(p.s. I hope it can run on android as well)
this is the full source code
https://github.com/sorayuki/CGSSPlayer/releases (cgssplayer.zip, not the source code)
(cgss-fumen.cpp makes no difference in this problem I think)
It can build in QTCreator (5.6) with no other dependency.
(for QT 5.5, it require to add
CONFIG += c++11
into the .pro file)