Posts Tagged ‘animation4j’

Toasting with LibGDX Scene2D and Animation4j

Sunday, March 4th, 2012

For our latest Vampire Runner update we changed to use LibGDX scene2d instead Android GUI. The main reason for the change is that we wanted to use a common GUI API for Android and PC, and sadly we can't do that using Android API. With LibGDX scene2d we can code once and run in both platforms.

In particular, the toast feature of the Android API was really interesting to have and we want to share how we implemented it using LibGDX scene2d.

Toasting

A toast is defined as a scene2d Window that shows some text and disappear after a while, this is a pseudo code to give the idea of how to create that toast window:

Actor toast(String text, float time, Skin skin) {
	Window window = new Window(skin);
	window.add(new Label(text, skin));
	...
	window.action(new Action() {
		act(float delta) {
			// update the animation
			// if the animation is finished, we remove the window from the stage.
		}
	});
	...
	return window;
}

To animate the toast, we create a TimelineAnimation using animation4j defining that the window should move from outside the screen to inside the screen, wait some time and then go out of the screen again. The code looks like this:

TimelineAnimation toastAnimation = Builders.animation( //
	Builders.timeline() //
		.value(Builders.timelineValue(window, Scene2dConverters.actorPositionTypeConverter) //
			.keyFrame(0f, new float[] { window.x, outsideY }) //
			.keyFrame(1f, new float[] { window.x, insideY }) //
			.keyFrame(4f, new float[] { window.x, insideY }) //
			.keyFrame(5f, new float[] { window.x, outsideY }) //
		) //
	) //
	.started(true) //
	.delay(0f) //
	.speed(5f / time) //
	.build();

That code creates a new animation which modifies the position of the Window each time update() method is called.

Of course, you can animate the Window using LibGDX custom Actions or another animation framework like Universal Tween Engine, that is up to you.

If you want to see the code itself, you can see the Actor factory named Actors at our Github of commons-gdx.

In our subclass of Game, we added an empty Stage updated in each render() method, and a toast(string) method which creates a toast as explained before using default Skin and time.

MyGame extends Game {

	Stage stage;
	float defaultTime;
	Skin defaultSkin;

	render() {
		// all our game update and render logic
		...
		stage.act(delta);
		stage.draw();
	}

	toast(String text) {
		stage.add(Actors.toast(text, defaultTime, defaultSkin);
	}
}

So, if we want to toast about something, we only have to call game.toast("something") and voilá.

You can see a running example of this, you can run the Gui.Scene2dToastPrototype of our prototypes webstart (recommended), or watch the next video:

Conclusion

Despite being a bit incomplete and buggy yet, scene2d API is almost easy to use and it is great if you want to do simple stuff.

Using scene2d is great for our simple need of GUI interfaces because we can quickly test all the stuff in PC. In Vampire Runner we are using scene2d for the feedback dialog, the new version available dialog and for the change username screen.

An interesting thing to have in mind when using scene2d API is that you can make your own Skin to achieve a more integrated look and feel.

As always, hope you like the post and could be of help.

VN:F [1.9.22_1171]
Rating: 3.4/5 (5 votes cast)

Some changes to animation4j to clean the API

Friday, November 25th, 2011

Lately, animation4j API received some love by removing a lot of unused classes and improving a bit how things are used. Now both Transitions and Timelines (hence the animations based time lines) work over mutable objects only.

To illustrate some of the changes there are two examples shown in the next sections.

Transitions

This example shows how to use new API to create a Transition:

	// a mutable object example, if you use LibGDX this could be a Vector2

	class MyObject {
		float a, b;
	}

	// we need a TypeConverter for that object, as explained in a previous post.
	// an instance of this class could be reused since holds no internal state

	class MyObjectTypeConverter implements TypeConverter {
		@Override
		public float[] copyFromObject(MyObject o, float[] x) {
			if (x == null)
				x = new float[variables()];
			x[0] = o.a;
			x[1] = o.b;
			return x;

		}

		@Override
		public MyObject copyToObject(MyObject o, float[] x) {
			if (o == null)
				o = new MyObject();
			o.a = x[0];
			o.b = x[1];
			return o;
		}

		@Override
		public int variables() {
			return 2;
		}
	}

	// now, to create a transition to be used we use the Transitions class which provides
	// some builder methods

	MyObjectTypeConverter myObjectTypeConverter = new MyObjectTypeConverter();
	MyObject myObject = new MyObject();

	Transition transition = Transitions.transition(myObject, myObjectTypeConverter) //
			.start(0f, 50f) //
			.end(1f, 50f, 100f) // (time, value1, value2, ....)
			.build();

	transition.update(0.5f);

	// this should print 25,75 since the update of the transition updated the object 
	// directly.
	System.out.println("" + myObject.a + "," + myObject.b); 

TransitionBuilder

TransitionBuilder changed its interface to create transitions specifying the object to be modified. It now also provides some methods which lets you specify the start and end values with a float[] by using var args, it is convenient if you want to write less code (you could avoid new Object(..)) but will generate garbage as new Object() does. The recommendation to avoid that is to reuse the end/start values, for example, if you want a Transition of a color from yellow to red, create the yellow and red colors and store them somewhere (maybe static final fields) and reuse them each time you need a new Transition.

Animations

This example shows how to create an Animation which uses a Timeline:

	// using the same classes we defined before
	MyObjectTypeConverter myObjectTypeConverter = new MyObjectTypeConverter();
	MyObject myObject = new MyObject();

	Animation animation = Builders.animation(Builders.timeline() //
			.value(Builders.timelineValue(myObject, myObjectTypeConverter) //
				.keyFrame(0f, new MyObject(50, 50)) // at the beginning of the Timeline, the object should be at 50, 50
				.keyFrame(2f, new MyObject(100, 100)) // two seconds after that, it should be at 100, 100
				.keyFrame(10f, new MyObject(200, 200)) // eight seconds after that, it should be at 200, 200
		)) //
		.speed(2f) // we want the animation to run at double speed
		.build();

	animation.start(1); // starts the animation with 1 iteration.

	animation.update(1f);

	// this should print 100,100 since the update we asked for double speed.
	System.out.println("" + myObject.a + "," + myObject.b); 

	animation.update(4f);

	// this should print 200,200
	System.out.println("" + myObject.a + "," + myObject.b);

(note: if you want more examples, there is an examples project with the project, some of the examples needs to be simplified but the idea of how to used animations and transitions should be clear enough)

Animation interface is very rich, it has methods to start the animation specifying the iterations you want, if you want to alternate directions or not, etc.

Immutable Objects

As I said before, animations and transitions can only be performed over mutable objects. This means you can't animate a java.lang.Float or a java.awt.Color since you have no way to change their values without creating a new instance. To animate immutable objects the idea is to create your own mutable objects with the corresponding variables, animate them and then, when needed, create a new instance of the required immutable object using the values of the mutable instance, for example, new java.awt.Color(values).

Conclusion

All the changes were made to improve performance and reduce garbage generation, mainly because we are using the project on our Android games. The changes also improve the usability of the library since they reduce a lot of noise and reduce what you need to use. For example, all the modules slick2d, java2d and componentsengine were removed from the project since they had unused code and they depended on libraries that aren't on maven central.

I wanted to share a bit the changes but, as things keep changing, for now all this stuff is on an unstable 0.2.0-SNAPSHOT version and wasn't released on maven central yet.

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

Animation4j - Synchronizer

Friday, May 13th, 2011

In this post I will talk a bit more about animation4j project, particularly the Synchronizer class.

When working with transitions we could want to declare them in a seamlessly way. In a previous post I introduced the Transition class which lets you define a transition of an object from one state to another but it requires manual synchronization from transition object values to your own object values. In retrospective, that doesn't seems the best way to achieve seamless usage.

Meet the Synchronizer

For this reason, animation4j provides a class named Synchronizer, which handles all the synchronization internally for you. To create a new transition you have to declare something like this:

	// create a synchronizer in some part of your initialization code
	Synchronizer synchronizer = new Synchronizer();
	
	// create a transition in some parte of your game logic, for example when the user press something
	Vector2f position = new Vector2f(100, 100);
	synchronizer.transition(position, Transitions.transitionBuilder().end(new Vector2f(200, 200)).time(500));

	// this will perform the synchronization, it will set to my object the current value of the transition.
	// normally this call will be on an update() method of your game
	synchronizer.synchronize(delta);

	// so now my object will be update with the new values
	System.out.prinln(position);

note: I used a Vector2f class in the example because it is a known class, all libraries have a Vector implementation.

In the previous example, I create a transition of a Vector2f class from (100,100) to (200, 200) in 500ms.

To register a new transition to be synchronized you call transition() method and each time synchronize(delta) method is called, Synchronizer will perform synchronization of all registered transitions. The registration method comes in to flavors, one will modify the object you pass but it only works if you are using a mutable object. The other one works over the field of an object using reflection and calling public set method to modify the internal field. It works for both mutable and immutable objects because it is setting a new value each time, however, one pending improvement is to modify current field value, instead creating a new one each time, when the field class is mutable.

Synchronizer class could be used in a static way using the Synchronizers class, which holds an internal singleton instance to do all the work. That is really useful when you want to use the synchronization stuff wherever you want. However a restriction is that it will updates all registered transitions and that could be a problem if you have different states for your game, for example, a pause game state which keeps rendering a playing game state, you don't want the transitions started in that state to go on, so in that case could use different instances for each game state.

TransitionBuilder is your friend

Another interesting stuff added to the library is the TransitionBuilder class provided inside the Transitions class. In previous versions, there were different methods to create a Transition using the Transitions factory class, one only specifying speed, other specifying speed and end value, other specifying speed and the interpolation functions, and the list goes on and on. In order to improve this, the TransitionBuilder class was created. It lets you specify the parameters you want when building a Transition, for example:

	Transition transition = Transitions.transitionBuilder().start(v1)
		.end(v2)
		.time(5000)
		.functions(InterpolationFunctions.easeIn(), InterpolationFunctions.easeOut())
		.build();

The previous code will create a transition from value v1 to value v2 in 5000ms using the declared interpolation functions to interpolate between the internal values of v1 and v2 (as explained in a previous post).

These classes simplify a lot working with animation4j but there is still a lot of work to do in order to improve usage and internal performance.

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

Animation4j - Interpolation Functions

Saturday, March 26th, 2011

Interpolation Functions are a key concept in animation4j project, they define how to a variable should change from one value to another. To define interpolation functions in animation4j, InterpolatorFunction interface should be implemented, the API looks like this:

public interface InterpolatorFunction {

	/**
	 * @param t
	 *            A real number in the interval [0,1]
	 * @return The interpolated value.
	 */
	float interpolate(float t);

}

So basically, functions works for values of t between interval [0,1]. An example implementation of this function is a linear Bézier:

/**
 * Linear Bézier curve implementation of an InterpolatorFunction.
 * 
 */
public class LinearBezierInterpolatorFunction implements InterpolatorFunction {

	private final float p0, p1;

	public LinearBezierInterpolatorFunction(float p0, float p1) {
		this.p0 = p0;
		this.p1 = p1;
	}

	@Override
	public float interpolate(float t) {
		if (t < 0)
			return p0;
		if (t > 1)
			return p1;
		return (1 - t) * p0 + t * p1;
	}

}

The library already provides some implementations, you could instantiate them using InterpolatorFunctionFactory factory class. The API of the factory looks like this:

	// returns a cubic Bézier interpolation function based on the four specified points.
	InterpolatorFunction cubicBezier(float p0, float p1, float p2, float p3);

	// returns a quadratic Bézier interpolation function based on the four specified points.
	InterpolatorFunction quadratic(float p0, float p1, float p2);

	// returns a cubic Bézier interpolation function with presetted values.
	InterpolatorFunction ease();

	// returns a linear Bézier interpolation function.
	InterpolatorFunction linear();

	// returns a cubic Bézier interpolation function with presetted values.
	InterpolatorFunction easeIn();

	// returns a cubic Bézier interpolation function with presetted values.
	InterpolatorFunction easeOut();

	// returns a cubic Bézier interpolation function with presetted values.
	InterpolatorFunction easeInOut();

In the previous post we talked about transitions of variables from one value to another using Transition interface. When building a transition using the Transitions factory, you could specify the interpolation functions you want to use, if you don't, then linear Bézier functions are used by default. One example of how to create a Transition specifying the interpolation functions looks like this:

Transition<Vector2f> transition = Transitions.transition(
	new Vector2f(0f, 0f), 					// the starting value
	vector2fConverter, 						// the type converter (using two variables)
	InterpolatorFunctionFactory.easeOut(),	// the interpolation function for the first variable
	InterpolatorFunctionFactory.easeIn());	// the interpolation function for the second variable

One thing to mention is that Transitions factory methods use a varargs to specify interpolation functions parameters because we don't know beforehand how many variables you need. In case you specify less functions than variables, then linear Bézier functions will be used for the variables without functions specified.

As we said on the previous post, animation4j API could change since this blog post was written. API used for this post is the one of the current released version 0.0.8 (already uploaded to maven central).

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

Animation4j - Transitions

Friday, March 25th, 2011

As we said on a previous post, we are going to talk a bit more about the current released version (0.0.8) of animation4j, remember that the API could change since we wrote this post.

In this case, we are going to talk about making a transition from one value to another in some time. Animation4j provides you one interface to make transitions, the Transition interface, the API by now looks like this:

public interface Transition<T> {

	/**
	 * Returns the current value of the transition.
	 * 
	 */
	T get();

	/**
	 * Start an interpolation from a to b in the specified default time.
	 * 
	 * @param t
	 *            The wanted new value.
	 */
	void set(T t);

	/**
	 * Start an interpolation from a to b in the specified time.
	 * 
	 * @param t
	 *            The wanted new value.
	 * @param time
	 *            The time to set the new value. If time is zero, then value is applied directly.
	 */
	void set(T t, int time);
}

The library uses generics so you can create transitions of any type. To do this, you can use the Transitions factory class, where you can create transitions for your types. The API of the factory class looks like this:

<T> Transition<T> transition(T startValue, TypeConverter<T> typeConverter);

The current Transition generic implementation internally work with a float[] in order to optimize memory and to simplify internal work. To use it, you will have to create a converter from your type to float[] and vice versa by implementing the TypeConverter<T> interface. Current API of TypeConverter<T> looks like this:

/**
 * Provides a way to convert an object in a float[] array and vice versa, for interpolation purposes.
 * 
 * @param <T>
 *            The type to convert.
 * @author acoppes
 */
public interface TypeConverter<T> {

	/**
	 * Returns the quantity of variables are used to convert the object to the float[] and vice versa.
	 * 
	 * @return the quantity of variables used.
	 */
	int variables();

	/**
	 * Copy the values of the object to the specified float array, if null it will create a new float array.
	 * 
	 * @param object
	 *            The object from where to get the values to fulfill the float array.
	 * @param x
	 *            The float array to copy the values of the object. If null it will create a new float array.
	 * @return The float array with the values of the object.
	 */
	float[] copyFromObject(T object, float[] x);

	/**
	 * Copy the values of the float array to the specified object.
	 * 
	 * @param object
	 *            The object which the float array values will be copied to. If null or object immutable, it will create a new object.
	 * @param x
	 *            The float array to get the values to fulfill the object.
	 * @return An object with the values of the float array.
	 */
	T copyToObject(T object, float[] x);

}

Type converters should be stateless, so you can reuse a single type converter for all your transitions of the same type. For the next Vector2f class example:

public class Vector2f {

	public float x,y;

	public Vector2f(float x, float y) {
		set(x,y);
	}

	public void set(float x, float y) {
		this.x = x;
		this.y = y;
	}

}

We could create the next type converter:

public class Vector2fConverter implements TypeConverter<Vector2f> {

	@Override
	public float[] copyFromObject(Vector2f v, float[] x) {
		if (x == null) 
			x = new float[variables()];  // don't worry about garbage generation, the transition implementation will cache these values.
		x[0] = v.x;
		x[1] = v.y;
		return x;
	}

	@Override
	public Vector2f copyToObject(Vector2f v, float[] x) {
		if (v == null)
			v = new Vector2f(0, 0); // don't worry about garbage generation, the transition implementation will cache these values.
		v.x = x[0];
		v.y = x[1];
		return v;
	}

	@Override
	public int variables() {
		// we are only using two variables.
		return 2;
	}
}

So, to create a transition, your code would look like:

TypeConverter<Vector2f> converter = new Vector2fConverter(); // could be reused
Transition<Vector2f> transition = Transitions.transition(new Vector2f(100, 100), converter);

// now, set a transition to (500,500) in five seconds.
transition.set(new Vector2f(500, 500), 5000);

// wait some time, and get the value interpolated
Vector2f v = transition.get();

For more information, there is an transitions example in the examples module.

The idea is to provide different TypeConverter implementations for different libraries as project modules so you don't have to implement a TypeConverter for a Slick2D vector2f, or libgdx Vector2. However it is really easy to implement a type converter and you only have to do it once. Also, you will probably use transitions only for some types.

In one of the next posts, we want to talk about interpolation functions (and how are they used for transitions) as they are key concepts in animation4j project.

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)