Question

I am creating my first game in LibGDX and for my splash screen, I am making use of Universal tween engine. I am using Aurelien Ribon's demo except for my own images. The problem occurs when the splash screen ends, it Gives a call to Launcher and from there on, it call the various classes extending the Test class. I found no clean way of giving the control to my LevelSelector class which implements screen and uses stage for rendering. Whenever the control goes to my class, it calls its show() and without entering the render(), it calls hide() . This continues till application is stopped. All the while the App class (i.e. the main class) render() continues to be called continuosly. i have figured out a work around for this but it causes memory problems and is making the game slow. can anyone please tell me how to stop the rendering of App & transfer control to my class?

My workaround works as follows :

  1. When click on Play (extends test), in its initialize static flag of App : inPlay is set.
  2. in App render(), if isPlay is set, setScreen as LevelSelector.
  3. in LevelSelector, if click on any level, set static flag of App : inLevel.
  4. in App render(), if inLevel is set, setscreen to that level.

this works, but LevelSelector render, App render & level render are all being called even when after screen is set to a level which causes delays and memory problems in my app,

Is there a solution to this problem without using the work around?

My Code :

//APP class

import aurelienribon.tweenengine.BaseTween;
import aurelienribon.tweenengine.Tween;
import aurelienribon.tweenengine.TweenCallback;

import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;

/**
 * @author Aurelien Ribon | http://www.aurelienribon.com/
 */
public class App extends Game {
private SplashScreen splashScreen;
private Launcher launcherScreen;
private boolean isLoaded = false;
static boolean inPlay = false;
static boolean levelStarted = false;
static int levelIndex;
LevelSelector ls;
Screen screen;
Level level;

@Override
public void create() {
    System.out.println("********App create********");
    Tween.setWaypointsLimit(10);
    Tween.setCombinedAttributesLimit(3);
    Tween.registerAccessor(Sprite.class, new SpriteAccessor());

    Assets.inst().load("data/splash/pack", TextureAtlas.class);
    Assets.inst().load("data/launcher/pack", TextureAtlas.class);
    Assets.inst().load("data/test/pack", TextureAtlas.class);
    Assets.inst().load("data/arial-16.fnt", BitmapFont.class);
    Assets.inst().load("data/arial-18.fnt", BitmapFont.class);
    Assets.inst().load("data/arial-20.fnt", BitmapFont.class);
    Assets.inst().load("data/arial-24.fnt", BitmapFont.class);

}

@Override
public void dispose() {
    Assets.inst().dispose();
    if (splashScreen != null) splashScreen.dispose();
    if (launcherScreen != null) launcherScreen.dispose();
    if(screen != null) screen.dispose();
}

@Override
public void render() {

    if (isLoaded) {
        screen = null;
        if (splashScreen != null) splashScreen.render();
       if(inPlay && levelStarted==false){

            splashScreen = null;
            launcherScreen = null;
            Gdx.graphics.setContinuousRendering(false);
            Gdx.input.setInputProcessor(pspt.stage);
            this.setScreen(ls);
        }
        else if(inPlay && levelStarted)
        {
            level.setLevelIndex(levelIndex);
            screen = level.getLevelScreen();
            if(screen != null)
            {
                splashScreen = null;
                launcherScreen = null;
                Gdx.graphics.setContinuousRendering(false);
                this.setScreen(screen);
            }
        }
        if (launcherScreen != null) launcherScreen.render();

    } else {
        if (Assets.inst().getProgress() < 1) {
            Assets.inst().update();  //update returns true when asset manager finishes loading all assets
        } else {
            launch();
            isLoaded = true;
            inPlay = false;
        }
    }
}

@Override public void resize(int width, int height) {}
@Override public void pause() {}
@Override public void resume() {}

private void launch() {
    System.out.println("********App Launch********");
    ls = new LevelSelector(this);
    screen = null;
    level = new Level();
    splashScreen = new SplashScreen(new TweenCallback() {
        @Override public void onEvent(int type, BaseTween source) {
            Test[] tests = new Test[] {
                    new Info(),
                    new Help(),
                    new PlayScreen()
            };

            splashScreen.dispose();
            splashScreen = null;
            launcherScreen = new Launcher(tests);
        }
    });
}
}


//TEST class

public abstract class Test {
private final TweenManager tweenManager = new TweenManager();
private final TextureAtlas atlas;
private final Sprite background;
private final Sprite veil;
private final Sprite infoBack;
private final List<Sprite> dots = new ArrayList<Sprite>(50);
private boolean[] useDots;
private Callback callback;

protected final OrthographicCamera camera = new OrthographicCamera();
protected final SpriteBatch batch = new SpriteBatch();
protected final Random rand = new Random();
protected final BitmapFont font;
protected final float wpw = 10;
protected final float wph = 10 * Gdx.graphics.getHeight() / Gdx.graphics.getWidth();
protected Sprite[] sprites;

public Test() {
    System.out.println("********Test Constructor********");
    atlas = Assets.inst().get("data/test/pack", TextureAtlas.class);
    background = atlas.createSprite("background");
    veil = atlas.createSprite("white");
    infoBack = atlas.createSprite("white");

    int w = Gdx.graphics.getWidth();
    if (w > 600) font = Assets.inst().get("data/arial-24.fnt", BitmapFont.class);
    else font = Assets.inst().get("data/arial-16.fnt", BitmapFont.class);
}

// -------------------------------------------------------------------------
// Abstract API
// -------------------------------------------------------------------------

public abstract String getTitle();
public abstract String getInfo();
public abstract String getImageName();
public abstract InputProcessor getInput();
protected abstract void initializeOverride();
protected abstract void disposeOverride();
protected abstract void renderOverride();

// -------------------------------------------------------------------------
// Public API
// -------------------------------------------------------------------------

public static interface Callback {
    public void closeRequested(Test source);
}

public void setCallback(Callback callback) {
    System.out.println("********Test setCallback********");
    this.callback = callback;
}

public void initialize() {
    System.out.println("********Test initialize********");
    if (isCustomDisplay()) {
        initializeOverride();
        return;
    }

    camera.viewportWidth = wpw;
    camera.viewportHeight = wph;
    camera.update();

    background.setSize(wpw, wpw * background.getHeight() / background.getWidth());
    background.setPosition(-wpw/2, -background.getHeight()/2);

    veil.setSize(wpw, wph);
    veil.setPosition(-wpw/2, -wph/2);

    infoBack.setColor(0, 0, 0, 0.3f);
    infoBack.setPosition(0, 0);

    initializeOverride();

    Tween.set(veil, SpriteAccessor.OPACITY).target(1).start(tweenManager);
    Tween.to(veil, SpriteAccessor.OPACITY, 0.5f).target(0).start(tweenManager);
}

public void dispose() {
    System.out.println("###Test dispose###");
    tweenManager.killAll();
    dots.clear();
    sprites = null;
    useDots = null;

    disposeOverride();
}

public void render() {
    System.out.println("********Test render********");
    if(App.inPlay == false)
    {
        if (isCustomDisplay()) {
            System.out.println("CustomDisplay : True");
            renderOverride();
            return;
        }    
        // update

        tweenManager.update(Gdx.graphics.getDeltaTime());

        for (int i=0; i<dots.size(); i++) {
            if (dots.get(i).getScaleX() < 0.1f) {
                dots.remove(i);
            }
        }

        // render
        GLCommon gl = Gdx.gl;
        gl.glClearColor(1, 1, 1, 1);
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        gl.glEnable(GL10.GL_BLEND);
        gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);

        int w = Gdx.graphics.getWidth();
        int h = Gdx.graphics.getHeight();

        batch.setProjectionMatrix(camera.combined);
        batch.begin();
        batch.disableBlending();
        background.draw(batch);
        batch.enableBlending();
        for (int i=0; i<dots.size(); i++) dots.get(i).draw(batch);
        for (int i=0; i<sprites.length; i++) sprites[i].draw(batch);
        batch.end();
        System.out.println("********Test call renderOverride********");
        renderOverride();

        if (getInfo() != null) {
            int padding = 15;
            BitmapFont.TextBounds bs = font.getWrappedBounds(getInfo(), w - padding*2);
            infoBack.setSize(w, bs.height + padding*2);
            font.setColor(Color.WHITE);

            batch.getProjectionMatrix().setToOrtho2D(0, 0, w, h);
            batch.begin();
            infoBack.draw(batch);
            font.drawWrapped(batch, getInfo(), padding, bs.height + padding, w - padding*2);
            batch.end();
        }

        if (veil.getColor().a > 0.1f) {
            batch.setProjectionMatrix(camera.combined);
            batch.begin();
            veil.draw(batch);
            batch.end();
        }
    }
}

// -------------------------------------------------------------------------
// Helpers
// -------------------------------------------------------------------------

protected boolean isCustomDisplay() {
    return false;
}

protected void forceClose() {
    System.out.println("#######Test forceClose########");
    if (callback != null) callback.closeRequested(this);
}

protected void createSprites(int cnt) {
    System.out.println("********Test create Sprites : "+cnt+"********");
    sprites = new Sprite[cnt];
    useDots = new boolean[cnt];

    for (int i=0; i<cnt; i++) {
        int idx = rand.nextInt(400)/100 + 1;
        sprites[i] = atlas.createSprite("sprite" + idx);
        sprites[i].setSize(1f, 1f * sprites[i].getHeight() / sprites[i].getWidth());
        sprites[i].setOrigin(sprites[i].getWidth()/2, sprites[i].getHeight()/2);
        useDots[i] = false;
    }
}

protected void center(Sprite sp, float x, float y) {
    sp.setPosition(x - sp.getWidth()/2, y - sp.getHeight()/2);
}

protected void enableDots(int spriteId) {
    useDots[spriteId] = true;

    Tween.call(dotCallback)
    .delay(0.02f)
    .repeat(-1, 0.02f)
    .setUserData(spriteId)
    .start(tweenManager);
}

protected void disableDots(int spriteId) {
    useDots[spriteId] = false;
}

private final Vector2 v2 = new Vector2();
private final Vector3 v3 = new Vector3();
protected Vector2 touch2world(int x, int y) {
    v3.set(x, y, 0);
    camera.unproject(v3);
    return v2.set(v3.x, v3.y);
}

// -------------------------------------------------------------------------
// Helpers
// -------------------------------------------------------------------------

private final TweenCallback dotCallback = new TweenCallback() {
    @Override
    public void onEvent(int type, BaseTween source) {
        System.out.println("********Test dotCallback : onEvent********");
        int spriteId = (Integer) source.getUserData();

        if (useDots[spriteId] == false) source.kill();
        Sprite sp = sprites[spriteId];

        Sprite dot = atlas.createSprite("dot");
        dot.setSize(0.2f, 0.2f);
        dot.setOrigin(0.1f, 0.1f);
        dot.setPosition(sp.getX(), sp.getY());
        dot.translate(sp.getWidth()/2, sp.getHeight()/2);
        dot.translate(-dot.getWidth()/2, -dot.getHeight()/2);
        dots.add(dot);
        Tween.to(dot, SpriteAccessor.SCALE_XY, 1.0f).target(0, 0).start(tweenManager);
    }
};

// -------------------------------------------------------------------------
// Dummy
// -------------------------------------------------------------------------

public static final Test dummy = new Test() {
    @Override public String getTitle() {
        System.out.println("********Test dummy getTitle********");
        return "Dummy test";}
    @Override public String getInfo() {
        System.out.println("********Test dummy getInfo********");
        return null;}
    @Override public String getImageName() {
        System.out.println("********Test dummy getImageName********");
        return null;}
    @Override public InputProcessor getInput() {
        System.out.println("********Test dummy getInput********");
        return null;}
    @Override protected void initializeOverride() {System.out.println("********Test dummy initOverride********");}
    @Override protected void disposeOverride() {System.out.println("********Test dummy disposeOverride********");}
    @Override protected void renderOverride() {System.out.println("********Test dummy renderOverride********");}
};
}


//LevelSelector

public class LevelSelector implements Screen {

private Skin skin;
Stage stage;
private Table container;
Game game;
//  Level_1_1 level1;
PagedScrollPane scroll ;
int rank=0,leveldone;
Table starTable;
Utils Utils;

public LevelSelector(Game game){
    //      System.out.println("########In pagedScrollPaneTest construct (App)##########");
    Gdx.input.setInputProcessor(stage);
    this.game = game;
    Utils = new Utils();

    stage = new Stage(0, 0, false);
    skin = new Skin(Gdx.files.internal("data/uiskin.json"));
    skin.add("top", skin.newDrawable("default-round", Color.RED), Drawable.class);
    skin.add("star-filled", skin.newDrawable("white", Color.YELLOW), Drawable.class); 
    skin.add("star-unfilled", skin.newDrawable("white", Color.GRAY), Drawable.class);

    Gdx.input.setInputProcessor(stage);

    container = new Table();
    stage.addActor(container);
    container.setFillParent(true);

    scroll= new PagedScrollPane();
    scroll.setFlingTime(0.1f);
    scroll.setPageSpacing(25);
    int c = 1;
    for (int l =0; l < 5; l++) {
        Table levels = new Table().pad(50);
        levels.defaults().pad(20, 40, 20, 40);
        for (int y = 0; y <3; y++) {
            levels.row();
            for (int x = 0; x < 1; x++) {
                levels.add(getLevelButton(c++)).expand().fill();
            }
        }
        scroll.addPage(levels);
    }
    container.add(scroll).expand().fill();

}

public void resize (int width, int height) {
    stage.setViewport(width, height, true);
}

public void dispose () {
    System.out.println("In selector dispose ####");
    Gdx.input.setInputProcessor(null);
    stage.dispose();
    skin.dispose();
}

public boolean needsGL20 () {
    return false;
}

/**
 * Creates a button to represent the level
 * 
 * @param level
 * @return The button to use for the level
 */
public Button getLevelButton(int level) {
    Button button = new Button(skin);
    ButtonStyle style = button.getStyle();
    style.up =  style.down = null;

    // Create the label to show the level number
    Label label = new Label(Integer.toString(level), skin);
    label.setFontScale(2f);
    label.setAlignment(Align.center);       

    // Stack the image and the label at the top of our button
    button.stack(new Image(skin.getDrawable("top")), label).expand().fill();

    // Randomize the number of stars earned for demonstration purposes
    int stars = rank;
    starTable = new Table();
    int j=level;
    starTable.defaults().pad(5);

    if (Utils.prefs.getInteger("rank"+j) >= 0) {
        for (int star = 0; star < 3; star++) {
            if (Utils.prefs.getInteger("rank"+j) > star && level== Utils.prefs.getInteger("level"+j)) {
                System.out.println("\n\nHAd saved option Level:: "+Utils.prefs.getInteger("level"+j));
                System.out.println("HAd saved option Rank :: "+Utils.prefs.getInteger("rank"+j));
                starTable.add(new Image(skin.getDrawable("star-filled"))).width(20).height(20);
            } 
            else {
                starTable.add(new Image(skin.getDrawable("star-unfilled"))).width(20).height(20);
            }
        }           
    }

    button.row();
    button.add(starTable).height(30);

    button.setName("level" + Integer.toString(level));
    button.addListener(levelClickListener);
    return button;
}

/**
 * Handle the click - in real life, we'd go to the level
 */
public ClickListener levelClickListener = new ClickListener() {
    @Override
    public void clicked (InputEvent event, float x, float y) {
        System.out.println("Click: " + event.getListenerActor().getName());
        String levelSelected = event.getListenerActor().getName();
        if(levelSelected.equalsIgnoreCase("level1"))
        {
            App.levelStarted = true;
            game.dispose();
            App.whichLevel = levelSelected;
            App.levelIndex = 1;
        }
        if(levelSelected.equalsIgnoreCase("level2"))
        {
            App.levelStarted = true;
            game.dispose();
            App.whichLevel = levelSelected;
            App.levelIndex = 2;
        }
    }
};


@Override
public void show() {
    System.out.println("########In pagedScrollPaneTest show##########");
    render(Gdx.graphics.getDeltaTime());
}

@Override
public void hide() {
    System.out.println("########In pagedScrollPaneTest hide##########");
}

@Override
public void render(float delta) {
    GLCommon gl = Gdx.gl;
    gl.glClearColor(1, 1, 1, 1);
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
    Gdx.input.setInputProcessor(stage);
    //      System.out.println("########In pagedScrollPaneTest renderer(float)##########");
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

    stage.act();
    stage.act(Gdx.graphics.getDeltaTime());
    stage.draw();

    Table.drawDebug(stage);
}

@Override
public void pause() {}
@Override
public void resume() {}

}

//PlayScreen
public class PlayScreen extends Test {
private final TweenManager tweenManager = new TweenManager();

@Override
public String getTitle() {
    return "Play";
}

@Override
public String getInfo() {
    return "Select which level you want to play.";
}

@Override
public String getImageName() {
    return "tile-path";
}

@Override
public InputProcessor getInput() {
    return null;
}

@Override
protected void initializeOverride() {
    System.out.println("#####Play Screen#####");
    App.inPlay = true;
}

@Override
protected void disposeOverride() {
    tweenManager.killAll();
    super.dispose();

}

@Override
protected void renderOverride() {
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
    tweenManager.update(Gdx.graphics.getDeltaTime());
}
}
Was it helpful?

Solution

I found out the problem in my code. Overriding the render() method of class extending Game would cause that render to be called ahead of each screen's render. This would also cause plenty of memory issues as at a time 3 render methods were being called : 1>Game class 2>Test class 3>Screen extending Test class.

I solved the problem by creating a new MainScreen class which extends Screen and in it I performed all the tasks which was being done in the class extending Game.

Now at any given time, only 1 render method gets called and the game runs a lot faster. This also reduced my code as I now longer have to setScreen in Game's render but can follow the normal flow.

GAME CLASS

import com.badlogic.gdx.Game;

public class PacketJourney extends Game {

    @Override
    public void create() 
    {
        setScreen(new MainScreen(this));
    }   
}

MainScreen class

import aurelienribon.tweenengine.BaseTween;
import aurelienribon.tweenengine.Tween;
import aurelienribon.tweenengine.TweenCallback;

import com.badlogic.gdx.Screen; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.TextureAtlas;

public class MainScreen implements Screen { private SplashScreen splashScreen; private ScreenLauncher launcherScreen; Utils utils;

private boolean isLoaded = false; public MainScreen() { utils = new Utils(null); } public MainScreen(PacketJourney game) { utils = new Utils(game); } @Override public void render(float delta) { if (isLoaded) { if (splashScreen != null) splashScreen.render(); if (launcherScreen != null) launcherScreen.render(); } else { if (Assets.inst().getProgress() < 1) { Assets.inst().update(); //update returns true when asset manager finishes loading all assets } else { launch(); isLoaded = true; } } } @Override public void resize(int width, int height) { } @Override public void show() { Tween.setWaypointsLimit(10); Tween.setCombinedAttributesLimit(3); Tween.registerAccessor(Sprite.class, new SpriteAccessor()); Assets.inst().load("data/splash/pack", TextureAtlas.class); Assets.inst().load("data/launcher/pack", TextureAtlas.class); Assets.inst().load("data/launcher/screenLauncher", TextureAtlas.class); Assets.inst().load("data/arial-16.fnt", BitmapFont.class); Assets.inst().load("data/arial-18.fnt", BitmapFont.class); Assets.inst().load("data/arial-20.fnt", BitmapFont.class); Assets.inst().load("data/arial-24.fnt", BitmapFont.class); } @Override public void hide() { } @Override public void pause() { } @Override public void resume() { } private void launch() { splashScreen = new SplashScreen(new TweenCallback() { @Override public void onEvent(int type, BaseTween source) { String str= ""; switch(type) { case TweenCallback.BEGIN : str = "BEGIN"; break; case TweenCallback.COMPLETE : str = "COMPLETE"; break; case TweenCallback.END : str = "END"; break; case TweenCallback.ANY : str = "ANY"; break; } splashScreen.dispose(); splashScreen = null; if(utils.game != null) launcherScreen = new ScreenLauncher(utils.screens,utils.spriteNames,utils); } }); } @Override public void dispose() { Assets.inst().dispose(); if (splashScreen != null) splashScreen.dispose(); if (launcherScreen != null) launcherScreen.dispose(); } }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top