Android Question libGDX: ScreenManager and SpriteBatch

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
I'm expanding the assetmanager/screenmanger example based on the PacDroid example program.

Using the same basic UI structure as the PacDroid game, with the addition of the screen manager, I'm getting an error during the render event for the map:
B4X:
java.lang.IllegalStateException: SpriteBatch.end must be called before begin.
at com.badlogic.gdx.graphics.g2d.SpriteBatch.begin(SourceFile:161)
at com.badlogic.gdx.maps.tiled.renderers.BatchTiledMapRenderer.beginRender(SourceFile:166)
at com.badlogic.gdx.maps.tiled.renderers.BatchTiledMapRenderer.Render(SourceFile:127)
at b4a.example.clsmap._drawall(clsmap.java:120)
at b4a.example.main._grpmap_draw(main.java:463)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
<--snip-->

Is this something I am doing incorrectly, or can a group render event only be called from the main render thread and not from a screen render thread?

-- Edit: Modified attached example to more closely follow the PacDroid UI setup.
 

Attachments

  • AssetAndScreen2.zip
    423.3 KB · Views: 360
Last edited:

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
I've been tinkering with this some more, and I've found that if I comment out the group_draw block and invoke the map render directly in the screen render event I can get past the batch error.

However, when it draws the map it draws it flush with the bottom of the screen, not centered in the middle cell of the table. Is this because the render is called from the main render event and not from the group_draw event?
 
Upvote 0

Informatix

Expert
Licensed User
Longtime User
All drawings of the stage are batched and rendered by a SpriteBatch renderer. So when the Draw event of an actor is triggered, SpriteBatch.Begin has already been called by the stage, and SpriteBatch.End will be called automatically after the last Draw event. If you call the Render function of a MapRenderer in a Draw event, you get the error message above ("SpriteBatch.end must be called before begin") because the MapRenderer, which is a renderer like the Spritebatch object of your stage, calls its own Begin function to start its batching process.
 
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
Odd... I tried to copy the logic (and rendering order) from the PacDroid example as closely as I could, so I'm not sure by what evil sorcery you have it working there ;).

That said, if I move the MapRenderer to main render block (comment out the group_draw block and insert the map.DrawAll before the .Act) what is causing the map to be drawn over the top of the bottom row of the table and not directly below the first row of the table?
 
Upvote 0

Informatix

Expert
Licensed User
Longtime User
Odd... I tried to copy the logic (and rendering order) from the PacDroid example as closely as I could, so I'm not sure by what evil sorcery you have it working there ;).
In PacDroid, I don't call the Render function in the Draw event, but RenderTileLayer (in Maze.Draw). RenderTileLayer is equivalent for a layer of a map to the Draw function of an actor. On the contrary, Render is a complete process: Begin, Render all layers, End. That's why you cannot call Render in a Draw event.

That said, if I move the MapRenderer to main render block (comment out the group_draw block and insert the map.DrawAll before the .Act) what is causing the map to be drawn over the top of the bottom row of the table and not directly below the first row of the table?
In PacDroid, the map is not drawn separately from the stage objects. It is drawn in a cell of the main stage table (for this, I use the Draw event of a group). If you draw the map outside the table, then it is probably drawn at 0, 0 and the cell in the table where it should be (MainCell) is empty.
 
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
Outstanding explanation! The salient point that I failed to grasp was that the .Render has its own batch start/end and the RenderTileLayer renders as part of an existing batch!

And you are also correct, if the map is not drawn inside the group's draw event it is then rendered on the main stage and not in the table cell containing the group (another important point, I think).

The RenderTyleLayer method seems to clear the image before it draws the requested layer, if your map has more than one layer to be rendered, does that mean you cannot use this method?
 
Upvote 0

Informatix

Expert
Licensed User
Longtime User
Outstanding explanation! The salient point that I failed to grasp was that the .Render has its own batch start/end and the RenderTileLayer renders as part of an existing batch!

Render does:
Batch.Begin
RenderTileLayer1
RenderTileLayer2
RenderTileLayer3
....
Batch.End

The RenderTyleLayer method seems to clear the image before it draws the requested layer, if your map has more than one layer to be rendered, does that mean you cannot use this method?
RenderTileLayer does not clear anything. You can call many RenderTileLayer in a row and each layer will be on top of the other. But pay attention that I disable the blending in PacDroid to improve performance when I draw the layer. Without blending, each layer is opaque.
 
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
But pay attention that I disable the blending in PacDroid to improve performance when I draw the layer. Without blending, each layer is opaque

Nice catch, I didn't even consider that (not that I knew what the blending did exactly). I'm sorry if I seem a bit dense trying to understand all this and I really appreciate your patience in explaining it to me.

I have tried reading the libGDX documentation directly from the badlogic site, but the documentation there seems to be a bit too self-referencing most of the time for me to be able to understand it.

Did you have a book that explained things such as the Render process or is this just more obvious if you actually know Java code?
 
Upvote 0

Informatix

Expert
Licensed User
Longtime User
Did you have a book that explained things such as the Render process or is this just more obvious if you actually know Java code?
I had nothing but the code and the wiki was not as rich as it is currently. But after a few weeks in the Java code, it was a lot more clear. That being said, there are still parts that I couldn't explain (e.g. all the OpenGL advanced stuff).
 
Upvote 0
Top