Help in my 2d Qt game
-
Hi all,
I'm having fun building a 2D game, but I'm hitting performance issue before that I even started :)
My idea is basically to have a ground scenario as composition of tiles (set in a matrix).
Then drawing the tiles to screen in the update loop as follows:- delete everything
- iterate on the matrix
- display the tile if it fits in the screen coordinate
The problem I'm having is that my tiles are 45x15, and a full screen resolution is 1200x1000 which means:
- (1200x1000) / (45x15) = 1777 tiles
Drawing the 1777 tiles in a for loop takes between 15 and 20 msec, far too much for a 60 FPS.
I'm simply drawing tiles into a QOpenGLWidget with the painter using the following code:painter->drawRect(target, *image);
(I get exactly the same result when I use instead drawImage or drawPixmap, which is eventually what I want to have).
Is there anyway I can speed up the drawRect (or any other draw functionality) to screen?
Am I doing something completely wrong? Is not how I am supposed to draw the ground?I had the following two ideas but I think they are out of track:
-
I wrote some code to aggregate ground images in bigger tiles (e.g. aggregate 10 tiles in a 450x150 image). That drastically improved performances, but then it would not work in future as I'm planning to have only the tiles around the character visible and the further away black/grayed out (imagine age of empires).
-
I thought as well to have a not blank the screen and draw only the tiles that requires update but I will incur in two problems:
** when I scroll the screen I need to repaint everything anyway.
** if I have few units walking in the screen it is probably going to repaint everything anyway.
What is the best way to approach my problem?
Thanks in advance
Antonio -
For the time being I did a composition of both option described above.
As I got only one unit I'll deal with this problem later on.Scrolling is fast and paint loop is fast.
I have few problems when the unit moves, I need to clean up the grounds "around" it as they don't repaint and if the unit was overflowing on that ground some "bits" stay on it.
It looks cool, although not sure if it is the best solution.
-
Just if somebody is wondering I tried to use qGraphicsView/qGraphicsScene/qGraphicsItem and the performance are even much much worse.
I guess I must be doing something very wrong.
I thought to make a game it would be possible at each frame (60fps) to clear the screen (make it all black) and then draw all my images (it didn't matter if they were 10000 images) but evidently not.Maybe opengl / transformer / shaders is the only way to go :(
I'll let you know what I discover.
-
Hi all,
I'm having fun building a 2D game, but I'm hitting performance issue before that I even started :)
My idea is basically to have a ground scenario as composition of tiles (set in a matrix).
Then drawing the tiles to screen in the update loop as follows:- delete everything
- iterate on the matrix
- display the tile if it fits in the screen coordinate
The problem I'm having is that my tiles are 45x15, and a full screen resolution is 1200x1000 which means:
- (1200x1000) / (45x15) = 1777 tiles
Drawing the 1777 tiles in a for loop takes between 15 and 20 msec, far too much for a 60 FPS.
I'm simply drawing tiles into a QOpenGLWidget with the painter using the following code:painter->drawRect(target, *image);
(I get exactly the same result when I use instead drawImage or drawPixmap, which is eventually what I want to have).
Is there anyway I can speed up the drawRect (or any other draw functionality) to screen?
Am I doing something completely wrong? Is not how I am supposed to draw the ground?I had the following two ideas but I think they are out of track:
-
I wrote some code to aggregate ground images in bigger tiles (e.g. aggregate 10 tiles in a 450x150 image). That drastically improved performances, but then it would not work in future as I'm planning to have only the tiles around the character visible and the further away black/grayed out (imagine age of empires).
-
I thought as well to have a not blank the screen and draw only the tiles that requires update but I will incur in two problems:
** when I scroll the screen I need to repaint everything anyway.
** if I have few units walking in the screen it is probably going to repaint everything anyway.
What is the best way to approach my problem?
Thanks in advance
AntonioHi @antonio_1985,
The for-loop only draws one tile at a time, which is slow. To achieve a high frame rate, you need to let your program paint different parts of the screen in parallel.
You don't need to micro-manage the screen clearing and repainting -- QGraphicsView can do that for you.
@antonio_1985 said in Help in my 2d Qt game:
Just if somebody is wondering I tried to use qGraphicsView/qGraphicsScene/qGraphicsItem and the performance are even much much worse.
I recommend you build, run, and study the "40000 Chips" example. (Search Qt Creator for the examples)
The key points are:
- Make each ground tile an individual
QGraphicsPixmapItem
. (It might help to aggregate the tiles to bigger images) - Make your character sprite another QGraphicsPixmapItem.
- Add all the ground tiles to your
QGraphicsScene
. You only need to do this once at startup, and you don't need to destroy them until your program quits. - For the Age of Empires-style fog-of-war, call
QGraphicsView::setBackgroundBrush()
once to make your background black. During the game, callsetOpacity()
to make the tiles around your character fully opaque, and make all the other tiles fully transparent. The transparent tiles will show the black background instead of the image. - To scroll, move your character sprite and call
QGraphicsView::centerOn()
to move the viewport.