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);
}
Related
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.
Very simple question, but I could not find the answer in JavaFX docs or StackOverflow:
I have a JavaFX Canvas filled with a graph (various calls to strokeLine(), not the issue here). I need to be able to draw a rectangle over this graph, then simply clear the rectangle, without affecting the graph in the background. (Like an undo operation).
Code to draw the rectangle ('p' and 'e' are points):
gc.rect(p.getX(), p.getY(), e.getX()-p.getX(), e.getY()-p.getY());
gc.stroke();
The most obvious answer would be to use the clearRect() method, but the problem is that it clears also the portion of the graph in the background...
So the question is: how do I clear a drawing that was made with stroke(), without affecting the other drawings in the background?
You can't do this with one canvas.
Canvas only store the result of your painting operation.
This is the interest of the canvas you can stroke million times the same line and it will only store and represent the result and doesn't consume more memory.
So you if you need to draw Something over your chart you should put an other canvas over the chart and draw on the second canvas.
It might be more straight forward and much more the JavaFX-way of doing things if you just put your canvas into a Group and then just add a Rectangle node to the Group which you can remove at any time if you want.
This can be acheaved by taking snapshot(s) of your Canvas, using the .snapshot(SnapshotParameters params, WritableImage image) method. Basicly, every time you draw something on your Canvas, you take a snapshot of it and store it somewhere (for example in a ArrayList). Then you can use those snapshots to create a 'undo' operation, by using the . drawImage(Image img, double x, double y) method of Canvas's GraphicsContext, in which you would pass the snapshot you want to go back to as the Image parameter.
I'm using a ShapeRenderer object to create a color gradient in my game (Screen class). The allocated memory used to grow permanently until I started to dispose my ShapeRenderer object after every call. How can I reuse my color gradient? Is there a way to paint the gradient into a texture (only once for reuse in the render method)?
public void render(float deltaTime) {
camera.update();
batch.setProjectionMatrix(camera.combined);
ShapeRenderer shapeRenderer = new ShapeRenderer();
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.rect(0, 0, screenWidth, screenHeight, topColor, topColor, bottomColor, bottomColor);
shapeRenderer.end();
shapeRenderer.dispose();
batch.begin();
...
batch.end();
}
Although it seems you have solved your problem, here is just a little note for you and anyone stumbling across this post with a similar question.
Do not instantiate new Objects (of any type) during every run through a loop, at all costs. The reason you were experiencing slow-down is because of exactly this. Every time you instantiate a new object and then stop using it, the JVM's Garbage Collector needs to get rid of that Object. You should always try to reuse objects. This is why pools and memory management in general (these links are for LibGdx specificially) are so important.
Your notion to make a field for the ShapeRenderer was a good one, just don't forget to dispose() it in your game's dispose() method.
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.
I'm developing some kind of videogame, so I am not interested in calling paint, repaint or any sort of those methods on each updating from keylistening, since they call also the update(Graphics g) method which cleans the whole screen. That's why I do want to #Override the update method, not allowing it to cleaning the screen at first. Doing this I can update what I want when I want.
However, sometimes it goes in a loop auto painting the components (such as jButtons) cleaning the screen(I couldn't track anything special happening whenever this occurs, I have already tried overriding some methods in order to catch which one's the troublesome and I couldn't find it, I'm likely missing something). I do not want this happening, because this auto painting cleans the screen which makes me draw everything once again. Moreover I don't feel comfortable with something looping until the player press any key. Do you have any clue? One solution could simply be using a timer with a boolean that each time a screen is completed and the next one is being loaded it calls update(g) from my JFrame (which contains the jPanel). But I would like something better..
Maybe I am doing something wrong, even if I tried to improve my painting methods thousand times surfing throughout the net and netbeans's suggs.
This is how my painting methods looks with some flags written and the ones that are called after running:
#Override public void paint(java.awt.Graphics g){
paintComponents(g);
System.out.println("Flag");
update(g);
}
#Override
public synchronized void update(Graphics g)
{
g.setColor(java.awt.Color.GREEN);
w.getDrawer().draw(g);
g.drawRect (0, 0, w.getActive().getW(), w.getActive().getH());
}`
The overriding on paint(Graphics g) method is not needed at all, just did it in order to see what was going on. I never called repaint() but update(getGraphics()) and it just spam Flags all around. Also thought that maybe I was making it run in a loop with paint and paintComponents, but deleting paintComponents(g) line helps not at all.
Any help would be welcome, since I am trying to make this project "serious". Thanks in advance.
Sergi.
By the way, w.getDrawer().draw(g); is just calling some entities (like 100) with something like g.drawImage(image, locationX, locationY, null) inside. I don't think it has anything to do with my prob.
..this auto painting cleans the screen which makes me draw everything once again.
Draw it to a BufferedImage displayed in a JLabel. When the data (the image) updates call label.repaint().
E.G. as seen in:
This answer to How to draw an image over another image?
This answer to Dynamic Graphics Object Painting.