Since the last update of Vampire Runner we were experiencing some notorious performance issues on the Android version and that is why we focused our efforts trying to improve it. The main problem was having some stuttering from time to time and some really bad fps on some devices.
We updated Vampire Runner in the Android Market with all the improvements we made:
Removed the energy bar
Fixed the instructions texts to be clearer.
Here is the QR-code if you want to easy access from your Android device:
As we mentioned on a previous post, we were having some performance issues in Vampire Runner and we were trying different approaches to improve its performance.
One limitation of Android when making games is you have to avoid generating garbage whenever you can since the garbage collection would generate pauses on your games and that leads to a bad user experience. Then, we should try to reuse already created object instead of creating new ones.
In Vampire Runner, one problem we were having was that we were creating a lot of entities at a specific moment of the game, when we detected a new obstacle should be created, and that was making some pauses on the Android version.
As we use Artemis, we should try to reuse some entities when we can. For example, if we make a shooting game (like the Jetpac prototype I made) it seems a good idea to reuse bullets since their life cycle is really short. Ziggy made two blog posts about this topic some weeks ago here and here, however we followed a slightly different approach and we will explain it in this post.
Storing entities to reuse them
We created a concept named Store (similar to LibGDX Pool class) which let us easily store objects, in this case entities of one kind (for example bullets).
free(T t) // returns an entity to the Store to be reused later
get() : t // returns an entity from the Store, it reuses an object from the free
collection if there is one or creates a new object otherwise.
The idea is to, for example, instead of creating a new bullet when a weapon is fired, calling store.get() and set the component values as they should be, and when the bullet collides with something call the store.free(e) instead of deleting the entity, so we can reuse it later.
This is a generic approach and we can use different stores to reuse different kind of entities but it has a big problem, those entities keep being in Artemis world, that means they keep being processed (collisions, render, etc). A basic solution to this problem was adding a new state to the entity, and we explain that in the following section.
Enabling and disabling Artemis entities
Artemis supports reuse of entities by internally caching created entities inside the World class, however their state (which components their have) is not easily reused, and that was one of the big problems when creating a new entity, we wanted to reuse their state.
Our current solution to the problem was adding a new state to the entities, if they are enabled or not. Being enabled means the entity is processed by all interested EntitySystems, being disabled means the entity is still in the Artemis world but it is not processed by any system.
So, in our customization of Artemis we added three new methods to Entity to be called whenever you want to enable or disable an entity:
disable() : disables an entity to avoid it to be processed on EntitySystems
enable() : enables again an entity to let it be processed on EntitySystems
isEnabled() : returns true if the entity is enabled, false otherwise.
Then, we added new methods to EntitySystem API to let each EntitySystem to be aware an entity of interest was enabled or disabled:
disabled(Entity e) : called whenever an entity of this EntitySystem was disabled
enabled(Entity e) : called whenever an entity of this EntitySystem was disabled
In our case, we are using them to enable and disable Box2D bodies in our PhysicsSystem, and also to remove them from our render layers in our RenderSystem.
As an example, we have a nice video of Vampire Runner we made by changing the zoom of the camera to see the behind the scenes:
As you can see, when entities like wall, fire and Christmas stuff are behind the main character, they disappear. That is because they are disabled and moved again to their stores so they stop being processed by Artemis, in particular, stop being rendered.
By combining both solutions, we have an easy way to reuse created entities of one kind, like our obstacles tiles in Vampire Runner, while at the same time we can disable them when they are on a store to avoid them being processed.
In case of Vampire Runner, this solution improved Vampire Runner performance since we now pre create a lot of entities we need during the game and then disable them and enable them only when needed, in this way, we could avoid creating a lot of entities in one update after the game was started.
This is a first approach solution to the problem and seems good for our current games but it may not fit other type of games or bigger games, we don't know that yet.
If you use Artemis and you had this problem too, hope this blog post is helpful to you.
As we were having some performance issues with Vampire Runner and we didn't have a clear idea of what was happening, we started trying some improvement techniques. The first one we implemented was a basic frustum culling technique to avoid trying to render objects outside of the screen.
First, we created an Artemis component named FrustumCullingComponent with a Rectangle representing the bounds of that entity to easily detect if the entity is inside the screen or not. For now, as it is a basic implementation, the rectangle was only modified when the entity was created. So, for example, if we know an entity was able to rotate during the game, then we create a bigger bounding box using box diagonal.
Then, we added a method to our custom 2d Camera implementation to get the camera frustum (by making the corresponding transformations).
Finally, we modified our Artemis render system to check before rendering if an entity has or not a FrustumCullingComponent, if it hasn't one, then we perform the render logic as we always did. If it has one, then we check if the bounds of that entity overlaps with the camera frustum, if it does, then we render as we always did, if it doesn't, then we avoid rendering that entity.
Here is an example of the bounds and the frustum of the camera:
In the image, the element (a) and (b) are rendered because their bounds overlaps with the camera frustum. The element (c) is not rendered because its bounds are totally outside the camera frustum.
For Vampire Runner, we didn't notice the difference of having this technique enabled or not since the game always render fast (on our devices) and we had no metrics of the render process time. However, as it was really easy to implement this basic version of the technique, we believe it should help to maintain render performance, and we can reuse the logic for all of our games.