【问题标题】:How to use SpriteBatch and ShapeRenderer in one screen?如何在一个屏幕中使用 SpriteBatch 和 ShapeRenderer?
【发布时间】:2015-09-02 20:35:33
【问题描述】:

我使用 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)

编辑:有关我在做什么的更多详细信息:

我想要的是画一个形状。因为舞台的batch正在绘制,所以我不得不结束它进行形状绘制。我的代码仍然有效,但有时,另一个演员,我认为,使用舞台的批次来绘制其他东西。它使舞台开始它的批处理。所以它在开始和结束之间发生冲突。

比如actor的draw方法:

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

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

【问题讨论】:

    标签: libgdx


    【解决方案1】:

    我知道这是我的老问题,但我可以看到仍有新人使用 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()
        }
    }
    

    ** 这只是绕过帧中一些意外错误(例如字形布局)的解决方法,它应该在下一帧中正常工作。如果您的代码或资源中存在任何真正的问题,您的渲染代码最终会被捕获{}

    【讨论】:

    • 所有其他答案都是错误的,因为他们没有注意到您的代码在 Actor 的 draw 方法中,但是如果这不是一个丑陋的 hack,那就太棒了。您最初的问题几乎可以肯定是因为未接来电 batch.end() 或额外来电 batch.begin()。您在原始问题中发布的实际代码不会是罪魁祸首。 LibGDX 不做任何异步绘图。
    • @Tenfour04 确实,我的代码问题是因为已修复的旧版本 GlyphLayout。它打破了stage的draw方法中的循环,因此stage无法调用batch.end()在下一帧调用batch.begin()时发生所有错误
    【解决方案2】:

    如果您在打开新渲染器之前没有关闭所有渲染器,您将看到没有以前的渲染器

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:
        @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 (); 之前尝试更改顺序

        另一方面,如果是draw方法。是舞台课,你用你需要的参数给他打电话,public void draw (Batch batch, float parentAlpha)

        【讨论】:

        • draw 方法在一个actor中。我想要的是结束阶段的批处理(绘制一些东西)以便绘制一个形状,然后再开始它。我的代码仍然有效,但有时,另一个演员,我认为,使用舞台的批次来绘制其他东西。它使舞台开始它的批处理。所以它在开始和结束之间发生冲突。 batch.end() ... batch.begin() (某处) .. batch.begin()
        猜你喜欢
        • 2013-02-06
        • 2018-04-14
        • 2013-09-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多