0
\$\begingroup\$

My renderBoard is slow and it's because of font.draw function. I read that I should use stringBuilder instead of string, but it didn't help at all. I suppose I'm using it wrong. Could you guide me to the right way?

public void renderBoard(SpriteBatch sb, BitmapFont font) {
    int L = 0;
    String string;
    ...
    // "size" is a private variable of the class, the same goes for "stringBuilder"
    for(int k = - size + 1; k <= size - 1; k++) {
        for (int j = 1; j <= size - Math.abs(k); j++) {
            string = L + "";
            for(int g = 0; g < string.length(); g++) {
                stringBuilder.setCharAt(g, string.charAt(g));
            }
            sb.draw(
                    this.getTexturesArray().get(L),
                    x_j_k_position,
                    y_j_k_position
            );
            font.setColor(Color.WHITE);
            font.draw(
                    sb,
                    stringBuilder,
                    x_j_k_position,
                    y_j_k_position
            );
            L++;
        }
    }
}

If I comment out the font.draw line, the game accelerates, so I guess here lies the problem.

\$\endgroup\$
2
  • \$\begingroup\$ How many times is the loop body called? Drawing a lot of text can be slow. I suggest you look how the Label actor in scene2d does it, I think it caches the font glyph or something. If that's still to slow and the text doesn't change often, you could consider drawing the text to a FrameBuffer first then drawing the buffer to the batch. \$\endgroup\$
    – Nicolas
    Jul 5 '19 at 17:04
  • \$\begingroup\$ Thank you for your response. I can't really find the code of how Label in scene2d does it. When it comes to FrameBuffer, unfortunately I can't find any info of how should I use it. \$\endgroup\$
    – musialmi
    Jul 7 '19 at 11:23
0
\$\begingroup\$

I assume your font uses a different texture/image than your sprites. If it does, the slowdown may be caused by texture binding.

In your loop, you are drawing a sprite using texture A (sb.draw() call) and immediately after you draw text using texture B (font.draw() call). These calls alternate many times, causing OpenGL to switch texture (which is an expensive operation) many times in a single render() call.

To solve this, you could use two loops:

for(int k = - size + 1; k <= size - 1; k++) {
    for (int j = 1; j <= size - Math.abs(k); j++) {
        //draw the sprite - sb.draw(...)
    }
}
for(int k = - size + 1; k <= size - 1; k++) {
    for (int j = 1; j <= size - Math.abs(k); j++) {
        //draw the text - font.draw(...)
    }
}

Note: The code above may not be optimal and it's here just to give you an idea what I mean. Nevertheless, if your problem is caused by texture binding, it should speed up the game significantly.


Another reason why your code may not be performing well is because you use StringBuilder incorrectly.

string = L + "";

gets compiled into

string = new StringBuilder().append(L).append("").toString();

... and creates a new StringBuilder object each time - more work for garbage collector.

Since variable L is a number, you don't need StringBuilder at all (nor you need string concatenation) and you can use String.valueOf() method to get the String value of the number.

string = String.valueOf(L);
//you don't need the StringBuilder loop
\$\endgroup\$
5
  • \$\begingroup\$ You are right, it accelerates the game. Not to the level I would expect, but anyway I learnt something from you ;) Thank you. \$\endgroup\$
    – musialmi
    Jul 7 '19 at 11:25
  • \$\begingroup\$ In fact, I used regular String instead of StringBuilder before I even posted the question here. In my feeling, the change from String to StringBuilder or from StringBuilder to String doesn't influence the speed. On the other hand, your loop decomposition changed definitely more. I'll mark your answer as best if there are no better answers :P For now I'm hoping for something that will just delete the problem. \$\endgroup\$
    – musialmi
    Jul 7 '19 at 12:47
  • \$\begingroup\$ @musialmi The issue is that, you are concatenating strings which creates a new StringBuilder object internally each time this line is executed string = L + "";. Therefore, garbage collector takes more CPU time to get rid of those temporary objects. \$\endgroup\$
    – Genhis
    Jul 7 '19 at 12:52
  • \$\begingroup\$ Look that if I comment out font.draw(...), there are no slow-downs. And yet strings/ stringbuilders are being produced. What is more, it doesn't matter if I use string or strinbuilder. It's not the production which is slowing the game down, it's the rendering it, right? \$\endgroup\$
    – musialmi
    Jul 7 '19 at 14:42
  • 1
    \$\begingroup\$ @musialmi If you have a lot of text which is the same (doesn't change during gameplay), you can use BitmapFontCache. The idea behind it is that, you only add text once, and then draw all the text in your render() method at once. \$\endgroup\$
    – Genhis
    Jul 7 '19 at 15:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .