Tag 4 – Animationen mit scene2d

veröffentlicht am: 4. Dezember 2012

Heute wollen wir uns mit scene2d beschäftigen.
scene2d kann uns die Arbeit für einfache Animationen (wie das Ein- und Ausblenden von Bildern) abnehmen. In scene2d gibt es drei wichtige Objekte:
Stage ist ein Objekt, das man einmal erzeugt wird und eine ganze Szene verwaltet (z.B. das Menü oder das komplette Ingame).
Actor ist ein 2D-Objekt, das von der Stage verwaltet wird. Ein Actor ist quasi ein Bild, das allerdings noch viel mehr Informationen wie Position, Skalierung, Rotierung, Einfärbung o.ä. speichert.
Actors kann man zusätzlich noch Actions mitgeben. Actions sind Animationen wie Verschieben, Vergrößern, Drehen oder Ausblenden, die dann (falls gewünscht auch mit gewisser Verzögerung) auf dem Actor angewendet werden.

Die Stage bringt ihren eigenen SpriteBatch mit, daher brauchen wir unseren jetzt erstmal nicht.
Wir nutzen Image-Objekte als Actor, da es direkt eine Textur zum Actor macht.

Wir benötigen nun folgenden Code, um den Baum mit der Weihnachtskugel dran zu erzeugen:

public class TestGame implements ApplicationListener {
	
	Texture tree;
	TextureRegion christmasTree;
	Texture ball;
	OrthographicCamera camera;
	Stage stage;
	
	@Override
	public void create() {
		// load assets
		tree=new Texture(Gdx.files.internal("graphics/tree.png"));
		christmasTree=new TextureRegion(tree, 0, 0, 450,730);
		ball=new Texture(Gdx.files.internal("graphics/ball.png"));
		
		// create viewport
		camera=new OrthographicCamera();
		camera.setToOrtho(false, 800,480);
		
		stage=new Stage();
		stage.setCamera(camera);
		
		// our christmas tree
		Image ctree=new Image(christmasTree);
		ctree.setSize(296, 480); // scale the tree to the right size
		ctree.setPosition(400 - 148, 0); // center the tree
		stage.addActor(ctree);

		Image ballImage=new Image(ball);
		ballImage.setPosition(400 - 148+60, 170);
		
		stage.addActor(ballImage);

	}

	
	@Override
	public void render() {		
	
		Gdx.gl.glClearColor(1,1,1, 1);
		Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
		
		// update the stage
		stage.act();
		// draw the stage
		stage.draw();
	}

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

	@Override
	public void pause() {
	}

	@Override
	public void resume() {
	}
	
	@Override
	public void dispose() {
		// dispose all the trash :P
		tree.dispose();
		ball.dispose();
		stage.dispose();
	}
}

Wichtig hierbei ist, dass wir alle Texturen und die Stage in dispose() wieder wegwerfen. Später wird auch noch der Fakt wichtig, dass wir vor stage.draw(); die Methode stage.act() aufrufen. In dieser Methode werden nämlich alle Animationen behandelt.

Wir wollen nun, dass der Ball erst langsam erscheint.
Dafür setzen wir zuerst den Alpha-Wert des Bildes auf 0, damit es unsichtbar ist und fügen danach die FadeIn-Action (erscheinen in 2 Sekunden) hinzu:

ballImage.setColor(1,1,1,0);
ballImage.addAction(Actions.fadeIn(2));

Die Klasse Actions stellt viele Aktionen statisch zur Verfügung (hier eine Übersicht).

Wir können auch direkt zwei Aktionen hinzufügen, die werden dann gleichzeitig ausgeführt.

ballImage.setOrigin(32,32);
ballImage.setColor(1,1,1,0);
ballImage.addAction(Actions.fadeIn(2));
ballImage.addAction(Actions.rotateBy(360,2));

Hier setzen wir zuerst den Ursprung im Bild (die Mitte) und rotieren dann gleichzeitig um diesen Punkt, während der Ball eingeblendet wird.
Das selbe könnte man auch so schreiben:

ballImage.addAction(Actions.parallel(Actions.fadeIn(2),Actions.rotateBy(360,2)));

Das Gegenteil davon ist die Aktionen nacheinander ablaufen zu lassen:

ballImage.addAction(Actions.sequence((Actions.fadeIn(2),Actions.rotateBy(360,2)));

Wenn man dann noch den Befehl delay() hinzunimmt, der einfach eine bestimmte Zeit wartet, kann man damit ziemlich komplexe Animationen bauen.

		
// our christmas tree
Image ctree=new Image(christmasTree);
ctree.setSize(296, 480); // scale the tree to the right size
ctree.setPosition(-300,0);
//ctree.setPosition(400 - 148, 0); // center the tree
ctree.addAction(Actions.moveTo(400-148, 0,1f));
	
stage.addActor(ctree);
	

Image ballImage=new Image(ball);
ballImage.setPosition(400 - 148+60, 170);
		
ballImage.setOrigin(32,32);
ballImage.setColor(1,1,1,0);
ballImage.addAction(Actions.sequence(Actions.delay(1),Actions.parallel(Actions.fadeIn(1),Actions.rotateBy(360,1))));

hier wird zuerst der Weihnachtsbaum für eine Sekunde von links eingeflogen und dann erscheint die Kugel, während sie sich dreht.

Aufgabe für heute ist es diesen komplexeren Animationscode zu verstehen 😀 (Schneeflocke von openclipart.org)

public class TestGame implements ApplicationListener {
	
	Texture tree;
	TextureRegion christmasTree;
	Texture ball;
	Texture snow;
	OrthographicCamera camera;
	Stage stage;
	
	
	@Override
	public void create() {
		// load assets
		tree=new Texture(Gdx.files.internal("graphics/tree.png"));
		christmasTree=new TextureRegion(tree, 0, 0, 450,730);
		ball=new Texture(Gdx.files.internal("graphics/ball.png"));
		snow=new Texture(Gdx.files.internal("graphics/snow.png"));
		
		// create viewport
		camera=new OrthographicCamera();
		camera.setToOrtho(false, 800,480);
		
		stage=new Stage();
		stage.setCamera(camera);
		
		// our christmas tree
		Image ctree=new Image(christmasTree);
		ctree.setSize(296, 480); // scale the tree to the right size
		ctree.setPosition(-300,0);
		ctree.addAction(Actions.moveTo(400-148, 0,1f));
		
		stage.addActor(ctree);
		

		Image ballImage=new Image(ball);
		ballImage.setPosition(400 - 148+60, 170);
		
		ballImage.setOrigin(32,32);
		ballImage.setColor(1,1,1,0);
		ballImage.addAction(Actions.sequence(Actions.delay(1),Actions.parallel(Actions.fadeIn(1),Actions.rotateBy(360,1))));
	
		
		stage.addActor(ballImage);
		
		// create the snowflakes
		for(int i=0;i<10;i++){
			spawnSnowflake();
		}

	}

	public void spawnSnowflake(){
		final Image snowflake=new Image(snow);
		snowflake.setOrigin(64,64);
		int x=(int) (Math.random()*800);
		snowflake.setPosition(x,480);
		snowflake.setScale((float) (Math.random()*0.8f+0.2f));
		// animate the snowflake randomly
		snowflake.addAction(Actions.parallel(
				Actions.forever(Actions.rotateBy(360,(float) (Math.random()*6))),
				Actions.sequence(Actions.moveTo(x,0,(float) (Math.random()*15)),Actions.fadeOut((float) (Math.random()*1)),
					new Action() { // we can define custom actions :)
					
					@Override
					public boolean act(float delta) {
						snowflake.remove(); // delete this snowflake
						spawnSnowflake(); // spawn a new snowflake
						return false;
					}
				}
				)));
		stage.addActor(snowflake);
	}
	
	@Override
	public void render() {		
	
		Gdx.gl.glClearColor(1,1,1, 1);
		Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
		
		// update the stage
		stage.act();
		// draw the stage
		stage.draw();
	}

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

	@Override
	public void pause() {
	}

	@Override
	public void resume() {
	}
	
	@Override
	public void dispose() {
		// dispose all the trash :P
		tree.dispose();
		ball.dispose();
		snow.dispose();
		stage.dispose();
	}

}

Nun muss ich weiter rumspielen und schauen, was man sonst noch so alles cooles mit scene2d machen kann.
Falls irgendwas unverständlich war, frag nach! 😉

geposted in libgdx

5 Antworten zu “Tag 4 – Animationen mit scene2d”

  1. Katoffel sagt:

    Ist die „stage.act();“ Multi-Therading stable ? weil das dürfte ja kein OGL enthalten …
    mfG Katoffel

    • bitowl sagt:

      Das würde ich so vermuten. Allerdings solltest du dann die Methode stage.act(float deltaT) benutzen und die vergangene Zeit, seit dem letzen Aufruf mitgeben.
      bitowl

  2. andfax sagt:

    Sorry ich bin noch ein relativer Anfänger .
    Wie haben sie es hinbekommen, dass der Drehpunkt in der Mitte des Objekts ist ?
    Ich würde mich über eine Antwort freuen.

  3. Rupert sagt:

    If using Libgdx 1.3.1
    There is no more stage.setCamera(camera)
    use
    stage.getViewport().setCamera(camera)

    Thanks for great tutorials.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.