Building 2d animations using Inkscape and Synfig

In this blog post we want to share a method to animate Inkscape SVG objects using Synfig Studio, trying to follow a similar approach to the Building 2d sprites from 3d models using Blender blog post.

A small introduction about Inkscape

Inkscape is one of the best open source, multi platform and free tools to work with vector graphics using the open standard SVG.

After some time using Inkscape, I have learned how to make a lot of things and feel great using it. However, it lacks of some features which would make it a great tool, for example, a way to animate objects by making interpolations of its different states defining key frames and using a time line, among others.

It has some ways to create interpolations of objects between two different states but it is unusable since it doesn't work with groups, so if you have a complex object made of a group of several other objects, then you have to interpolate all of them. If you make some modification on of the key frames, then you have to interpolate everything again.

Synfig comes into action

Synfig Studio is a free and open-source 2D animation tool, it works with vector graphics as well. It lets you create nice animations using a time line and key frames and lets you easily export the animation. However, it uses its own format, so you can't directly import an SVG. Luckily, the format is open and there are already some ways to transform from SVG to Synfig.

In particular I tried an Inkscape extension named svg2sif which lets you save files in Synfig format and seems to work fine (the page of the extension explains how to install it). I don't know possible limitations of the svg2sif Inkscape extension, so use it with caution, don't expect everything to work fine.

Now that we have the method defined, we will explain it by showing an example.

Creating an object in Inkscape

We start by creating an Inkscape object to be animated later. For this mini tutorial I created a black creature named Bor...ahem! Gishus Maximus:

Modelling Gishus Maximus using Inkscape

Here is the SVG if you are interested on it, sadly WordPress doesn't support SVG files as media files.

With the model defined, we have to save it as Synfig format using the extension, so go to "Save a Copy..." and select the .sif format (added by the svg2sif extension), and save it.

Animating the object in Synfig

Now that we have the Synfig file we open it and voilà, we can animate it. However, there is a bug, probably with the svg2sif extension and the time line is missing. To fix it, we have to create a new document and copy the shape from the one exported by Inkscape to the new one.

The next step is to use your super animation skill and animate the object. In my case I created some kind of eating animation by making a mouth, opening it slow and then closing it fast:

Animating Gishus Maxumis using Synfig

Here is the Synfig file with the animation if you are interested on it.

To export it, use the "Show the Render Settings Dialog" button and configure how much frames per second you want, among other things, and then export it using the Render button. You can export it to different format, for example, a list of separated PNG files for each animation frame or an animated GIF. However, it you can't configure some of the formats and the exported file is not what I wanted so I preferred to export to a list of PNG files and then use the convert tool to create the animated GIF:

Finally, I have a time lapse of how I applied the method if you want to watch it:

Extra section: Importing the animation in your game

After we have separated PNG files for the animation, we can create a sprite sheet or use another tools to create files to be easily imported by a game framework. For this example, I used a Gimp plug-in named Sprite Tape to import all the separated PNG files and create a sprite sheet:

If you are a LibGDX user and want to use the Texture Packer, you can create a folder and copy the PNG files changing their names to animationname_01, animationname_02, etc, and let Texture Packer to automatically import it.

Conclusions

One problem with this method is that you can't easily modify your objects in Inkscape and then automatically import them in Synfig and update the current animation to work with it. So, once you moved to Synfig you have to keep there to avoid making a lot of duplicated work. This could be avoided if Inkscape provided a good animation extension.

Synfig Studio is a great tool but not the best of course, it is not intuitive (as Gimp, Blender and others) and it has some bugs that make it explode without reason. On the other hand, it is open source, free and multi platform and the best part is that it works well for what we need right now 😉

This method allow us to animate vector graphics which is great since it is a way for programmers like us to animate their programmer art 😀

Finally, I am not an animation expert at all, so this blog post could be based on some wrong assumptions. So, if you are one, feel free to correct me and share your opinions.

As always, hope you like the post.

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

Implementing transitions between screens

Using transitions between game screens is a great way to provide smoothness between screen changes, for example, fade out one screen and then fade in the next one. The next video shows an example of those effects our Vampire Runner game.

In this post, we will show a possible implementation of transitions between screens using LibGDX, however the code should be independent enough to be easily ported to other frameworks.

Although we implemented it using the our own concept of GameState, we will try to use LibGDX Screen concept in this post to simplify understandability.

Implementation

The implementation is based in the concept of TransitionEffect. A TransitionEffect holds the render logic of one of the effects of the transition being performed.

class TransitionEffect {

	// returns a value between 0 and 1 representing the level of completion of the transition.
	protected float getAlpha() { .. }

	void update(float delta) { .. } 

	void render(Screen current, Screen next);

	boolean isFinished() { .. }

	TransitionEffect(float duration) { .. }
}

An implementation example of a TransitionEffect is a FadeOutTransitionEffect to perform a fade out effect:

class FadeOutTransitionEffect extends TransitionEffect {

	Color color = new Color();

	@Override
	public void render(Screen current, Screen next) {
		current.render();
		color.set(0f, 0f, 0f, getAlpha());
		// draw a quad over the screen using the color
	}

}

Then, in order to perform a transition between Screens, we need a custom Screen with the logic to apply render each transition effect and to set the next Screen when the transition is over. This is a possible implementation:

class TransitionScreen implements Screen {
	Game game;

	Screen current;
	Screen next;

	int currentTransitionEffect;
	ArrayList<TransitionEffect> transitionEffects;

	TransitionScreen(Game game, Screen current, Screen next, ArrayList<TransitionEffect> transitionEffects) {
		this.current = current;
		this.next = next;
		this.transitionEffects = transitionEffects;
		this.currentTransitionEffect = 0;
		this.game = game;
	}

	void render() {
		if (currentTransitionEffect >= transitionEffects.size()) {
			game.setScreen(next);
			return;
		}

		transitionEffects.get(currentTransitionEffect).update(getDelta());
		transitionEffects.get(currentTransitionEffect).render(current, next);

		if (transitionEffects.get(currentTransitionEffect).isFinished())
			currentTransitionEffect++;
	}
}

Finally, each time we want to perform a transition between two screens, we have to create a new TransitionScreen with the current and next Screens and a collection of effects we want. For example:

	Screen current = game.getScreen();
	Screen next = new HighscoresScreen();

	ArrayList<TransitionEffect> effects = new ArrayList<TransitionEffect>();

	effects.add(new FadeOutTransitionEffect(1f));
	effects.add(new FadeInTransitionEffect(1f));

	Screen transitionScreen = new TransitionScreen(game, current, next, effects);

	game.setScreen(transitionScreen);

As we mention before, we use our own concepts in our implementation. If you want to see our code take a look at the classes ApplicationListenerGameStateBasedImpl, GameState and GameStateTransitionImpl (do not expect the best code in the world).

Conclusion

Adding transitions between the game screens gives users a feeling of smoothness, and we believe it worth the effort.

Also, we like the current design lets you implement different effects for the transitions, we only shown fade out and fade in as example because they are really simple to implement and we are using only those for our games.

As always, hope you like the post.

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

Toasting with LibGDX Scene2D and Animation4j

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)

How we use Box2D with Artemis

As you may know from our previous posts or from your personal knowledge (obviously), Box2D is a 2D physics engine and Artemis is an Entity System Framework. Box2D is used to add physics behavior to games however it could be used only to detect collisions if you want (that means no dynamic behavior). In this post, we want to share a bit how we are using both frameworks together.

Introduction

The main idea is to react to physics events, like two bodies colliding, to perform some game logic. For example, whenever the main character ship touches an asteroid, it explodes.

When you use Artemis, the game logic is done in an Artemis System or a Script (custom), if you use our customization. The ideal situation would be if you could check in your game logic which entities are in contact or not. In order to make that work, you have to find a way to link a Box2D contact with an Artemis Entity and vice versa.

Our solution

The first thing we do is, to each Artemis Entity we want to have a physics behavior, we add a PhysicsComponent the Box2D Body of the Entity and a Contacts instance where all the Box2D contacts for that Body are stored. Also, in order to get the Entity from the Body, we set the its userData pointing to the Entity.

The Contacts concept gives us useful methods to get information about contacts and the API looks like this:

    getContactsCount() : int - returns the contacts quantity
    getContact(index: int) : Contact - returns the contact information

And our Contact concept API, returned by the Contacts getContact() method, looks like this:

    getMyFixture() : Fixture - returns the fixture in contact of the Contacts owner Entity.
    getOtherFixture() : Fixture - returns the fixture of the other Entity.
    getNormal() : Vector2 - returns the normal of the contact.

(note: we decided to make a deep copy of the contacts information since it is recommended in the Box2D manual if you use a ContactsListener)

Then, we have a ContactsListener (named PhysicsListener) which, whenever a contact is reported (begin or end), it gets the bodies from the contact and gets the entities from each body userData and then adds or removes the contact data to/from each Entity's PhysicsComponent using its Contacts instance.

(note: we decided to use a custom ContactListener since it is recommended in the Box2D manual)

Finally, in each Artemis System or Script, we use the Entity's PhysicsComponent to get the contacts data and we proceed to do the logic we want, for example, destroy the character or enable some special ability, etc.

Here is an example of how we use it inside a Script from our Leave me Alone game:

public void update(World world, Entity e) {
	PhysicsComponent physicsComponent = Components.getPhysicsComponent(e);
	
	Contacts contacts = physicsComponent.getContact();
	
	if (!contacts.isInContact())
		return;
	
	boolean shouldExplode = false;
	
	for (int i = 0; i < contacts.getContactCount(); i++) {
		
		Contact contact = contacts.getContact(i);
		Entity otherEntity = (Entity) contact.getOtherFixture().getBody().getUserData();
		
		GroupComponent groupComponent = Components.getGroupComponent(otherEntity);
		
		if (groupComponent == null)
			continue;
		
		if (groupComponent.group.equals(Groups.EnemyCharacter)) {
			shouldExplode= true;
			break;
		}
		
	}
	
	if (shouldExplode)
		eventManager.dispatch(Events.MainExploded, e);
}

If you use Box2D and you are starting to use Artemis or vice versa, hope this post could help you. Otherwise, I hope you like it.

Also, if you use Artemis with Box2D in another way, would be great to have your point of view.

Thanks.

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

Modifying textures using libGDX Pixmap in runtime - Explained

We have previously shown a bit how we were using LibGDX Pixmap to modify textures in runtime here and here for a game prototype we were doing. In this post I want to share more detail of how we do that. The objective was to make destructible terrain like in Worms 2.

Introduction

When you work with OpenGL textures, you can't directly modify their pixels whenever you want since they are on OpenGL context. To modify them you have to upload an array of bytes using glTexImage2D or glTexSubImage2D. The problem is you have to maintain on the application side an array of bytes representing the modifications you want to do.

To simplify working with byte arrays representing images, LibGDX provides a useful class named Pixmap which is a map of pixels kept in local memory with some methods to interact with a native library to perform all modifications with better performance.

Moving data from Pixmap to OpenGL Texture

In our prototypes, we wanted to remove part of the terrain whenever a missile touches it, like a Worms 2 explosion. That means we need some way to detect the collisions between the missile and the terrain and then a way to remove pixels from a texture.

We simplified the first problem by getting the color of the pixel only for the missile's position and checking if it was transparent or not. A more correct solution could be using a bitmap mask to check collisions between pixels but we wanted to simplify the work for now.

For the second problem, given a radius of explosion of the missile, we used the pixmap fillCircle method by previously setting the color to (0,0,0,0) (fully transparent) and disabled Pixmap blending to override those pixels.

But that only modified the pixmap data, now we needed to modify the OpenGL texture. To do that, we called OpenGL glTexImage2D using the bytes of the pixmap as the new texture data and that worked correctly.

Transforming from world coordinates to Pixmap coordinates

One problem when working with pixmaps is we have to map world coordinates (the position of the missile for example) to coordinates inside the Pixmap.


This image shows the coordinate system of the Pixmap, it goes from 0 to width in x and 0 to height in y.


This image shows how we normally need to move, rotate and resize the Pixmap in a game.

To solve this, we are using a LibGDX Sprite to maintain the Pixmap transformation, so we can easily move, rotate and scale it. Then, we can use that information to project a world coordinate to Pixmap coordinate by applying the inverse transform, here is the code:

	public void project(Vector2 position, float x, float y) {
		position.set(x, y);

		float centerX = sprite.getX() + sprite.getOriginX();
		float centerY = sprite.getY() + sprite.getOriginY();

		position.add(-centerX, -centerY);

		position.rotate(-sprite.getRotation());

		float scaleX = pixmap.getWidth() / sprite.getWidth();
		float scaleY = pixmap.getHeight() / sprite.getHeight();

		position.x *= scaleX;
		position.y *= scaleY;

		position.add( //
				pixmap.getWidth() * 0.5f, //
				-pixmap.getHeight() * 0.5f //
		);

		position.y *= -1f;
	}

(note: it is the first version at least, it could have bugs and could be improved also)

To simplify our work with all this stuff, we created a class named PixmapHelper which manage a Pixmap, a Texture and a Sprite, so we could move the Sprite wherever we wanted to and if we modify the pixmap through the PixmapHelper then the Texture was automatically updated and hence the Sprite (since it uses internally the Texture).

The next video shows how we tested the previous work in a prototype were we simulated cluster bombs (similar to Worms 2):

Some adjustments to improve performance

Instead of always working with a full size Pixmap by modifying it and then moved to the OpenGL texture, we created smaller Pixmaps of fixed sizes: 32x32, 64x64, etc. Then, each time we needed to make an explosion, we used the best Pixmap for that explosion and then we called glTexSubImage2D instead glTexImage2D to avoid updating untouched pixels. One limitation of this modification is we have to create and maintain several fixed size pixmaps depending on the modification size. Our current greater quad is 256x256 (almost never used).

Then, we changed to store each modification instead performing them in the moment the PixmapHelper erase method was called, and we added an update method which performs all modifications together. This improvement allow us to call Pixmap update method when we wanted, maybe one in three game updates or things like that.

Conclusion

Despite using LibGDX Pixmap for better performance, moving data to and from OpenGL context is not a cheap operation, on Android devices this could means some pauses when refreshing the modified textures with the new data. However, there is a lot of space for performance improvement, some ideas are to work only with pixmap of less bits instead RGBA8888 and use that one as the collisions context and as the mask of the real image (even using shaders), between other ideas.

Finally, the technique looks really nice and we believe that it could be used without problems for a simple game but it is not ready yet to manage a greater game like Worms 2.

Hope you like the technique and if you use it, maybe even also share your findings.

P.S.: In case you were wondering: yes, I love Worms 2.

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

Reusing Artemis entities by enabling, disabling and storing them

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.

Introduction

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.

Conclusion

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.

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

Basic frustum culling to avoid rendering entities outside screen

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.

Basic implementation

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.

Conclusion

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.

As always, hope you like it.

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

Simulating parallax scrolling for 2d game

In this post we want to share how we simulated parallax scrolling in Vampire Runner, a simple technique that could be used in any 2d game.

Introduction

The basic idea to simulate parallax is to work with different render layers and to move them at different speeds.

To easily understand the post, we will work with a basic example based on Vampire Runner graphics where we have three layers, the first layer is the background which is static, the second layer are the mountains and the third layer is the world layer where the main character runs.

In Vampire Runner, the main character is the center of the world, despite being running, he is in a fixed position on the screen while all the other objects move accordingly to give the correct idea.

To simulate the parallax, each layer of objects moves at different speeds to give the correct idea of depth. In case of Vampire Runner, the background layer is static, the mountains layer moves at 1/12 the speed of the main character and the world layer moves at the speed of the main character.

Simulating movement with cameras

We said before that the character is in a fixed position on the screen, however the real entity of the character is moving around the world, even more, he is running!.

To simulate him being in a fixed position, we have a camera following the character, so the player always see the character in the same position.

However, as all the other objects (obstacles, trees, etc) have a fixed position in the world when the camera follows the main character they move in the opposite direction. That is how we move the world layer and the mountains layer. The only difference is we move the mountains layer camera slower.

In conclusion, we have one camera for each layer and two of them move following the main character.

Using OpenGL model view matrices to configure the cameras

As we are using OpenGL through LibGDX (and LWJGL on desktop), we need to translate all the previous camera behavior to OpenGL.

In OpenGL, to simulate a world camera what you typically modify the model view matrix and then render the objects.

So, for Vampire Runner, we had three different matrices to render each layer, and the render method was something like this:

    1.1 configure background layer camera
    1.2 render background layer

    2.1 configure mountains layer camera
    2.2 render mountains layer

    3.1 configure world layer camera
    3.2 render world layer

In the update method we only had to update the cameras depending on the character position.

To simplify the work, if you are using LibGDX, you can use the Camera class which comes with a proper class for 2d games named OrthographicCamera. In our case we used a custom implementation which provided a nicer API to work with.

Conclusion

Working with different cameras with OpenGL is not so hard and it let you achieve a correct feeling when moving across the world.

As always, hope you like the post.

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

Resizable Applets and Applications with LWJGL

Some posts before, in the comments section, Gornova asked me to write about resizable Applets if I had some time. As I never used resizable LWJGL Applets, I had to do some research. This post is to show what I found.

(note: LWJGL version 2.8.2 was used for all the tests I made).

Introduction

LWJGL Applets are similar to LWJGL Applications, they work using a class named Display which uses an AWT Canvas component. On desktop, you create a JFrame or similar and add inside a Canvas, on Applet you just create the Canvas and add it to the Applet. Unless you want some custom behavior, I believe that is the common usage.

(note: using fullscreen is a different case but has no meaning for this post)

How to resize an Applet

To resize an Applet on the browser, two possible ways are, use Javascript to change the applet tag sizes or just configure the HTML applet tag to adapt to its container size, so if you resize the browser window then all corresponding HTML components are resized.

The other way around, suppose you have a way inside your game to choose the game resolution, you will have to communicate that to the Browser, probably calling a Javascript function from your Applet to let the Browser react to the change.

How to handle Applet resize

If you are working with LWJGL directly, then it depends a lot of how which kind of layout are you using for the container of the Canvas object. For example, if you chose a layout which grows to the parent container size, then each time you resize the container, the Canvas will be resized. If you chose another layout, then maybe you will call Canvas.setSize() by hand.

However, you need to react to that change in your game, to do that the best way (imho) is use a similar approach LibGDX does. What LibGDX does is, its stores the current Canvas size on each iteration of the main application loop, on the next iteration, if the Canvas size is different to the stored, then it calls a resize() method to tell your game the screen size changed.

Another way is to create a ComponentListener and add that to the Canvas component so each time the componentResized() method is called you resize your game. However as all the AWT stuff runs in another thread you need to store the new size and process the resize in your LWJGL thread to avoid problems.

What to do inside your game

The very basic approach is to just modify the OpenGL viewport of your game, then the game is scaled to the new size and, in some cases, that should be enough.

	glViewport(0, 0, width, height);

However, You may want to take care about aspect ratio since just scaling the game could look ugly. One option is to modify the viewport in values to maintain the aspect ratio you want, for example:

	glViewport(0, 0, width, width / aspectRatio);

You could also provide different common aspect ratios (4:3, 16:10, 16:9, etc). However, I believe the best option is to provide fixed commonly used resolutions like 640x480 or 800x600 instead.

In some cases you could want to adapt your game elements, for example GUI stuff, where you may want to maintain the element sizes and move them accordingly over the screen instead just scaling them.

Then, you have to take care of the user input. As mouse location is dependent on the viewport size, you will have to take that in mind when interacting with part of your application, like the GUI stuff, after a size change. For example, LibGDX Camera uses the current viewport size when using project and unproject methods (which allow you to transform world coordinates to viewport coordinates and vice versa).

Not so sure as I am not an OpenGL expert but if you work different cameras (model + projection matrices) you probably need to update them in order to render everything in the correct way. I have to go deeper in this issue.

Optionally, you may want make other changes when reacting to the resize like loading HD assets if you go to a higher resolution and vice versa.

Some issues

  • You have some glitches if you do resize in real time (tested myself, but cant find references right now). However, in general nobody does this so it is not a big problem.
  • I believe Applet resizing is not working on mac yet.

Conclusion

Handling all the mentioned things when resizing LWJGL Applets and LWJGL Applications depends a lot on the game you are making, in some cases the basic approach work fine and should be easy to implement.

Despite the article was focused mainly on LWJGL Applets, great part of the findings can be applied to LWJGL Applications as well.

This post is only to show some basic experimentation I made on the subject, as I said before, I am not an OpenGL nor LWJGL expert, so some assertions could be wrong. If you have more experience and want to contribute your opinion, feel free to do it.

Thanks and hope you like the post.

VN:F [1.9.22_1171]
Rating: 5.0/5 (1 vote cast)

Making buttons using Inkscape - part 3

This is the third part of the buttons tutorial series, in this case I will show how to make more complex shapes to be used inside the buttons.

As I did on previous posts, I will show images with the steps to follow to make each icon.


This image explains the steps to follow to make a question mark icon.

This image explains the steps to follow to make an icon for high scores.

Finally, a time lapse video showing how I made all the stuff:

Here is the link to download the question mark SVG and here is the link to download the high scores icon SVG.

As always, hope you like it.

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