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).


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](https://github.com/gemserk/animation4j/blob/animation4j-0.0.8/animation4j-core/src/main/java/com/gemserk/animation4j/converters/TypeConverter.java) interface. Current API of [TypeConverter](https://github.com/gemserk/animation4j/blob/animation4j-0.0.8/animation4j-core/src/main/java/com/gemserk/animation4j/converters/TypeConverter.java) 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.


Some time ago I made a lighting bolt effect in Java, using Slick2D library, following the tutorial of Drilian’s House of Game Development. My results:

If you are looking to make a nice lighting bolt effect for your game, I recommend you to follow the original tutorial.

Here is my code if you want to use it and/or modify it:

package com.gemserk.commons.tests;

import static org.lwjgl.opengl.GL11.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;
import java.util.concurrent.Callable;

import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Line;
import org.newdawn.slick.geom.Vector2f;
import org.newdawn.slick.opengl.SlickCallable;

public class LightingBoltTestTemporal extends BasicGame {

	public LightingBoltTestTemporal(String title) {
		super(title);
	}

	public static void main(String[] arguments) throws SlickException {
		AppGameContainer app = new AppGameContainer(new LightingBoltTestTemporal("Name");
		app.setDisplayMode(320, 240, false);
		app.setAlwaysRender(true);
		app.setMinimumLogicUpdateInterval(1);
		app.setShowFPS(true);
		app.start();
		return app;
	}

	public static class LightingBoltEffect {

		Collection<Line> segments;

		int totalTime;

		int currentTime;

		private float lineWidth;

		public LightingBoltEffect(int time, Collection<Line> segments, float lineWidth) {
			this.totalTime = time;
			this.segments = segments;
			this.currentTime = time;
			this.lineWidth = lineWidth;
		}

		public void update(int delta) {
			currentTime -= delta;
			if (currentTime <= 0)
				currentTime = 0;
		}

		public void render() {
			float alpha = (float) currentTime / (float) totalTime;
			glPushMatrix();
			glColor4f(alpha, alpha, alpha, alpha);
			glLineWidth(lineWidth);
			glBegin(GL_LINES);
			{
				for (Line segment : segments) {
					glVertex(segment.getStart());
					glVertex(segment.getEnd());
				}
			}
			glEnd();
			glPopMatrix();
		}

		public boolean isDone() {
			return currentTime <= 0;
		}
		

		public void glVertex(Vector2f v) {
			glVertex3f(v.x, v.y, 0);
		}
		
	}

	@Override
	public void init(GameContainer container) throws SlickException {
		generateLightingBolt(new Vector2f(50, 240), new Vector2f(290, 240), 100);
	}

	protected void generateLightingBolt(Vector2f p0, Vector2f p1, int duration) {
		Collection<Line> segments = new ArrayList<Line>();
		
		segments.add(new Line(p0, p1));
		
		float offset = 200f;
		double probability = 0.3; // probability to generate new partitions
		float height = 50.0f; 
		
		Random random = new Random();
		
		int partitions = 4;
		
		for (int i = 0; i < partitions; i++) {
		
			Collection<Line> newSegments = new ArrayList<Line>();
		
			for (Line segment : segments) {
		
				Vector2f midPoint = segment.getStart().copy().add(segment.getEnd()).scale(0.5f);
		
				Vector2f perpendicular = midPoint.copy().add(90);
				perpendicular.normalise().scale(random.nextFloat() * offset - (offset / 2));
				midPoint.add(perpendicular);
				
				if (random.nextFloat() < probability) {
					// generate new branch
					Vector2f direction = midPoint.copy().sub(segment.getStart());
					direction.add(random.nextFloat() * height);
					newSegments.add(new Line(midPoint.copy(), midPoint.copy().add(direction)));
				}
		
				newSegments.add(new Line(segment.getStart().copy(), midPoint.copy()));
				newSegments.add(new Line(midPoint.copy(), segment.getEnd().copy()));
			}
		
			segments = newSegments;
		
			offset /= 2;
		}
		lightingBoltEffect = new LightingBoltEffect(duration, segments, 2.0f);
	}

	private LightingBoltEffect lightingBoltEffect;

	@Override
	public void update(GameContainer container, int delta) throws SlickException {
		lightingBoltEffect.update(delta);
		if (!lightingBoltEffect.isDone())
			return;

		Input input = container.getInput();
		if (!input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON))
			return;

		int mouseX = input.getMouseX();
		int mouseY = input.getMouseY();

		Random random = new Random();
		int duration = random.nextInt() % 600 + 100;
		generateLightingBolt(new Vector2f(mouseX, mouseY), new Vector2f((mouseX + 300), mouseY), duration);
	}

	@Override
	public void render(GameContainer container, Graphics g) throws SlickException {
		SlickCallable.enterSafeBlock();
		lightingBoltEffect.render();
		SlickCallable.leaveSafeBlock();
	}
}

Some time ago I started an internal project to simplify working with animations and transitions when making games in Java.

It was used in some of our games, for example ZombieRockers to make different kind of effects like fade in/out of screens or the points messages when scoring, or in JSnakes to make camera effects like zoom in/out, camera movement, etc.

After using it on our games, it became more clear what kind of things are possible with it.

Now that we are using Github for our source code, we started a dedicated project named animation4j with all the stuff related with animations.

This video shows some working examples of the project:

You can download a runnable jar to test the features shown in the video.

The project is on development, so right now there are a lot of things to improve starting by making easy to understand examples.

I plan to add more posts explaining some design decisions and showing how to use the library.

Hope Java developers could find some use for it.


Some time ago, Rubén wrote a Java based tool to download all JNLP resources and prepare executable files to run it based on the JNLP file values.

It downloads all the resources specified by the JNLP file and save them into /libs and /natives for jar resources and nativelib resources respectively, in the second case it creates sub folders for each platform (Windows, Mac and Linux). After that, it creates one executable script file to run the application for each platform, configuring classpath and java.library.path inside it.

For example, running the tool:

java -jar jnlpdownloader.jar example http://www.example.com/application.jnlp

where the JNLP contents are:

<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+" codebase="http://www.example.com/" href="application.jnlp">
    <information>
            <title>Some Title</title>
            <vendor>Some Vendor</vendor>
            <description>Some Description</description>
    </information>
    <resources>
            <jar href="slf4j-api-1.5.8.jar" />
            <jar href="google-collections-1.0.jar" />
            <jar href="lwjgl-2.4.2.jar" />
    </resources>
    <resources os="Windows">
            <nativelib href="lwjgl-2.4.2-natives-win.jar" />
    </resources>
    <resources os="Linux">
            <nativelib href="lwjgl-2.4.2-natives-linux.jar" />
    </resources>
    <resources os="Mac">
            <nativelib href="lwjgl-2.4.2-natives-mac.jar" />
    </resources>  
    <application-desc main-class="Main" />
</jnlp>

will create the next file structure:

./example
./example/natives
./example/natives/Linux
./example/natives/Linux/liblwjgl.so
./example/natives/Windows
./example/natives/Windows/lwjgl.dll
./example/natives/Mac
./example/natives/Mac/liblwjgl.jnilib
./example/libs
./example/libs/google-collections-1.0.jar
./example/libs/slf4j-api-1.5.8.jar
./example/libs/lwjgl-2.4.2.jar
./example/run-windows.bat
./example/run-macosx.sh
./example/run-linux.sh

More info at the project’s home page.

We used this tool mainly to take a snapshot of a deployed Java Web Start application to make it run offline, for demo purposes.