How we used Entity Component System (ECS) approach at Gemserk - 2/2

So, after our first attempt on using ECS, when we started to develop mobile games and moved to the LibGDX framework, we decided to abandon our ComponentsEngine and start over.

We were still reading about ECS while we were creating our set of tools and code over LibGDX. At some point in time, some of the Java community developers started Artemis, a lightweight ECS, and we decided to give it a try.

Artemis

This is a simplified core architecture diagram:

Note: we used a modified version of Artemis with some additions like enable/disable an Entity.

In this pure approach, Entities and Components are just data, and they are related by identifiers, like these tables in a relational database:

Where we have two entities, both with a PositionComponent and only one of them with MovementComponent.

An example of this components in code:

public class PositionComponent : Component {
    public float x, y;
}

public class MovementComponent: Component {
    public float speed;
}

EntitySystems perform the game logic. They normally work on a subset of Components from an Entity but they could need it in order to enable/disable/destroy it (if it is part of its logic).

An example of a System is LimitLinearVelocitySystem, used in multiple of our games to limit the physics velocity of an Entity with PhysicsComponent and LimitVelocityLimitComponent:

public void process(Entity e) {
    PhysicsComponent physicsComponent = 
                     Components.getPhysicsComponent(e);
    Body body = physicsComponent.getPhysics().getBody();

    LinearVelocityLimitComponent limitComponent = 
             e.getComponent(LinearVelocityLimitComponent.class);
    Vector2 linearVelocity = body.getLinearVelocity();

    float speed = linearVelocity.len();
    float maxSpeed = limitComponent.getLimit();

    if (speed > maxSpeed) {
        float factor = maxSpeed / speed;
        linearVelocity.mul(factor);
        body.setLinearVelocity(linearVelocity);
    }
}

There are some extra classes like the TagManager which allows assigning a unique string identifier to an Entity in order to find it, and the GroupManager which allows adding entities to groups identified by a name, which is more like how tags are used everywhere else.

Even though it could look similar to our ComponentsEngine where the Properties in that engine correspond to the Components in this one, and Components to Systems, there is an important difference: Systems are not part of an Entity and work horizontally over all entities with specific Components (data). So, in this approach, changing only data from entities indeed change their behaviour in the game, so it is really data driven.

Since Entities and Components are just data, their instances in memory are easier to reuse. An Entity is just an id, so it is obvious. A Component is a set of data that doesn't care too much which Entity it belongs to. So, after the Entity doesn't need it anymore, it could be reused elsewhere, improving a lot memory usage and garbage collection.

Artemis, and other pure ECS implementations, are really lightweight and performant frameworks. The real power comes from the Systems and Components built over them. In our case, we created a lot of Systems that we started to reuse between games, from SuperFlyingThing to VampireRunner and even in Clash of the Olympians.

Scripting

One of the most interesting ones is the Scripting framework we created over Artemis. It was really useful and gave us a lot of power to overcome some of the limitations we were facing with the pure approach when we need to create a specific logic for a specific moment during the game and (probably) never again and we didn't want a System for that.

They work similar to Unity MonoBehaviours and our logic Components from ComponentsEngine, and they also belong to the Entity lifecycle. One difference, however, is that they try to avoid storing data in their instances as much as possible and instead try to store and read data from Components, like Systems do.

Here is an example Script from one of our games:

public class MovementScript extends ScriptJavaImpl {
	
  @Override
  public void update(World world, Entity e) {

    MovementComponent movementComponent = Components.getMovementComponent(e);
    SpatialComponent spatialComponent = Components.getSpatialComponent(e);
    ControllerComponent controllerComponent = Components.getControllerComponent(e);
		
    Controller controller = controllerComponent.controller;
    Movement movement = movementComponent.getMovement();
    Spatial spatial = spatialComponent.getSpatial();
		
    float rotationAngle = controllerComponent.rotationSpeed * GlobalTime.getDelta();
		
    Vector2 linearVelocity = movement.getLinearVelocity();
		
    if (controller.left) {
        spatial.setAngle(spatial.getAngle() + rotationAngle);
        linearVelocity.rotate(rotationAngle);
    } else if (controller.right) {
        spatial.setAngle(spatial.getAngle() - rotationAngle);
        linearVelocity.rotate(-rotationAngle);
    }
		
  }
	
}

Note: GlobalTime.getDelta() is similar to Unity's Time API.

One problem about the Scripting framework is that it is not always clear when some logic should be in a Script or a System, and that made reusability a bit harder. In the case of the example above, it is obvious it should be moved to a System.

Templates

Another useful thing we did over Artemis was using templates to build entities in a specific way, similar to what we had in ComponentsEngine.

We used also a concept of Parameters in templates in order to customize parts of them. Similar to ComponentsEngine, templates could apply other templates and different templates could be applied to the same Entity.

Here is an example of an Entity template:

public void apply(Entity entity) {

    String id = parameters.get("id");
    String targetPortalId = parameters.get("targetPortalId");
    String spriteId = parameters.get("sprite", "PortalSprite");
    Spatial spatial = parameters.get("spatial");
    Script script = parameters.get("script", new PortalScript());

    Sprite sprite = resourceManager.getResourceValue(spriteId);

    entity.addComponent(new TagComponent(id));
    entity.addComponent(new SpriteComponent(sprite, Colors.darkBlue));
    entity.addComponent(new Components.PortalComponent(targetPortalId, spatial.getAngle()));
    entity.addComponent(new RenderableComponent(-5));
    entity.addComponent(new SpatialComponent(spatial));
    entity.addComponent(new ScriptComponent(script));

    Body body = bodyBuilder //
            .fixture(bodyBuilder.fixtureDefBuilder() //
                    .circleShape(spatial.getWidth() * 0.35f) //
                    .categoryBits(CategoryBits.ObstacleCategoryBits) //
                    .maskBits((short) (CategoryBits.AllCategoryBits & ~CategoryBits.ObstacleCategoryBits)) //
                    .sensor()) //
            .position(spatial.getX(), spatial.getY()) //
            .mass(1f) //
            .type(BodyType.StaticBody) //
            .userData(entity) //
            .build();

    entity.addComponent(new PhysicsComponent(new PhysicsImpl(body)));

}

That template configures a Portal entity in SuperFlyingThing which teleports the main ship from one place to another. Click here for the list of templates used in that game.

Interacting with other systems

Sometimes you already have a solution for something, like the physics engine, and you want to integrate it with the ECS. The way we found was to create a way to synchronize data from that system to the ECS and vice versa, sometimes having to replicate a bit of data in order to have it easier for the game to use it.

Finally

Even though we had to do some modifications and we know it could still be improved, we loved using a pure ECS in the way we did.

It was used to build different kind of games/prototypes and even a full game like the Clash of the Olympians for mobile devices, and it worked pretty well.

What about now?

Right now we are not using any of this in Unity. However we never lost interest nor feith in ECS, and there are starting to appear new solutions over Unity in the last years that caught our attention. Entitas is one of them. The Unity team is working towards this path too as shown in this video. Someone who din't want to wait started implementing that solution in his own way. We've also watched some Unite and GDC talks about using this approach in big games and some of them even have a Scripting layer too, which is awesome since, in some way, it validates we weren't so wrong ;).

I am exited to try ECS approach again in the near future. I believe it could be a really good foundation for multiplayer games and that is something I'm really interested in doing at some point in my life.

Thanks for reading.

References

 

 

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

How we used Entity Component System (ECS) approach at Gemserk - 1/2

When we started Gemserk eight years ago, we didn't know which was the best way to make games. So before starting, we did some research. After reading some articles and presentations we were really interested in trying an Entity Component System (ECS) approach for our games. However, since we didn't find a clear guide or implementation at that point we had to create our own solution while exploring and understanding it. We named our engine ComponentsEngine.

Components Engine

The following image shows a simplified core architecture diagram:

Note: part of the design was inspired by a Flash ECS engine named PushButtonEngine.

An Entity is just a holder of state and logic. In an ECS, anything can be an Entity, from an enemy ship to the concept of a player or even a file path to a level definition. It depends a lot on the game you are making and how you want to structure it.

A Property is part of the state of an Entity, like the health or the position in the world, anything that means something for the state of the game. It can be accessed and modified from outside.

Components perform logic updating one or more Properties to change the Entity state. A component could for example change the position of an Entity given a speed and a moving direction.

They normally communicate with each other either by modifying common Properties (when on the same Entity) or by sending and receiving Messages through a MessageDispatcher (when on the same or on different Entities). They just have to register a method to handle a message. In some way, this is pretty similar to using SendMessage() method in Unity and having the proper methods in the MonoBehaviours that need to react to those messages.

EntityTemplates are an easy way to define and build specific game entities, they just add Properties and Components (and more stuff) to make an Entity behave in one way or another.

For example, a ShipTemplate could add position, velocity and health properties and some components to perform movement and to process damage from bullet hits:

public void build() {
        // ... more stuff 
        property("position", new Vector2f(0, 0));
        property("direction", new Vector2f(1, 0));

        property("speed", 5.0f);

        property("currentHealth", 100.0f);
        property("maxHealth", 100.0f);

        component(new MovementComponent());
        component(new HealthComponent());
}

An example of the MovementComponent:

public class MovementComponent() {

   @EntityProperty
   Vector2f position;

   @EntityProperty
   Vector2f direction;

   @EntityProperty
   Float speed;

   @Handles
   public void update(Message message) {
      Property<Float> dt = message.getProperty("deltaTime");
      position += direction * speed * dt.get();
   }

}

In some way, EntityTemplates are similar to Unity Prefabs or Unreal Engine Blueprints, represeting in some way a (not pure) Prototype pattern.

Some interesting stuff of our engine:

  • Since templates are applied to Entities, we can apply multiple templates to the same one. In this way, we could have common templates to add generic features like motion for example. So we could do something like OrcTemplate.apply(e) to add the orc properties and components and then MovableTemplate.apply(e), so now we have an Orc that moves.
  • Templates can apply other templates inside them. So we could do the same as before but inside OrcTemplate, we could apply MovableTemplate there. Or even use this to create specific templates, like OrcBossTemplate which is an Orc with a special ability.
  • Entities have also tags which are defined when applying a template too and are used to quickly identify entities of interest. For example, if we want to identify all bullets in the game, we could add the tag "Bullet" during the Entity creation and then, when processing a special power, we get all the bullets in the scene and make them explode. Note: in some ECS a "flag" component is used for this purpose.
  • The Property abstraction is really powerful, it can be implemented in any way, for example, an expression property like "my current health is my speed * 2". We used that while prototyping.

Some bad stuff:

  • Execution speed wasn't good, we had a lot of layers in the middle, a lot of reflection, send and receive messages (even for the update method), a lot of boxing and unboxing, etc. It worked ok in desktop but wasn't a viable solution for mobile devices.
  • The logic started to be distributed all around and it wasn't easy to reuse, and we started to have tons of special cases, when we couldn't reuse something we simply copy-pasted and changed it.
  • There was a lot of code in the Components to get/set properties instead of just doing the important logic.
  • Indirection in Properties code was powerful but we end up with stuff like this (and we didn't like it since it was too much code overhead):
e.getProperty("key").value = e.getProperty("key").value + 1.
  • We didn't manage to have a good data driven approach which is one of the best points of ECS. In order to have different behaviours we were forced to add both properties, components and even tags instead of just changing data.

Note: Some of these points can be improved but we never worked on that.

Even though we don't think the achitecture is bad, it guided us to do stuff in a way we didn't like it and didn't scale. We feel that Unity does the same thing with its GameObjects and MonoBehaviours, all the examples in their documentation go in that direction.

That was our first try to the ECS approach. In case you are interested, ComponentsEngine and all the games we did with it are on Github and even though they are probably not compiling, they could be used as reference.

This post will continue with how we later transitioned to use a more pure approach with Artemis, when we were more dedicated to mobile games.

References

Evolve your hierarchy - Classic article about Entity Component System.

PushButtonEngine - Flash Entity Component System we used as reference when developing our ComponentsEngine.

Game architecture is different - A quick transformation from normal game architecture to ECS.

Slick2D - The game library we were using during ComponentsEngine development.

 

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

Our resources manager and how it helped in localizing Clash of the Olympians

In this post we want to share how our resources manager implementation helped us when we had to localize Clash of the Olympians.

Our resources manager

Some time ago we started a small java project named jresourcesmanager (yeah, the most creative name in the world) which provides a simple abstraction of what a resource is and how it is loaded. It consists in some basic concepts named Resource, DataLoader and ResourceManager.

Resource

Is the concept of an application resource/asset, and provides an API to know if the resource is loaded or not and to load and unload it. Here is the code:

public class Resource<T> {

	T data = null;

	DataLoader<T> dataLoader;

	protected Resource(DataLoader<T> dataLoader) {
		this(dataLoader, true);
	}

	protected Resource(DataLoader<T> dataLoader, boolean deferred) {
		this.dataLoader = dataLoader;
		if (!deferred)
			reload();
	}

	/**
	 * Returns the data stored by the Resource.
	 */
	public T get() {
		if (!isLoaded())
			load();
		return data;
	}
	
	public void set(T data) {
		this.data = data;
	}

	public DataLoader<T> getDataLoader() {
		return dataLoader;
	}
	
	public void setDataLoader(DataLoader<T> dataLoader) {
		unload();
		this.dataLoader = dataLoader;
	}

	/**
	 * Reloads the internal data by calling unload and load().
	 */
	public void reload() {
		unload();
		load();
	}

	/**
	 * Loads the data if it wasn't loaded yet, it does nothing otherwise.
	 */
	public void load() {
		if (!isLoaded())
			data = dataLoader.load();
	}

	/**
	 * Unloads the data by calling the DataLoader.unload(t) method.
	 */
	public void unload() {
		if (isLoaded()) {
			dataLoader.unload(data);
			data = null;
		}
	}

	/**
	 * Returns true if the data is loaded, false otherwise.
	 */
	public boolean isLoaded() {
		return data != null;
	}

	public Resource<T> clone() {
		return new Resource<T>(dataLoader);
	}

}

DataLoader

Provides an API to define a way to load and unload a Resource, here is the code:

public abstract class DataLoader<T> {

	/**
	 * Implements how to load the data.
	 */
	public abstract T load();

	/**
	 * Implements how to unload the data, if it is nod automatic and you need to unload stuff by hand.
	 */
	public void unload(T t) {

	}

	/**
	 * Provides a way to return custom information about the data loader.
	 * 
	 * @return An object with the custom information.
	 */
	public Object getMetaData() {
		return null;
	}

}

ResourceManager

It is just a map with all the resources identified by a key, which can be a String for example, and an API to store and get resources to and from, respectively.

That is our resources management code, it is really simple and fulfilled our needs in assets loading/unloading for Vampire Runner and Clash of the Olympians.

The interesting part of this library is that it allows you to store whatever you want to consider as a resource/asset, and that feature is what we used in order to solve the localization issue.

Declaring resources

Another important pillar is how we declare resources in an easy way through the code, and that is by using some builders that simplified the resource declaration. As we were using LibGDX library, we created a resource builder for LibGDX assets and more. This resource builder allowed us to do stuff like this:

splitLoadingTextureAtlas("MainTextureAtlas", "data/images/screens/mainmenu/pack");
resource("MainBackgroundTop", sprite2().textureAtlas("MainTextureAtlas", "mainmenu-bg", 1).center(0.5f, 0.5f).trySpriteAtlas());

That declares a texture atlas with the name of MainTextureAtlas and then a resource which is a sprite with the name of MainBackgroundTop from a texture atlas resource identified by the previous name. Also, allow us to do stuff like declare that the sprite is centered in the middle (the anchor point) and more.

This code is not important, just an example of some of our builders.

Declaring localized resources

As we have the power to create complex resource builders and we needed a simple way to switch between assets given the language selected, we created a resource builder which allowed us to declare different resources, depending the current locale, using the same identifier. So, for example, we can do something like this:

resource("CreditsButton", new MultilanguageResourceBuilder<Sprite>() //
	.defaultLocale(new Locale("en")) //
	.resource(new Locale("en"), sprite2().textureAtlas(TextureAtlases.MeinMenu, "mainmenu-but-credits-en", 1).trySpriteAtlas()) //
	.resource(new Locale("es"), sprite2().textureAtlas(TextureAtlases.MeinMenu, "mainmenu-but-credits-es", 1).trySpriteAtlas()) //
			);

That declares a resource named CreditsButton which returns a sprite with index 1 and name “mainmenu-but-credits-en” from a texture atlas in case the locale is English and a sprite with index 1 and name “mainmenu-but-credits-es” in case the locale is Spanish. It also declares that the default locale (in case a resource for the current locale wasn’t found) is English.

This resource builder was very handy because it allowed us to declare any type of resource for different locales, and from the application side it was transparent, we just ask for the resource CreditsButton.

In case you are interested, the code of the MultilanguageResoruceBuilder is:

public class MultilanguageResourceBuilder<T> implements ResourceBuilder<T> {

	private Map<Locale, ResourceBuilder<T>> resourceBuilders = new HashMap<Locale, ResourceBuilder<T>>();
	private Locale defaultLocale;

	@Override
	public boolean isVolatile() {
		if (defaultLocale == null)
			throw new IllegalStateException("Multilanguage resource builder needs a default locale");
		ResourceBuilder<T> resourceBuilder = resourceBuilders.get(defaultLocale);
		if (resourceBuilder == null)
			throw new IllegalStateException("Multilanguage resource builder needs a default resource builder");
		return resourceBuilder.isVolatile();
	}

	public MultilanguageResourceBuilder<T> defaultLocale(Locale locale) {
		this.defaultLocale = locale;
		return this;
	}

	public MultilanguageResourceBuilder<T> resource(Locale locale, ResourceBuilder<T> resourceBuilder) {
		resourceBuilders.put(locale, resourceBuilder);
		return this;
	}

	@Override
	public T build() {
		Locale locale = Locale.getDefault();

		if (defaultLocale == null)
			throw new IllegalStateException("Multilanguage resource builder needs a default locale");

		if (!resourceBuilders.containsKey(locale))
			locale = defaultLocale;

		ResourceBuilder<T> resourceBuilder = resourceBuilders.get(locale);

		if (resourceBuilder == null)
			throw new IllegalStateException("Multilanguage resource builder needs a default resource builder");

		return resourceBuilder.build();
	}

}

Conclusion

That was the way we used to support multiple languages in a transparent way for the application, we just need to change the current locale and reload the assets.

Hope this blog post idea helps you in case you are about to support multiple languages in your game, and see you next time.

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

Some changes to animation4j to clean the API

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

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

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

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)

Animation4j Project Introduction

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.

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