day 11 – loading screenTag 11 – Ladebildschirm

veröffentlicht am: 11. Dezember 2012

I think it looks somehow kind of professional if the app shows a little loading-screen at start. Of course this only makes sence if you really have things to load there.
Es sieht doch irgendwie professionell aus, wenn die App beim Starten einen kleinen Ladebildschirm anzeigt. Sinnvoll ist das natürlich nur, wenn man auch Daten hat, die man vorher laden kann und die in der ganzen App gebraucht werden.

If we put all our image into one big texture, we’ll need that all the time. Such things we can preload at the beginning.
In Libgdx there is a class called AssetManager for this. We create an object of this in our Game-class so that we can access it from all screens.
As well I added a new Screen called LoadingScreen.

public class TestGame extends Game{
	AssetManager assets;

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

In the constructor of the LoadingScreen we tell the Assetmanger with assets.load(“FILE”,[TYPE OF ASSET].class) which assets should be loaded.

public LoadingScreen(TestGame pGame) {
	game=pGame;

	// which assets do we want to be loaded
	game.assets=new AssetManager();

	game.assets.load("ui/myskin.json", Skin.class);
	game.assets.load("graphics/testPack.atlas",TextureAtlas.class);
	game.assets.load("ui/test.fnt",BitmapFont.class);

}

The assets should be loaded asynchronly while our screen is displayed. Therefore we have to call the method assets.update() in the render()-method. This method as well tells us, when the assets have finished loading.

if(game.assets.update()){
	// all the assets are loaded
	game.setScreen(new SplashScreen(game));
}

If you want to access your textures, etc. in the other screens you can get them with assets.get():

atlas = game.assets.get("graphics/testPack.atlas", TextureAtlas.class);

Now preloading the assets works great, but we want in the (at the moment really short) loading time to show a progressbar. I used these two NinePatches to build one.

The assets for the progressbar have to be loaded the old way.

// load the assets for the loading screen :D
font=new BitmapFont();
batch=new SpriteBatch();
emptyT=new Texture(Gdx.files.internal("load/empty.png"));
fullT=new Texture(Gdx.files.internal("load/full.png"));
empty=new NinePatch(new TextureRegion(emptyT,24,24),8,8,8,8);
full=new NinePatch(new TextureRegion(fullT,24,24),8,8,8,8);

// [...] render():
batch.begin();
empty.draw(batch, 40, 225, 720, 30);
full.draw(batch, 40, 225, game.assets.getProgress()*720, 30);
font.drawMultiLine(batch,(int)(game.assets.getProgress()*100)+"% loaded",400,247,0, BitmapFont.HAlignment.CENTER);
batch.end();

And you get this cool loadingscreen:


Libgdx hat dafür eine Klasse namens AssetManager. Ein Objekt dieser Klasse speichern wir in unserem Game, damit wir von allen Screens drauf zugreifen können.
Außerdem habe ich einen neuen Screen namens loading-Screen hinzugefügt.

public class TestGame extends Game{
	AssetManager assets;

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

Im Loading-Screen geben wir mit assets.load(“FILE”,[TYPE OF ASSET].class) an, welche Assets geladen werden sollen.

public LoadingScreen(TestGame pGame) {
	game=pGame;
	
	// which assets do we want to be loaded
	game.assets=new AssetManager();
		
	game.assets.load("ui/myskin.json", Skin.class);
	game.assets.load("graphics/testPack.atlas",TextureAtlas.class);
	game.assets.load("ui/test.fnt",BitmapFont.class);
	
}

Damit die Assets asynchron geladen werden, muss man in der render() Methode assets.update() aufrufen. Diese liefert netterweise direkt true zurück, wenn die Assets fertig geladen sind.

if(game.assets.update()){
	// all the assets are loaded
	game.setScreen(new SplashScreen(game));
}

In den anderen Screens kann man dann mit assets.get() die vorher geladenen Daten holen.

atlas = game.assets.get("graphics/testPack.atlas", TextureAtlas.class);

Damit während der (momentan noch sehr kurzen) Ladezeit nicht einfach ein leerer Bildschirm ist, hab ich mir mit diesen zwei NinePatches einen Ladebalken gebaut:

Die nötigen Assets muss ich dann natürlich im LoadingScreen auf alte Weise laden:

// load the assets for the loading screen :D
font=new BitmapFont();
batch=new SpriteBatch();
emptyT=new Texture(Gdx.files.internal("load/empty.png"));
fullT=new Texture(Gdx.files.internal("load/full.png"));
empty=new NinePatch(new TextureRegion(emptyT,24,24),8,8,8,8);
full=new NinePatch(new TextureRegion(fullT,24,24),8,8,8,8);

// [...] render():
batch.begin();
empty.draw(batch, 40, 225, 720, 30);
full.draw(batch, 40, 225, game.assets.getProgress()*720, 30);
font.drawMultiLine(batch,(int)(game.assets.getProgress()*100)+"% loaded",400,247,0, BitmapFont.HAlignment.CENTER);
batch.end();

Und schon erhält man diesen coolen Ladebildschirm.

geposted in libgdx

6 Antworten zu “day 11 – loading screenTag 11 – Ladebildschirm

  1. Jan sagt:

    Hey bitowl,

    ich bin es mal wieder :-)
    Ich habe deinen Ladebalken mal zu einem Image gemacht, damit ich anschließend als Actor in die Szene einfügen kann:
    Image fullImage = new Image(full);
    fullImage.addAction(Actions.sizeTo(byfgame.assets.getProgress()*440, 40));
    stage.addActor(fullImage);

    Nun verändert sich aber die Größe des Ladebalkens nicht. Ich gehe jetzt mal davon aus, dass die Action nur einmal ausgeführt wird, richtig? Wie kann man daraus eine Animation machen?

    Grüße Jan

    • bitowl sagt:

      wenn du die Größe des Ladenbalkens über eine bestimmte Zeit verändern wolltest, könnest du fullImage.addAction(Actions.sizeTo(440, 40,4.0f)); nutzen (für vier Sekunden). [einfach nur nützlich zu wissen]

      da du aber in jedem Frame den aktuellen Status des Ladens abfragen willst und das Bild dementsprechend verändern, musst du diese Zeile in die render()-Methode packen, damit eine “Animation” entsteht.

  2. Jan sagt:

    Hm klingt einfach, bekomme ich leider trotzdem nicht hin :( Ich habe jetzt so lang in der render methode rumgeschoben bis kaum noch etwas läuft. bisher konnte ich immer nur verzeichnen, dass die progresszahl richtig angegeben wird jedoch die anzeige immer auf 0 stehen blieb (obwohl ja von der gleichen variable gefütter):

    batch.setProjectionMatrix(camera.combined); // tells the batch, where to draw
    stage.getSpriteBatch().begin();
    stage.getSpriteBatch().end();
    batch.begin();
    stage.setViewport(byfgame.resulutionX,byfgame.resulutionY,false);

    // empty.draw(batch, 10, 30, 460, 25);
    // full.draw(batch, 10, 30, byfgame.assets.getProgress()*460, 25);
    int progress = (int)(byfgame.assets.getProgress()*100);
    fullImage.addAction(Actions.sizeTo(progress*440, 40));
    font.drawMultiLine(batch,progress+”% “,240,60,0, BitmapFont.HAlignment.CENTER);
    stage.act(delta);
    stage.draw();
    batch.end();

    • Jan sagt:

      Hab es zum laufen bekommen. Nach dem setzen der neuen Größe noch ein invalidate() dann klappt es

      • tommybee sagt:

        I am a fan of your articls nowadays…
        I thank you for all of these stuffs

        In LoadingScreen … All the stuffs are mixed up while loading progress bar processing…
        So, my idea is now to just clear screen first in the render method in the file like below
        @Override
        public void render(float delta) {
        //clears the buffer
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        ….rest of codes
        thanks

  3. John Master sagt:

    Great Tutorial!

Hinterlasse eine Antwort