Search code examples
androidlibgdxscene2d

Drawing many actors takes long time in scene2d


I have a problem with drawing many actors as it takes long time when testing with desktop project and not working on my android device.

I have a play button that when clicked should show 100 level for player to choose from.

Here is my code:

stage = new Stage(new ScalingViewport(Scaling.fill, 800, 1280));
Gdx.input.setInputProcessor(stage);
skin = new Skin(Gdx.files.internal("data/uiskin.json"));
Image play = new Image(new Texture(Gdx.files.internal("play.png")));
stage.addActor(play);
play.addListener(new ClickListener() {
    @Override
    public void clicked(InputEvent event, float x, float y) {
        Table container = new Table();
        stage.addActor(container);
        container.setFillParent(true);
        Table table = new Table();
        Puzzle[] puzzles = new Puzzle[100];
        for (int i=0; i<puzzles.length; i++) {
            table.padTop(60);
            table.padBottom(60);
            puzzles[i] = new Puzzle(i, false);
            if (i%6 == 0) table.row();
            table.add(puzzles[i]).pad(5);
        }
        ScrollPane scroll = new ScrollPane(table, skin);
        container.add(scroll).expand().fill().colspan(4);
    }
});

Here is puzzle class which simply shows a rectangle with puzzle number and if it is solved its color should be blue and if not color should be white.

private class Puzzle extends Actor {
        TextureRegion rect;
        BitmapFont font;
        float w,h;
        boolean solved;
        int drawNum;
        public Puzzle(int number, boolean solved) {
            rect = new TextureRegion(new Texture(Gdx.files.internal("rect.png")));
            setSize(rect.getRegionWidth(), rect.getRegionHeight());
            this.drawNum = number + 1;
            this.solved = solved;
            if (solved) font = HelpingMethods.createFont(38, Color.GOLD);
            else font = HelpingMethods.createFont(38, Color.DARK_GRAY);
            GlyphLayout layout = new GlyphLayout();
            layout.setText(font, "" + this.drawNum);
            w = layout.width;
            h = layout.height;
        }

        @Override
        public void draw(Batch batch, float parentAlpha) {
            Color color = getColor();
            if (!solved) batch.setColor(1, 1, 1, color.a * parentAlpha);
            else batch.setColor(0, 0, 1, color.a * parentAlpha);
            font.setColor(color.r, color.g, color.b, color.a * parentAlpha);
            batch.draw(rect, getX(), getY());
            font.draw(batch, "" + drawNum, getX() + getWidth()/2 - w/2,
                    getY() + h + getHeight()/2 - h/2);
        }
    }

Here is createFont() method:

public static BitmapFont createFont(int size, Color color) {
        FreeTypeFontGenerator generator = new FreeTypeFontGenerator
                (Gdx.files.internal("fonts/font.ttf"));
        FreeTypeFontGenerator.FreeTypeFontParameter parameter =
                new FreeTypeFontGenerator.FreeTypeFontParameter();

        parameter.size = size;
        parameter.color = color;
        parameter.minFilter = Texture.TextureFilter.Linear;
        parameter.magFilter = Texture.TextureFilter.Linear;
        BitmapFont font = generator.generateFont(parameter);
        return font;
    }

enter image description here

Any Solutions ?


Solution

  • The problem is, that whenever the play is clicked, you create new 100 Puzzle objects. In Puzzle constructor you generate BitmapFont with FreeTypeFontGenerator, which is expensive operation. And you do that 100 times. Instead, you should generate your BitmapFont object once (for example, when you initialize your game), and pass a reference to it to every Puzzle object. Also reuse Talbe container and GlyphLayout objects.

    In game development in general you should avoid creating new objects, when possible, and reuse them instead. And the reason is not only it can be slow, but also, as in your case, when you create new Puzzle objects instead of old ones, you create a lot of work for a garbage collector, which can cause stutters.

    Don't forget to dispose the BitmapFont object, when it's not needed anymore.