How to use SpriteBatch and ShapeRenderer on the same screen?

I am using SpriteBatch to paint textures and ShapeRenderer to paint some shape.

Here is my code in the actor

@Override
public void draw(Batch batch, float parentAlpha) {
    batch.end();
    Gdx.gl.glEnable(GL20.GL_ARRAY_BUFFER_BINDING);
    Gdx.gl.glEnable(GL20.GL_BLEND);
    Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
    shapeRenderer.begin(ShapeType.Filled);

    //change color

    shapeRenderer.setColor(color);

    shapeRenderer.rect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);

    shapeRenderer.end();
    Gdx.gl.glDisable(GL20.GL_BLEND);
    batch.begin();
}

      

and call stage.draw () on screen

@Override
public void render(float delta) {
    Gdx.gl20.glClearColor(0, 0, 0, 0);
    Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
    Gdx.gl20.glEnable(GL20.GL_TEXTURE_2D);
    stage.act(delta);
    stage.draw();
    //......
}

      

Works, but throws an exception unpredictably:

STACK_TRACE=java.lang.IllegalStateException: SpriteBatch.end must be called before begin.
at com.badlogic.gdx.graphics.g2d.SpriteBatch.begin(SpriteBatch.java:164)
at com.badlogic.gdx.scenes.scene2d.Stage.draw(Stage.java:127)
at c.i.a.a(AbstractCardRoomRenderer.java:3078)
at c.i.s.a(TLMNCardRoomRenderer.java:1158)
at c.j.e.render(GameScreen.java:22)
at com.badlogic.gdx.Game.render(Game.java:46)
at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(AndroidGraphics.java:422)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1522)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1239)

      

EDIT: For more details on what I am doing:

I want to draw a shape. Because the stage part is being drawn, so I have to finish it to draw the figure. My code still works, but at one time, another actor, I think, used a batch of the scene to paint something else. This forces the scene to begin its part. So this is a conflict between the beginning and the end.

For example, the method for drawing an actor:

batch.end();
//drawing shapes

         batch.begin() (somewhere else) <--- I think this code is call when stage call draw on other actor

 //drawing completed
 batch.begin() 

      

EDIT: If others' answer doesn't work for you, please consider my workaround, which I post as an answer below.

+3


source to share


4 answers


@Override
public void draw(Batch batch, float parentAlpha) {
    batch.end();   <-- 
    Gdx.gl.glEnable(GL20.GL_ARRAY_BUFFER_BINDING);
    ../// other code


    shapeRenderer.end();
    Gdx.gl.glDisable(GL20.GL_BLEND);
    batch.begin(); <--

      

I think the error in you is causing, batch.end ()

before bacth.begin ();

try to change the order



on the other hand, if the draw. This is the scene class, you call it the arguments you need,public void draw (Batch batch, float parentAlpha)

+8


source


If you don't close all Renderers before opening a new one, you will get a view without previous

spriteBatch.begin()
... // render Textures
shapeRenderer.begin()
... // render Shapes
shapeRenderer.close()
spriteBatch.close()

      

this will lead to the screen without your spriteBatch-Textures --- you already solved this problem by applying your code to this

    @Override
    public void draw(Batch batch, float parentAlpha) {
        batch.end(); // close A
        ...
        shapeRenderer.begin(ShapeType.Filled); // open B
        ...
        shapeRenderer.end(); // close B
        batch.begin(); // open A
 }

      

But in the very first batch.end () file, your code cannot find an open spriteBatch that can be closed, so you get an IllegalStateException



You need to call

batch.begin () once before using the end () method (but keep in mind that you don't have to start the batch every frame)

The simplest solution I would recommend solving is this:

class MyActor{
      private boolean firstDraw = true;

      @Override
      public void draw(Batch batch, float parentAlpha) {
            if(firstDraw)
            {
                  batch.begin();
                  firstDraw=false;
            }
            batch.end();
            Gdx.gl.glEnable(GL20.GL_ARRAY_BUFFER_BINDING);
            Gdx.gl.glEnable(GL20.GL_BLEND);
            Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
            shapeRenderer.begin(ShapeType.Filled);

            //change color

            shapeRenderer.setColor(color);

            shapeRenderer.rect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);

            shapeRenderer.end();
            Gdx.gl.glDisable(GL20.GL_BLEND);
            batch.begin();
      }

      ...

}

      

+3


source


As Angel * 2 says, your error comes from calling .end before .begin. Multiple batches of blueprints are quite possible and often used, but you must use them in order and start / end correctly. The following code is valid:

spriteBatch.begin();
spriteBatch.draw(..);
//more draw calls for this spritebatch
spriteBatch.end();

shapeRenderer.begin(..);
shapeRenderer.line(..);
//more draw calls for shaperenderer go here
shapeRenderer.end();

anotherSpriteBatch.begin();
anotherSpriteBatch.draw(..);
anotherSpriteBatch.end();

//You can also use the same batch again.
shapeRenderer.begin(..);
shapeRenderer.circle(..);
shapeRenderer.close();

      

0


source


I know this is an old question of mine, but I see that there are still new people using libgdx after facing this error. So I am posting my workaround as an answer:

The problem is that there is something in between

batch.begin()

      

and

batch.end()

      

when drawing a scene

so if you are using Stage to control the package try-catch can save you time:

@Override
public void render(float delta) {
    try {
        stage.act(delta)
        stage.draw()
    } catch (Exception ex) {
        if(stage.batch.isDrawing)
            stage.batch.end()
    }
}

      

** This is just a workaround for some random error (like glyphlayout) in a frame, and it should work fine on the next frame. If there is any real problem in your code or resource, your rendering code will end up in catch {}

0


source







All Articles