Tile map bad performance

Started by
6 comments, last by a light breeze 5 years, 8 months ago

I'm developing a 2D tile based game in JavaFx in college, I already have the sprites, animations, audio, menu ..., but I found a huge problem in rendering the map. On a 4GB notebook, Intel graphics card, Core i5, where any 2D Steam game works well at 60 FPS, my game runs from 27 to 31 FPS. I noticed that the precarious part is rendering the map, but I do not know why it's so slow. Here is the map rendering code:


// Clear Layers
    this.getLayer1GC().clearRect(0, 0, this.getLayer1GC().getCanvas().getWidth(),
                this.getLayer1GC().getCanvas().getHeight());

    this.getLayer2GC().clearRect(0, 0, this.getLayer2GC().getCanvas().getWidth(),
                this.getLayer2GC().getCanvas().getHeight());

    int index = 0;

    int tileSize = 64 * Engine.SCALE; // 128x128

    int startCol = Math.max(0, (int) (Engine.camera.xView / tileSize));

    int endCol = Math.min(this.width,
            (int) ((Engine.camera.xView + Engine.camera.wView) / tileSize) + 1);

    int startRow = Math.max(0, (int) (Engine.camera.yView / tileSize));

    int endRow = Math.min(this.height,
            (int) ((Engine.camera.yView + Engine.camera.hView) / tileSize) + 1);

    int tileX, tileY, indexLayer1, indexLayer2;

    for (int c = startCol; c < endCol; c++) {

        for (int r = startRow; r < endRow; r++) {

            // Tile Index
            index = this.tileManager.getTileIndex(c, r, this.width);

            // Tile Coordinates
            tileX = (int) (c * tileSize - Engine.camera.xView);
            tileY = (int) (r * tileSize - Engine.camera.yView);

            // Cache Tileset Images
            indexLayer1 = this.layer1.tileArray[index];
            indexLayer2 = this.layer2.tileArray[index];

            // Layer 1
            if (indexLayer1 > 0) {
                this.getLayer1GC().drawImage(this.mapTilset.tileImages[indexLayer1], 0, 0,
                        tileSize, tileSize, tileX, tileY, tileSize, tileSize);
            }

            // Layer 2
            if (indexLayer2 > 0) {
                this.getLayer2GC().drawImage(this.mapTilset.tileImages[indexLayer2], 0, 0,
                        tileSize, tileSize, tileX, tileY, tileSize, tileSize);
            }

        }
    }

 

Advertisement

I'm not familiar with JavaFX, but I think the first question would be, can you profile the app? It seems like that could be a good first step in analyzing the problem.

You could also do some ad hoc analysis. For example, comment out just the draw calls to make sure it's specifically drawing that's causing the problem. If possible, cache the return values of getLayer*GC() instead of calling those functions repeatedly, just in case they do some non-trivial work. Try a smaller window to see if performance scales with the number of pixels drawn. And so forth. With these kinds of simple experiments you may be able to narrow things down a bit.

so all of that's in your core graphics loop?
keeping in mind that I'm not a Java programmer, avoid instantiating variables inside the loop. make the variable outside loop and then just play w/it from there.
Don't make a call to canvas asking for its height in the loop. Make that a fixed variable set pre-loop. It's expensive to query canvas for its height.
Things like that might not help a bunch, but should squeeze a little more fps out.

If you're worried about people changing their screen size mid-game... well, most people don't, but just to make sure you can have a seperate loop that fires every.... .5 seconds? that will update canvas height/width variables. Much less taxing on system than doing that every 17 milliseconds.

Riding off of SkyPenguin's answer, you could also use a boolean to check if the canvas has changed. In fact, you will see than kind of code in more advanced engines as well that use OpenGL or DirectX. Those graphics libraries have functions that incur large losses of FPS, and need to be checked by a boolean first to make sure a call isn't wasted.

View my game dev blog here!

The best answer is to get a profiler. That's the tool for this job.

Far too many times people guess at what might be causing performance issues, and they guess wrong.

At a glance I'm concerned about the number of drawImage calls. Details matter -- which is why you need the profiler -- but individual draw calls often have significant overhead. One of the most common performance demands is to move all graphics items over to the video card and to limit the number of draw calls.  That guess is quite likely wrong, or at least not your only major bottleneck.

Well he is using a GUI framework, which may not be optimized for drawing that many tile images each frame. You might want to do a search on documentation how these draw calls are implemented in JavaFX.

You are calling four functions in your inner loop:

  • getTileIndex

  • getLayer1GC

  • getLayer2GC

  • drawImage

Assuming that your slowdown isn't outside of the code you posted, the slowdown is almost certainly in one of these functions.  drawImage seems like the most likely culprit, but do check the others.

This topic is closed to new replies.

Advertisement