libGDX Android white screen after back button pressed - java

I am having a problem with libGDX where when I resume the application after exiting with the back button, I get only a white screen.
The actual app runs, accepts touch input, and plays sounds, but the screen is just white.
I have read that keeping static references to Textures may cause this problem but I am not doing that.
Below is a simplified version of how my asset code works.
public class GdxGame extends Game {
private Assets assets;
#Override
public void onCreate() {
assets = new Asstes();
assets.startLoading();
/*
*Within SplashScreen, GdxGame.getAssets() is accessed, and
*manager.update() is called
*/
setScreen(new SplashScreen());
}
#Override
public void dispose() {
assets.dispose();
assets = null;
}
//Perhaps a problem??
public static Assets getAssets() {
return ((GdxGame) Gdx.app.getApplicationListener()).assets;
}
}
public class Assets implements Disposable{
private AssetManager manager;
public Assets() {
manager = new AssetManager();
}
public void startLoading() {
manager.load(....);
}
#Override
public void dispose() {
manager.dispose();
}
}
Upon returning to the application after the back button is pressed, the AssetManager is recreated, the SplashScreen is reopened (as white), and the AssetManager updates until all assets are reloaded (takes about 2 seconds).
So when the application is reopened, a new AssetManager is loading all of the necessary textures, but for some reason everything is still white.
Could it have something to do with how I access the AssetManager from my UI and Game classes?
//In GdxGame
public Assets getAssets() {
return ((GdxGame) Gdx.app.getApplicationListener()).assets;
}
That is the only place where I could see something going wrong, but even still, I don't understand what could be wrong with that.
Any help would be much appreciated.
Edit:
Here is the SplashScreen class. This makes the issue even more confusing. In the SplashScreen class I load, draw, and dispose a new Texture for the logo. Nothing to do with the AssetManager. Returning after the back button is pressed, this new Texture does not appear either.
public class SplashScreen extends Screen {
private Texture logo;
private Assets assets;
#Override
public void show() {
assets = GdxGame.getAssets();
logo = new Texture(Gdx.files.internal("data/logo.png"));
}
#Override
public void render(float delta) {
super.render(float delta);
if(assets.load()) {
//Switch screens
}
//getBatch() is the same form as getAssets() ((GdxGame) Gdx.app.getApplicationListener()).batch)
GdxGame.getBatch().draw(logo, 100, 100, 250, 250);
}
#Override
public void hide() {
super.hide();
logo.dispose();
}
}

It turns out the issue was to do with how I was managing screens. I had a convenience method in my GdxGame class that allowed me to switch screens based on a ScreenType enum.
Within the enum, I would create a new screen with reflection, given the screen's class in the enum constructor.
The problem is that I stored the screens in the enums, and only created them once. This means that I was keeping and using screens from the old context when I returned after pressing back.
To solve this, I simply had to change it so that a new screen is created every time the enum is accessed, instead of storing one at the start.

Related

Overlapping music in a Java game with LibGDX implementation

I am having a problem in with this part of the code, I am creating a very simple game in Java with the implementation of LibGDX.
I have three different game states that are handled in three different classes:
StateCreation
MenuState
PlayState
They all work perfectly except for one thing. The music that I have inserted and that is created in the StateCreation should start over, when the player gets to the gameover and the state changes the mode to start over or go back to the menu. This does not happen and the music overlaps
public class GameBarbo extends ApplicationAdapter {
//impostazioni base dell'applicazione
public static final int WIDTH = 480;
public static final int HEIGHT = 800;
public static final String TITLE = "Cavaliere";
private GameStateManager gsm = new GameStateManager();
private SpriteBatch batch;
private Music music;
#Override
public void create () {
batch = new SpriteBatch();
music = Gdx.audio.newMusic(Gdx.files.internal("sound.mp3"));
music.setVolume(0.1f);
music.play();
Gdx.gl.glClearColor(1, 0, 0, 1);
gsm.push(new MenuState(gsm));
}
#Override
public void render () {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
gsm.update(Gdx.graphics.getDeltaTime());
gsm.render(batch);
}
#Override
public void dispose() {
super.dispose();
music.dispose();
}
}
You code looks very much like what I found in this guide (though they don't include super.dispose().)
Is it possible that when your game state changes, the dispose() method does not execute? I haven't used libgdx in ages, but it could be the case that dispose() only executes when you exit the program.
I see from this wiki that the Music class has a stop() method. Perhaps that needs to be called directly when the game ends. But IDK if stopping the file and executing a reload for another iteration is asking for a memory leak or not.
Hopefully someone with more experience will answer, but maybe these thoughts will help you figure something out in the meantime.

Can't access controller and its methods from another controller

I'm not 100% sure how to best describe this issue but I will try my best.
I am developing a music application and have different windows within one and have loaded panes into a little in app window shown below:
The bit that changes from a green button to the playlist screen is the window that has FXML files loaded into it.
I recently created a part of the application that plays songs from a button within this little window of the application but the media player is in the main application controller and needs to be here as it updates the values of the two sliders at the bottom.
I have seen something about referencing the exact instance of the controller I am using for the main application but I am unsure how to do this. I tried to create a static version of the mainAppController but this was a separate instance and therefore did not reference properly.
The only method I need to reference is the addPlayerListener one. I tried to make this static but because it dealt with the slider and so on from the FXML file that could not be made static, this did not work.
A simplified version of the controller and FXML file I need to reference from outside of the class looks like this:
public class MainAppController implements Initializable {
#FXML AnchorPane anchor;
#FXML AnchorPane window;
public static AnchorPane pane;
private boolean isPlay = false;
private boolean makeChanges = false;
public static MediaPlayer player;
PlayerUtils playerUtil = new PlayerUtils();
#FXML Slider volume, progressBar;
#FXML Label playTime, fullDuration;
String songFile;
Media songMedia;
Duration duration;
boolean updating = false;
//declaring the media player listener so that it can be removed and added
public InvalidationListener listener = new InvalidationListener()
{
public void invalidated(Observable ov) {
//if changes to the slider are being made then values will not be updated
//as it causes interference when trying to move the slider
if(makeChanges == false){
updateValues();
}
}
};
//this just plays or pauses depending
#FXML public void play_pause(){
play_pauseFunction();
}
//updates values of current time display (playTime) and updates the slider value
//called from the listener so constantly updating
protected void updateValues() {
//updates values of playTime and slider values
}
//THIS IS THE ONE I NEED TO ACCESS
//makes sure the player has no listeners before adding a new one
public void addPlayerListener(){
player.currentTimeProperty().removeListener(listener);
player.currentTimeProperty().addListener(listener);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
}
}
Sorry if this question is poorly asked, but I couldn't think of another way of posing it.
Thank you for help in advance
Ammendment: I would actually like to access this method:
public void play_pauseFunction(){
if(isPlay == false){
//temp while playlists not working
if(player == null){
songFile = "E:\\Project\\Whupsh\\Songs\\Whenever, wherever - Shakira.mp3";
player = new MediaPlayer(PlayerUtils.getSongMedia(songFile));
progressBar.setDisable(false);
volume.setDisable(false);
duration = player.getMedia().getDuration();
}
player.play();
//adds listener to link with slider
addPlayerListener();
play_pause.getStyleClass().remove("play");
play_pause.getStyleClass().add("pause");
isPlay = true;
}
else{
player.pause();
play_pause.getStyleClass().remove("pause");
play_pause.getStyleClass().add("play");
isPlay = false;
}
}
This method is in the same class as all other methods
One way that worked was by having a static class holding all the controllers that would be needed to be accessed from another controller.
This is by not a particularly good way of doing things, and a better way of accessing controllers from outside another would be to pass it around as a parameter as kleopatra has said.
Passing Parameters JavaFX FXML

Wrote the whole game in one class MyGdxGame. How do i mae the main menu? libgdx

I have a big problem.I wrote the whole game in same(one) class MyGdxGame extends from the ApplicationAdapter. How do I make the main menu? So that when opening the game, the main menu opens, in which 1 button, when pressed, opens the game itself (MyGdxGame)? Just tell me how to do it (what to create, what to change)
It's better to achieve high cohesion but when you code inside one class, cohesiveness become very low.
Use Screen and Game class to implement more than one screen as in your case like MainScreen, GameScreen, LevelScreen...
But if you don't want to implement that use flags for different screen in your MyGdxGame class.
public enum GameScreen{
MENU_SCREEN, GAME_SCREEN, LEVELSCREEN;
}
In render method of your MyGdxGame
public GameScreen currentScreen=GameScreen.MENU_SCREEN;
#Override
public void render() {
Gdx.gl.glClearColor(1,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if(currentScreen==GameScreen.MENU_SCREEN){
//render objects for Menu Screen
}else if(currentScreen==GameScreen.GAME_SCREEN){
//render objects for Game Screen
}
}
Change value of currentScreen when you want to move on other screen.
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
if(currentScreen==GameScreen.MENU_SCREEN){
//detect button of MenuScreen by bounds or any other way
if(check in bound){
currentScreen==GameScreen.GAME_SCREEN;
}
}else if(currentScreen==GameScreen.GAME_SCREEN){
// for Game Screen
}
return false;
}
EDIT
Pelocho suggested to use abstract method inside enum.
public enum GameScreen{
MENU_SCREEN{
#Override
public void render(MyGdxGame gdxGame) {
}
}, GAME_SCREEN{
#Override
public void render(MyGdxGame gdxGame) {
}
}, LEVELSCREEN{
#Override
public void render(MyGdxGame gdxGame) {
}
};
public abstract void render(MyGdxGame gdxGame);
}
And inside render method of MyGdxGame
#Override
public void render() {
Gdx.gl.glClearColor(1,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
currentScreen.render(this);
}
You should do it properly instead of hacking a menu in. If you look at the Screen class it has the about the same methods as the ApplicationAdapter (show, render, resize, dispose, hide, pause, resume). If you would create a new class and have it implement Screen you can start to cut/paste from your main class to this screen class. If you have something in the Create method then either put it in the Show method or in the constructor. You then create another Screen for your main menu, options, credits, etc.
Have you main class MyGdxGame extend from Game instead of ApplicationAdapter delete all methods except the create method. In the create method you can load your assets and call your first screen like this setScreen(new MenuScreen()). For changing screens you have several options.
Pass the Game object allong with the screens so you can do game.setScreen(..)
Have some sort of screen manager with public static methods to change screens.
Gdx.app.getApplicationListener can be casted into game. This way you can change screen from anywhere in your LibGDX app. ((Game)Gdx.app.getApplicationListener).setScreen(myScreen)
If you are feeling scared you will destroy functionality, make a backup of you game in its current state. Abstracting code from big classes to new smaller classes is a important task for each programmer so it will be good practice. If you feel at any point that a certain piece of code should belong to another/new class feel free to do so. There are many ways to do things and keeping your code readable and understandable is your number 1 priority.

How do I make a button appear and disappear?Libgdx

I want my button to appear whenever an object reaches a certain position, that object is a sprite that is generated every second:
public void create() {
if(spritePosition>700) {
buttonObj.createButton();
}
}
public void render() {
if (condition==true) {
stage.draw();
}
}
The problem is that when the games starts no Sprite is generated yet, so the result is an error. I'm also thinking of calling the createButton() method on the render method but it would generate a new button every frame because it's called constantly.
A simple way to let your button "disappear" is to just set its position to some position outside of the visible screen area.
For example something like:
buttonObj.setPosition(-1000, -1000);
To make it visible again you can just set the real coordinates again!
How about:
public void create() {
buttonObj.createButton();
buttonObj.setVisible(false);
}
public void render() {
if (condition==true) {
buttonObj.setVisible(true);
}
}
All actors in Scene2d have the setVisible method. simply try :
yourButton.setVisible(true)
or
yourButton.setVisible(false);

What's the right place to dispose a libgdx Screen

Hello I am working out a game and I wonder how to dispose resources as I am experiencing memory problems.
I have something like this:
public SplashScreen implements Screen {
#Override
public void render(float delta) {
}
#Override
public void dispose() {
if (batch != null)
batch.dispose();
batch = null;
}
}
public MapScreen implements Screen {
#Override
public void render(float delta) {
}
#Override
public void show() {
splashScreenInstance.dispose();
}
#Override
public void dispose() {
if (mesh != null)
mesh.dispose();
mesh = null;
}
}
And I am disposing the splash screen as soon as the show method of MapScreen is called. Previously I'd settled the screen to the MapScree. Still the render method of the splashScreenInstance is called and I'd received null pointer exceptions. Why this is so?
I'd expect that once I set another screen, the previous one is no longer rendered. This is not seemingly so. I'd tried disposing right after setting the screen using the game instance, right after the hide method is called on the screen I want to dispose and finally on the show method of the next screen. All of these cases still renders the previous screen a few times before rendering the current one.
I really need to recover memory and also I don't want to test each time (On the render method) for null pointers as this has performance penalties.
Any suggestions?
Thanks
This is how I usually handle this problem:
public SplashScreen implements Screen {
#Override
public void render(float delta) {
// I assume that you have a reference to the game somewhere to switch the screen
game.setScreen(new MapScreen());
dispose();
return;
}
}
I first set the new Screen, then dispose() the current one and then immediately stop any further execution of the current screen via return. This way the current render cycle should be stopped and in the next cycle the render() of your next screen will be called.
Another approach might be to call dispose() in your hide() method of the Screens, because that is going to be the last method being called before the Game will use the next screen. This is especially useful when there could be several different next screens. In that case there will still be only a single place of dispose() and that will be in the hide() method.
Where are you calling setScreen? Since everything should be happening in the rendering thread (even InputListeners) you should be able to call setScreen in your first Screen and then return from the render method. The Game instance will automatically call hide on your first Screen which is where you can call dispose.

Categories

Resources