Libgdx SpriteBatch draws Actors, but not other Textures - java

It's been a while since I used LibGdx, so I feel like I'm just missing something obvious.
My render method in MyGdxGame looks like this, calling for the stage to draw itself (along with its actors), and then I try to draw a set of textures for debugging purposes.
#Override
public void render()
{
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
StageManager.getCurrentStage().act();
spriteBatch.begin();
StageManager.getCurrentStage().draw();
for(int i = 0; i < 100; i++)
{
spriteBatch.draw(TextureManager.getPlayerTexture(), 50*i, 50*i);
}
}
The stage is drawn along with its one actor, but the other textures are not being drawn.
What I've tried: setting batch projection matrix off the stage camera(after calling update), making sure the texture coordinates should be visible.
The actor gets its texture from the same TextureManager.getPlayerTexture so I don't think its a texture issue.
What else should I check for to get the textures drawn as well?

Normally, your code would have caused a RuntimeException, because you're calling begin on the batch before drawing the stage. But since you actually have two sprite batches (one internal to the Stage because you didn't share the original with it), no actual errors occur.
You're missing a call to spriteBatch.end() after drawing your texture(s). And the call to spriteBatch.begin() needs to move after stage.draw().
And you should pass that sprite batch into the Stage constructor, because it is wasteful to have more than one sprite batch. Each sprite batch uses a fair amount of memory and compiles a shader.

Related

LibGDX - setProjectionMatrix() "hiding" a Sprite

I am trying to draw a Sprite but it just appears for a frame when I first run my program, and then immediately disappears. I am working with a Stage, a Tiled map and two Batches, which I hope is not a problem.
It pretty much looked like the sprite was hiding behind something else, but I made completely sure that nothing was being drawn after it. So after a long time messing around, I found out that deleting the setProjectionMatrix() method "solved" my problem, since the sprite showed perfectly somehow.
I don't understand the reason why this happened at all, and I don't want to just delete the method and have sprites following the camera around, so:
Why or how would a setProjectionMatrix() method "hide" a Sprite? Is it altering the order in which my sprites are drawing? And most importantly, how do I fix it?
Here's my render method:
public void render(float delta) {
Render.cleanScreen(); //Render is a class i made with useful static stuff, like the Batch i am using.
//This method is pretty much just a Gdx.gl.glClearColor() method.
tmr.setView(camera); // tileMapRenderer
tmr.render();
b2dr.render(world, camera.combined); // Box2DDebugRenderer
stage.act();
stage.draw();
Render.batch.begin();
sprite2.draw(Render.batch); //The sprite i want to draw
Render.batch.end();
hudBatch.begin();
sprite1.draw(hudBatch); //This works fine
hudBatch.end();
Render.batch.setProjectionMatrix(camera.combined);
Gdx.input.setInputProcessor(stage);
}
Edit: Someone asked for extra info, so:
• This is what my game looks like with the setProjectionMatrix (after the first frame when the Sprite dissapears) and this is what it looks when i delete it. You can clearly see the red square(the Sprite).
• I am currently using a FitViewport.
Stage.draw() calls apply() on the Stage's Viewport, but never restores the OpenGL Viewport to what it was before. I'm guessing that your stage uses FitViewport, so it is cropping part of the screen. If you want different viewport behavior for stuff you draw outside your stage, you should create a separate viewport for that, and call viewport.apply() before you start rendering the other stuff.
Side note: if you are lazy loading anything that uses native memory (like SpriteBatch and Texture, things implementing Disposable) and storing a reference in a static variable (your Render class), make sure you dispose all of it and null it out in your game's destroy() method. Otherwise, on Android you will be leaking that stuff and it will fail to work when you reopen your game.
Another side note: In my opinion, the Sprite class should not be used unless you have hundreds of them and they aren't moving much (in which case it might have slightly better performance). Sprite is a weird conflation of an asset (a TextureRegion) and game state data. As a result, it can create design issues that you have to work around, such as when you want to animate it or flip it. It is better to create your own GameObject class that references a TextureRegion (a single instance of which can be shared by many elements), and has its own variables for position, color, rotation, etc. Then draw it with the appropriate SpriteBatch.draw method using those properties. In my game, I have a wrapper interface around TextureRegion that can alternately wrap Animation<TextureRegion> so my GameObject class can use either and it can be swapped easily. This makes the code more flexible to change.
So... I just realized my coworker accidentally deleted the viewport.update() method.
#Override
public void resize(int width, int height) {
viewport.update(width, height);
}

Is LibGDX SpriteBatch draw() smart enough not to redraw 100% exactly same sprite at each render() call?

Is LibGDX SpriteBatch draw() smart enough not to redraw 100% exactly same sprite at each render() call?
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (shallFadeOut) { // becomes true when sound message finishes
doFadingOut();
showNextScreen();
dispose();
} else {
batch.begin();
// introSprite is a static image - it never changes a pixel (splash screen)
// I need to paint it once and then just wait until sound message finishes
// DON'T NEED TO REDRAW IT EVERY render() cycle 60 times/sec (~60 fpm)
introSprite.draw(batch);
batch.end();
}
}
In OpenGL, you typically redraw the whole screen on every frame. It doesn’t make sense to wonder if the batch is smart enough to avoid redrawing the same thing, because it has to redraw it to prevent it from disappearing.
If you want to avoid redrawing anything on the screen for a while to save battery on the device, you can use GDX.graphics.setContinuousRendering(false) but that means your render() method will stop getting called so you must set it back to true using a timer or input callback.
You could alternatively use a Boolean to decide whether to clear the screen with glClear and draw stuff, but under the hood, LibGDX will still be requesting OpenGL to copy the screen buffer data between the back buffer and the screen buffer.
Not that drawing a single sprite is super trivial and probably not worth a second of thought about optimizing it.
I am afraid that I do not think any accounting is done by the Batch between batching render steps to see if a texture was already loaded and is ready to be rendered, but the texture itself might.
The batching is intended for cases where you are drawing duplicates of the same thing in the same render step so that you are not unnecessarily context switching between sprites and having to reload data to your graphics card.
The batch is as I am sure you know defined by the begin and end calls you are using, and it depends on you actually rendering all of the sprites of a particular type one after the other without jumping to render something else. This can be seen int he batch draw code here, but for readability the relevant lines are below:
Texture texture = region.texture;
if (texture != lastTexture) {
switchTexture(texture);
} else if (idx == vertices.length) {
flush();
}
To take advantage of the batch - you should be grouping the rendering of all your sprite types, and between steps, the batch does not offer any efficiencies by design as far as I can tell.
But, between batching steps or game loops, when a texture is bound, it uses a fixed target and handle as can be seen here. This means that if all you are drawing is a single sprite for several render loops, libgdx should be using your memory and graphics card as efficiently as can be expected.

Libgdx stage2d with another camera for HUD, how to handle the coordinates?

I'm using a stage in my game screen. In this stage I have actors like the map of the game (where player can move, and the camera of the stage moves along and scales (or relocates) to keep the viewport inside the map), the player and other game stuff. Then I add a HUD element that I make by extending Group:
public class Hud extends Group implements Disposable {
In this class I define a new OrthographicCamera:
hudCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
I want to use this camera to keep the HUD stationary on the screen. I do the drawing like this:
#Override
public void draw(SpriteBatch batch, float parentAlpha) {
batch.setProjectionMatrix(hudCamera.combined);
//Then draw my HUD stuff
}
The drawing works fine, but the problem is the (touch- and other) events. They have the wrong coordinates. How can I resolve this. I have tried to override the hit(float x, float y, boolean touchable) method and thought about overriding the localToParentCoordinates and parentToLocalCoordinates methods. But what would I put in them (multiplying by hudCamera.combined like when drawing, or something like that)? Or am I thinking this all wrong alltogether?
I'm also worried that, when I use zoom in my stage's camera, it will mess up with the coordinates. Is this a reality?
For creating HUDs, you could generally use multiple Stages on your screen, which are being rendered on top of each other. You can even have more than two, e.g. for a Pause-Dialog which is rendered on top of the HUD when the Application is paused and resumed...
You just need to make sure that within the render()-method they are drawn an in the right order:
public void render(float delta) {
scene.act(delta);
hud.act(delta);
pauseDialog.act(delta);
scene.draw();
hud.draw();
pauseDialog.draw();
}
This way you can create different coordinate systems however you like. Especially when working with Fonts and Labels in your HUD, it should have a coordinate system that matches the pixel size, e.g. setViewport(1280,768,true); or alike, whereas your Scene can have a completely different one.
I think camera.unproject(touchpos) should work, but I have never used it. You would have to search for it.
I would suggest using 2 stages, as the game and the HUD are independent parts of the screen. By using 2 Stages you have 2 cameras, 1 for each Stage. You can then move the game's camera around and the HUD would still be at the same position.

How do I draw adjacent bitmaps to a canvas in Android?

I've spent all night trying to figure out why I can't draw a series of bitmaps completely adjacent to each other (with no gaps in between), using Android.
For context, I am building a spectrogram application which displays a vertical bitmap for each 'window' of audio data that comes in, providing the user with a heatmap of frequencies. At the moment I'm using pre-recorded audio so I can perform all my calculations before I have to display anything - I have an ArrayList of integer arrays, each of which represents one window's bitmap, which is drawn to a canvas using a timer thread.
I am aware that the approach below will ultimately break when the application tries to draw past the dimensions of the screen, but I am not worrying about that for now. The problem I would like to solve is that the below code results in a one-pixel (ish) gap between the drawn bitmaps, when I would actually like them to be absolutely adjacent.
This is the run() method for my timer thread:
public void run() {
Canvas c = null;
try {
c = sh.lockCanvas(null);
synchronized(sh) {
doDraw(c);
}
} finally {
if (c!=null) {
sh.unlockCanvasAndPost(c);
}
}
}
This is the doDraw() method which draws the bitmaps, and then skips along to the end of that drawn bitmap in order to draw the next one. It simply does so by incrementing the 'windowsDrawn' field:
private void doDraw(Canvas canvas) {
canvas.drawBitmap(spec.getBitmapWindow(windowsDrawn), 0, 1, windowsDrawn, 0, 1, h, false, null);
System.out.println("Windows drawn: "+windowsDrawn);
windowsDrawn++;
}
spec.getBitmapWindow(windowsDrawn) simply returns an integer array of pixel values for the vertical window to be drawn.
Here's a screenshot to show what I'm talking about.The image looks as if it is behind tiny prison bars and I would like to get rid of these.
Thanks!
I found out what I was doing wrong. The 'prison bars' effect was actually a side-effect of me writing incremental updates to the back-buffer, which was presumably being flipped every so often (hence losing some of my updates to the other buffer, giving the black vertical lines). The problem was solved by ensuring that I was instead writing to a buffer bitmap and then redrawing the entire frame each time. Incremental updates to the screen (like I was trying to do) are not allowed in Android.

Libgdx SpriteBatch.SetProjectionMatrix makes spritebatch not draw

SpriteBatch.SetProjectionMatrix(cam.combined) makes Spritebatch not draw blocks and my character but camera movement works, but if I don't use this line of code everything is drawn but camera is not working? Does anyone know the solution, because if simply can't see it.
EDIT: sorry for the messy first post
Here is the piece of code that is troublesome:
public void render()
{
cam.update();
spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.begin();
drawBlocks();
drawBob();
spriteBatch.end();
cam.position.x = world.bob.GetPosition().x;
cam.update();
drawCollisionBlocks();
if(debug)
drawDebug();
}
I found the solution but for anyone who may have this kind of problem in the future, the problem was in drawing methods where i was drawing
textures like this:
CODE:
spriteBatch.draw(bobFrame, bob.GetPosition().x * PPuX, bob.GetPosition().y*PPuY ,Bob.SIZE*PPuX , Bob.SIZE*PPuY );
PPuX,PPuY were of type int and were used for different screen sizes and that was messing spriteBatch up when i was setting the projection matrix
The spriteBatch.setProjectionMatrix(cam.combined) lets spriteBatch use the coordinate system that specified by cam instead of the default ones. This is because the both's coordinate system are different and the cam.combined will do the maths for you.
I believe you actually ARE drawing the sprites, however you are not seeing them because your camera viewports are not set(ie. you are looking at the wrong coordinate area).
Adding
cam.setToOrtho(false); //true to invert y axis
"Sets this camera to an orthographic projection using a viewport fitting the screen resolution, centered at (Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2), with the y-axis pointing up or down."
Link to JavaDOC here

Categories