如何在一个屏幕中使用SpriteBatch和ShapeRenderer?

时间:2015-06-17 14:24:39

标签: libgdx

我使用SpriteBatch绘制纹理,使用ShapeRenderer绘制一些形状。

这是我在演员中的代码

@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();
}

并在屏幕上调用stage.draw()

@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();
    //......
}

它工作但不可预测地抛出异常:

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)

编辑:有关我正在做的更多详情:

我想要的是画一个形状。因为舞台的批次正在绘制所以我必须结束它以进行形状绘制。我的代码仍然可以工作,但有时候,另一个演员,我认为,使用stage的批处理来绘制其他内容。它使舞台开始批量生产。所以它在开始和结束之间发生冲突。

例如,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() 

编辑: 如果其他人&#39;答案不适合你,请考虑我的解决方法我在下面发布答案。

4 个答案:

答案 0 :(得分:9)

@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(); <--

我认为错误在于您在batch.end ()尝试更改订单之前调用bacth.begin ();

另一方面,如果是绘制方法。这是舞台课程,你用你需要的参数称呼他public void draw (Batch batch, float parentAlpha)

答案 1 :(得分:3)

如果在打开新渲染器之前没有关闭所有渲染器,您将获得一个没有前一个渲染器的视图

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

这会导致屏幕没有你的spriteBatch-Textures --- 您已经通过将代码用于此

来解决了这个问题
    @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
 }

但是在第一个batch.end()中你的代码无法找到任何可以关闭的打开的spriteBatch,因此你得到一个IllegalStateException

你必须致电

batch.begin()在使用end() - 方法之前一次 (但要注意,你不应该每一帧都开始批处理)

我建议解决此问题的最简单的解决方案如下:

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();
      }

      ...

}

答案 2 :(得分:0)

就像Angel * 2所说,你的错误来自于.begin之前调用.end。使用多个绘图批次是完全可能的并且经常使用,但您必须按顺序使用它们并正确地开始/结束它们。以下代码有效:

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();

答案 3 :(得分:0)

我知道这是我的老问题,但我可以看到还有新人使用libgdx也面临这个错误。所以我发布我的解决方法作为答案:

问题在于

之间存在某些中断
batch.begin()

batch.end()

舞台绘图时

因此,如果您使用Stage来管理批次,那么try-catch可以节省您的时间:

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

**这只是绕过框架中的一些意外错误(例如glyphlayout)的一种解决方法,它应该在下一帧中正常工作。如果您的代码或资源中存在任何实际问题,您的渲染代码将最终出现在catch {}