libgdx/Android: graphics disappearing after the app is destroyed/paused - java

I was doing some tests and I realized that on my Nexus 5, when I hit the back key (or the home) -that is, when there's a change of context- and I go back to my game, the openGL context is lost.
There are no textures anymore (they show as black) or skins for the UI (the buttons are white).
I thought it was automanaged by libgdx automatically, right? So why is this happening?
The way I'm creating the textures is via TextureAtlas, like
TextureAtlas atlas;
TextureRegion bg;
atlas = new TextureAtlas(Gdx.files.internal("mainMenu.atlas"));
bg = atlas.findRegion("bg");
And then it's used with the batch.draw(bg, x, y, w, h);
I also tried creating the TextureRegion loading directly a Texture instead of a TextureAtlas (just in case but it should be the same) and I get the same result...
Anyone?
Edit: more specific code:
Screen class basics:
public class MainMenuScreen extends ScreenManager.Screen {
private Game game;
private InputMultiplexer inputMultiplexer = new InputMultiplexer();
private MainMenuUi screenUi;
private MainMenuView screenView;
private TextureAtlas atlas;
public MainMenuScreen(ConbiniGame game) {
this.game = game;
atlas = new TextureAtlas(Gdx.files.internal("mainMenu.atlas"));
screenUi = new MainMenuUi(game);
screenView = new MainMenuView(atlas);
inputMultiplexer.addProcessor(screenUi.getInputProcessor());
inputMultiplexer.addProcessor(screenView.getInputProcessor());
Gdx.input.setInputProcessor(inputMultiplexer);
}
// ...
}
MainMenuView class where the TextureAtlas is being used...
public class MainMenuView {
private Stage stage;
private OrthographicCamera camera;
private Viewport viewport;
private TextureAtlas atlas;
TextureRegion bg;
public MainMenuView(TextureAtlas atlas) {
atlas = atlas;
bg = atlas.findRegion("bg");
camera = new OrthographicCamera();
camera.setToOrtho(false);
viewport = new FitViewport(1080, 1920, camera);
stage = new Stage(viewport);
}
public void update(float delta) {
stage.act(delta);
}
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.getBatch().begin();
stage.getBatch().draw(bg, 0, 0, stage.getCamera().viewportWidth, stage.getCamera().viewportHeight);
stage.getBatch().end();
stage.draw();
}
public InputProcessor getInputProcessor() {
return stage;
}
}
The code is just to show the use of the texture, with other parts removed

You didn't provide enough information, but your problem is likely caused by using static in your code. Don't do that.
When you press the back button your app is closed. When you press the home button then your app is paused. Note that this are two different things. Therefor you might experience the problem not always when using the home button. This because while your app is paused, that android might decide to close it (to free memory), but it is not guaranteed to do so.
Either way, this is not related to the opengl context being lost. It is just closed. If the context would be really lost then libgdx (and later versions of android) will recover it for you.
When you close your app and then immediately start it again then Android might reuse the same VM for that instance of your app. This also means that any static variables will have the value they had from the previous run of your app. If any of those variables include (may be indirectly) any resources, then those resources won't be valid anymore.
tl;dr never use static in android applications.
The most common mistake (without seeing your code this is just guessing) is to access assets by using a singleton. E.g. MyGame.getInstance().assets.get("atlas",...); don't do that, it will (because of above reason) fail. Instead pass a reference to your MyGame instance to whichever classes needs it (e.g. your Screen: new MenuScreen(this);).

I ran into the same problem when making my first LibGDX game - a Flappy Bird clone - and it turned out the problem was not with the Texture at all, but with a MEMBER Vector2/Vector3 variable that I used for velocity.
To make the bird fall from a given height, I'd declared:
1. a member int variable for gravity (initialised to -15),
2. a Vector2 member variable for bird position, initialised to (50, 300), and
3. another Vector2 member variable for velocity, initialised to 0,0
Now, in the update() method, I passed gravity as a value to velocity's y-axis parameter using velocity.add(0, gravity)
Then I scaled it, using velocity.scl(dt)
Then I added that velocity to position and then unscaled it again, using velocity. scl(1/dt).
This last line was what caused the bug, but since it was essential for the functionality of my game, I couldn't afford to delete.
My solution was to change the velocity variable from a member variable to a local variable, and the textures stopped disappearing when game was paused.

Actually it's OK to use Singleton or other static paterns for texture management. The only thing you should do to escape black-rectangle problem is:
make static content depending of Game entity:
private static TextureStore sStore = null;
private static MyGdxGame sGame;
static public TextureStore getStore()
{
if(sStore==null||sGame!=MyGdxGame.getGame())
{
sStore = new TextureStore();
sGame = MyGdxGame.getGame();
}
return sStore;
}
And in game entity
#Override
public void create()
{
sGame = this;
...

Related

Adding rayhandler in LibGDx causes issues in InputListener

I am trying out Libgdx, and I have an actor which performs some action whenever we click on it. So far it is working fine. Now I want to add light to the actor. After doing some research I came across Box2DLights. When I tried adding it to my project onClick Actor which was working fine does not seem to work. I am pretty sure this is due to rayhandler/Box2DLights because that is the only change I am making. here is the minimal change that I made to include Box2DLights.
public class GameScreen implements Screen {
private RayHandler rayHandler;
private World world;
public GameScreen(Game game) {
this.game = game;
world = new World(new Vector2(0, 0), true);
rayHandler = new RayHandler(world);
rayHandler.setAmbientLight(0.1f, 0.1f, 0.1f, 1f);
rayHandler.setBlurNum(3);
}
#Override
public void show() {
viewport = new FitViewport(1080, 720);
stage = new Stage(viewport);
rayHandler.setCombinedMatrix(stage.getCamera().combined);
Gdx.input.setInputProcessor(stage);
}
#Override
public void render(float delta) {
//some custom rendering logic, but nothing related to rayHandler, excluding this for brevity.
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
rayHandler.updateAndRender();
}
Now When I debugged, I realised the the onClick is
working little below the actual actor
, that means somehow the coordinates sifted(I know weird).
Can you please help?
Thanks #Mikhail Churbanov for your response here.
If somebody else stumbles on this again here is the solution which worked.
viewport = new FitViewport(1080, 720);
rayHandler.useCustomViewport(viewport.getScreenX(),
viewport.getScreenY(),
viewport.getScreenWidth(),
viewport.getScreenHeight());
The explaination is box2lights doesn't auto-acquire custom viewports, and restores the 'default one' after the updateAndRender called - your need to set your custom 'fitted' viewport to rayHandler so that it would restore it correctly- using the rayHandler.useCustomViewport(...) method.
All credits to #mikahi churbanov

Libgdx texture sizes, developing for bigger resolution than my laptop's

I'm currently working on a libgdx game and before I give it final touches I wanted to actually hear something from experienced users, that has been bothering me for a few days already.
If I want to support as many as possible devices, essentially I will be designing graphics for the biggest possible res ,which is then going to be scaled if needed, for smaller screens, right? How do I go about developing for a resolution that is even bigger than my laptop's(the 2015/16 gen phones). My laptop has a resolution of 1920x1080px and the S7 Samsung has 2k+ width.
Thank you!
I think what you are looking for is Viewports. You have to decide which strategy fits best your needs. For example a FitViewport always keeps the aspect ratio you define, which might lead to black bars on some devices.
When I personally develop with libgdx I place and size all objects relative to the screen width and height. This includes images, fonts, buttons, etc. This gives me a pretty consistent result across all devices because most devices today have a ratio 16:9 or something close to it. For developing an image larger than your screen size what's wrong with just using photoshop to create the image of the specified size?
Better you choose the screen with as 1280 and screen height as 800 and also use the fill viewPort . So you will be able to render your game in almost all the screens without the issue of stretching.
Viewport is the method which provided by the libgdx to solve this multi screen compatible issue . here i will post some sample code which you can use for the reference.
public class myGame extends ApplicationAdapter {
public OrthographicCamera camera;
public Viewport viewPort;
private SpriteBatch batch;
private BitmapFont myScoreFont;
private Texture texture;
public myGAme() {
}
#Override
public void create() {
myScoreFont = new BitmapFont(Gdx.files.internal(Constants.PATH_TO_MY_SCORE_FONT), true);
batch = new SpriteBatch();
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
texture = new Texture(Gdx.files.internal(Constants.PATH_TO_LEFT_BAR));
camera = new OrthographicCamera();
camera.position.set(0, 0, 0);
camera.update();
camera.setToOrtho(false, Constants.APP_WIDTH, Constants.APP_HEIGHT);
// Here is the viewport is setting up with the camera and the screen size
viewPort = new FillViewport(1280, 800, camera);
}
#Override
public void dispose() {
batch.dispose();
}
#Override
public void render() {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL30.GL_COLOR_BUFFER_BIT);
float deltaTime = Gdx.graphics.getDeltaTime();
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(myScorefont,"Score",0,0);
batch.end();
}
#Override
public void resize(int width, int height) {
// the game area will be resized as per the screen size of the device
viewPort.update(width, height);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}

Java/libGDX - issues with Actions.fadeIn() and Actions.fadeOut()

it's my first time posting and I'm self taught so be please gentle!
I've been building a bomberman replica game in libGDX using Game and Screen classes:
public class Main extends Game {
...
#Override
public void create() {
levelScreen = new LevelScreen(playerCount, new int[playerCount]);
levelScreen.level.addAction(Actions.sequence(Actions.alpha(0), Actions.fadeIn(2f)));
this.setScreen(levelScreen);
}
However when the game launches there is no fade effect.
public class LevelScreen implements Screen {
...
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 0.1f, 0.5f, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
level.act();
level.draw();
batch.end();
}
I want this levelScreen to fade in from black but it just doesn't!
When the round is over I want to fadeOut of this levelScreen to black, then fadeIn to a trophyScreen from black:
(From Main Class)
#Override
public void render() {
super.render();
if (endRoundTimer <= 0) {
trophyScreen = new TrophyScreen(playerCount, levelScreen.getScore());
levelScreen.level.addAction(Actions.sequence(Actions.fadeOut(1), Actions.run(new Runnable() {
#Override
public void run() {
setScreen(trophyScreen);
}
})));
}
}
And I've tried using the show() method in the TrophyScreen:
public class TrophyScreen implements Screen {
...
#Override
public void show() {
stage.addAction(Actions.sequence(Actions.alpha(0), Actions.fadeIn(1)));
}
I've done loads of searching and tried various things but no joy. I'm sure I'm missing something somewhere in a draw() or render() method that is preventing the fade Action from taking place.
UPDATE1
#Override public void draw() {
super.draw();
if (roundOver) {
this.getBatch().begin(); String s = String.format("%s", message);
font_text.draw(this.getBatch(), s, (90 + (2 * 30)), (this.getHeight() / 2));
this.getBatch().end();
}
For fading to work on actors, they must properly apply their own color's alpha in the draw method. And for an entire hierarchy of objects to fade at once, they must all also apply the parentAlpha parameter from the draw method signature.
So your draw method in any custom Actor subclass should look like this:
public void draw (Batch batch, float parentAlpha) {
Color color = getColor();
batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
//..do drawing
}
If you are using a Sprite in your Actor instead of a TextureRegion (which I don't recommend due to redundancies) you must apply the color to the Sprite instead of Batch.
Note that this method of fading the whole game is not a "clean" fade. Any actors that are overlapping other actors will show through each other when the parent alpha is less than 1 during the fade. An alternative that would provide a clean-looking fade would be to draw a copy of your background (or black) over your entire scene and fade that instead.
I assume that level is an object of class that extends Stage and you are creating a control inside the stage, which is weird. You are not appling color to your font_text which I assume it is a BitmapFont
Solution, the weird way
If you want to do it in this way you will need something like that:
#Override public void draw() {
super.draw();
if (roundOver) {
getBatch().begin();
String s = String.format("%s", message);
font_text.setColor(getRoot().getColor())
font_text.draw(this.getBatch(), s, (90 + (2 * 30)), (this.getHeight() / 2));
getBatch().end();
}
}
getRoot() gets Group from Stage, we do it, because every action applied to Stage is actually applied to this Group root element. We get color (which has alpha channel) and we copy the color to the bitmapFont.
This solution is weird, because you are actually creating an Label inside Stage. It is pointless, actors plays on stage, not inside.
Solution, the good way
You want to draw text, right? So just use Label which is an actor, who shows a text. Actors do jobs for you:
stage = new Stage();
Label.LabelStyle labelStyle = new Label.LabelStyle(bitmapFont, Color.WHITE);
Label label = new Label("Hi, I am a label!", labelStyle);
stage.addActor(label);
Then you can apply actions and they will work fine (and every actor can have own actions applied).
stage.addAction(Actions.sequence(Actions.alpha(0), Actions.fadeIn(5)));
label.addAction(Actions.moveBy(0, 300, 15));
There is a lot of different actors like TextButton, Image, ScrollPane. They are customizable, easy to manage and they can be integrated in groups and tables.
Output:
A better way would be to just start by drawing a black image over everything, so you don't have to mess with every scene object's alpha. Use layering to do that. This post may be helpful.
Then you can control it's alpha channel, change it's rendering to 0 right before unpausing the game action to get it's drawing cycles back. Reactivate it on stage ending for your fade out effect.
Thank you cray, it's way better like this.

Rendering textures causing memory leak

Inside my game I have this code. It renders a texture that serve as a button:
private void drawStart(){
startTexture = new Texture(Gdx.files.internal("start.png"));
startTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
stageStart = new Stage();
stageStart.clear();
buttonStart = new Image(startTexture);
buttonStart.setX(10);
buttonStart.setY(Gdx.graphics.getHeight()/2.75f);
buttonStart.setWidth(Gdx.graphics.getWidth()/4);
buttonStart.setHeight(Gdx.graphics.getHeight()/4);
Gdx.input.setInputProcessor(stageStart);
buttonStart.addListener(new ClickListener() {
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button)
{
currentState = GameState.RESET;
startTexture.dispose();
stageStart.dispose();
return true;
}
});
stageStart.addActor(buttonStart);
stageStart.draw();
startTexture.dispose();
}
However, whenever I put drawStart(); into my render method, the Java Heap and Native Heap slowly increases by 1 every 10 seconds. So, if the user leaves the game on the menu for about 5 minutes the game will crash on their phone. I've tested it and it only occurs when the texture is rendered.
I would appreciate any help on fixing this. I have tried an if statement that states if rendered = 0, render the texture then set rendered 1 but that didn't work.
This might help you. You only need draw in your render. So now you can put drawStart() in your render method which will only draw the stage, while leaving screen dont forget to call dispose.
private void drawStart(){
stageStart.draw();
}
public void initialize() {
startTexture = new Texture(Gdx.files.internal("start.png"));
startTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
stageStart = new Stage();
stageStart.clear();
buttonStart = new Image(startTexture);
buttonStart.setX(10);
buttonStart.setY(Gdx.graphics.getHeight()/2.75f);
buttonStart.setWidth(Gdx.graphics.getWidth()/4);
buttonStart.setHeight(Gdx.graphics.getHeight()/4);
Gdx.input.setInputProcessor(stageStart);
buttonStart.addListener(new ClickListener() {
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button)
{
currentState = GameState.RESET;
startTexture.dispose();
stageStart.dispose();
return true;
}
});
stageStart.addActor(buttonStart);
}
public void dispose() {
startTexture.dispose();
}
Your problem is, that in drawStart() you are creating new Textures and a new Stage.
If you call this every render loop, you create new Textures and a new Stage about 60 times/second.
This ofc causes a memory leak.
You should load/create Textures and the Stage only once, in the constructor or in the create() or show() method.
Also think about disposing them when needed. Here is a list of the things you need to dispose manually.
In the render loop you should then only update and draw the things.
But as you only have 3 month of experience i suggest you to learn the basics first. Don't rush into game programming, it will kill your motivation.
First learn the basics, then start with some ASCII-Games (commandline) and then you can start with libgdx.
If you are ready for libgdx, read the Wiki (at least the parts you need) as well as some tutorials (maybe they don't use the latest version of libgdx, but the concept should be more or less the same and it should help you understanding it.)

how to have a second screen in libgdx

I have a very simple Libgdx game, its my first one, and in this game i have a main java file(obviously). This file extends Game and looks like this.
package com.jawdroppergames.penalty;
import com.badlogic.gdx.Game;
public class Penalty extends Game{
public MainGame main_screen;
#Override
public void create(){
Assets.load();
main_screen = new MainGame(this);
setScreen(main_screen);
}
}
And in MainGame.java
private Penalty maingame;
public MainGame(Penalty game){
this.maingame = game;
camera = new OrthographicCamera();
camera.setToOrtho(true,1080,1920);
main_batch = new SpriteBatch();
ball_batch = new SpriteBatch();
}
as well as more code obviously
This works perfectly and opens the MainGame class. Now what i want to do is open ANOTHER screen from within MainGame. Ive tried using the same code and changing the necessary names of files etc, and this calls the show method but doesnt render the actual screen, it calls show() but not render(). Any help?
oh, and MainScreen does extend Game
this should work for u..
game.setScreen(new PlayScreen(game));//playscreen is the another screen
and why are you using two sprite batches, you should avoid this.

Categories