Posts Tagged ‘android’

Our solution to handle multiple screen sizes in Android – Part three

Thursday, September 12th, 2013

In the previous posts of this series we talked about our solution to handle multiple screen sizes for game menus, in particular we showed the main menu of the game Clash of the Olympians. In this post we are going to talk about what we did inside the game itself. As a side note, the solution we used here is simple and specific for this game, hope it could help as example but don't expect a silver bullet.

Scaling to match the physics world

As we use Box2D in Clash of the Olympians, the first step was to use a proper scale between Box2D bodies and our assets. The basic approach was to consider that 1m (meter in MKS system) was 32px, so in our target resolution of 800x480 could show 25m x 15m. We picked that scale because it gives pretty numbers both in terms of the game area and in terms of our assets, for example, a character of 64px of height is 2m tall. In particular, Achilles has a height of approx 60px which is equivalent to 1.875m using our scale, that sounds pretty reasonable for that character.

clashoftheolympians-800x480
The image shows the relation between screen size in pixels (800x480 in this case) and the game world in meters.

Defining a virtual area to show

We previously said that we could show 25m x 15m, in fact, the height is not so important in Clash of the Olympians since the game mainly depends in the horizontal distance. So, if we had an imaginary with a resolution of 800x400 (really wide, an aspect ratio of 2) we would show in that case 12.5m of height, we could assume that if we show at least that height the game balance would be not affected at all (enemies are never spawned too high). However, in terms of horizontal distance we want to show always the same area across all devices to avoid changing the game balance (for example, if you could see less area you couldn't react in the proper time to some waves), that is why we decided to show always 25m in terms of width.

clashoftheolympians-800x600

The image shows how we still show the same game world width of 25m on a 800x600 device.

Scaling the world back to match the screen size

Finally, in order to show this virtual area of 25m x H (with H >= 12.5m), we have to calculate the proper scale to set our game camera in each device. For example, in the case of having a Nexus 7 (1280x720 resolution device) the scale to show 25m of horizontal size is 51.2x since we know that 1280 / scale = 25, then 1280 / 25 = 51.2. In the case of a Samsung Galaxy Y (480x320 resolution device) the scale would be 19.2x since 480 / 25 = 19.2. Translating this inside the game would be something as easy as:

camera.scale = screen.width / 25

Final thoughts

This is not a general solution, it depends a lot in the game we were making and the things we could assume like the game height doesn't matter.

Even though the solution is specific and not so cool as the previous posts, we hope it could be of help when making your own game.

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

Our solution to handle multiple screen sizes in Android – Part two

Wednesday, February 13th, 2013

Continuing with the previous blog post, in this post we are going to talk about the code behind the theory. It consists in three concepts, the VirtualViewport, the OrthographicCameraWithVirtualViewport and the MultipleVirtualViewportBuilder.

VirtualViewport

It defines a virtual area where the game stuff is contained and provides a way to get the real width and height to use with a camera in order to always show the virtual area. Here is the code of this class:

public class VirtualViewport {

	float virtualWidth;
	float virtualHeight;

	public float getVirtualWidth() {
		return virtualWidth;
	}

	public float getVirtualHeight() {
		return virtualHeight;
	}

	public VirtualViewport(float virtualWidth, float virtualHeight) {
		this(virtualWidth, virtualHeight, false);
	}

	public VirtualViewport(float virtualWidth, float virtualHeight, boolean shrink) {
		this.virtualWidth = virtualWidth;
		this.virtualHeight = virtualHeight;
	}

	public float getWidth() {
		return getWidth(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
	}

	public float getHeight() {
		return getHeight(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
	}

	/**
	 * Returns the view port width to let all the virtual view port to be shown on the screen.
	 * 
	 * @param screenWidth
	 *            The screen width.
	 * @param screenHeight
	 *            The screen Height.
	 */
	public float getWidth(float screenWidth, float screenHeight) {
		float virtualAspect = virtualWidth / virtualHeight;
		float aspect = screenWidth / screenHeight;
		if (aspect > virtualAspect || (Math.abs(aspect - virtualAspect) < 0.01f)) {
			return virtualHeight * aspect;
		} else {
			return virtualWidth;
		}
	}

	/**
	 * Returns the view port height to let all the virtual view port to be shown on the screen.
	 * 
	 * @param screenWidth
	 *            The screen width.
	 * @param screenHeight
	 *            The screen Height.
	 */
	public float getHeight(float screenWidth, float screenHeight) {
		float virtualAspect = virtualWidth / virtualHeight;
		float aspect = screenWidth / screenHeight;
		if (aspect > virtualAspect || (Math.abs(aspect - virtualAspect) < 0.01f)) {
			return virtualHeight;
		} else {
			return virtualWidth / aspect;
		}
	}

}

So, if we have a virtual area of 640x480 and want to show it on a screen of 800x480 we can do the next steps in order to get the proper values that we have to use as the camera viewport for that screen:

VirtualViewport virtualViewport = new VirtualViewport(640, 480);
float realViewportWidth = virtualViewport.getWidth(800, 480);
float realViewportHeight = virtualViewport.getHeight(800, 480);
// now set the camera viewport values
camera.setViewportFor(realViewportWidth, realViewportHeight);

OrthographicCameraWithVirtualViewport

In order to simplify the work when using LibGDX library, we created a subclass of LibGDX's OrthographicCamera with specific behavior to update the camera viewport using the VirtualViewport values. Here is its code:

public class OrthographicCameraWithVirtualViewport extends OrthographicCamera {

	Vector3 tmp = new Vector3();
	Vector2 origin = new Vector2();
	VirtualViewport virtualViewport;
	
	public void setVirtualViewport(VirtualViewport virtualViewport) {
		this.virtualViewport = virtualViewport;
	}

	public OrthographicCameraWithVirtualViewport(VirtualViewport virtualViewport) {
		this(virtualViewport, 0f, 0f);
	}

	public OrthographicCameraWithVirtualViewport(VirtualViewport virtualViewport, float cx, float cy) {
		this.virtualViewport = virtualViewport;
		this.origin.set(cx, cy);
	}

	public void setPosition(float x, float y) {
		position.set(x - viewportWidth * origin.x, y - viewportHeight * origin.y, 0f);
	}

	@Override
	public void update() {
		float left = zoom * -viewportWidth / 2 + virtualViewport.getVirtualWidth() * origin.x;
		float right = zoom * viewportWidth / 2 + virtualViewport.getVirtualWidth() * origin.x;
		float top = zoom * viewportHeight / 2 + virtualViewport.getVirtualHeight() * origin.y;
		float bottom = zoom * -viewportHeight / 2 + virtualViewport.getVirtualHeight() * origin.y;

		projection.setToOrtho(left, right, bottom, top, Math.abs(near), Math.abs(far));
		view.setToLookAt(position, tmp.set(position).add(direction), up);
		combined.set(projection);
		Matrix4.mul(combined.val, view.val);
		invProjectionView.set(combined);
		Matrix4.inv(invProjectionView.val);
		frustum.update(invProjectionView);
	}

	/**
	 * This must be called in ApplicationListener.resize() in order to correctly update the camera viewport. 
	 */
	public void updateViewport() {
		setToOrtho(false, virtualViewport.getWidth(), virtualViewport.getHeight());
	}
}

MultipleVirtualViewportBuilder

This class allows us to build a better VirtualViewport given the minimum and maximum areas we want to support performing the logic we explained in the previous post. For example, if we have a minimum area of 800x480 and a maximum area of 854x600, then, given a device of 480x320 (3:2) it will return a VirtualViewport of 854x570 which is a good match of a resolution which contains the minimum area and is smaller than the maximum area and has the same aspect ratio of 480x320.

public class MultipleVirtualViewportBuilder {

	private final float minWidth;
	private final float minHeight;
	private final float maxWidth;
	private final float maxHeight;

	public MultipleVirtualViewportBuilder(float minWidth, float minHeight, float maxWidth, float maxHeight) {
		this.minWidth = minWidth;
		this.minHeight = minHeight;
		this.maxWidth = maxWidth;
		this.maxHeight = maxHeight;
	}

	public VirtualViewport getVirtualViewport(float width, float height) {
		if (width >= minWidth && width <= maxWidth && height >= minHeight && height <= maxHeight)
			return new VirtualViewport(width, height, true);

		float aspect = width / height;

		float scaleForMinSize = minWidth / width;
		float scaleForMaxSize = maxWidth / width;

		float virtualViewportWidth = width * scaleForMaxSize;
		float virtualViewportHeight = virtualViewportWidth / aspect;

		if (insideBounds(virtualViewportWidth, virtualViewportHeight))
			return new VirtualViewport(virtualViewportWidth, virtualViewportHeight, false);

		virtualViewportWidth = width * scaleForMinSize;
		virtualViewportHeight = virtualViewportWidth / aspect;

		if (insideBounds(virtualViewportWidth, virtualViewportHeight))
			return new VirtualViewport(virtualViewportWidth, virtualViewportHeight, false);
		
		return new VirtualViewport(minWidth, minHeight, true);
	}
	
	private boolean insideBounds(float width, float height) {
		if (width < minWidth || width > maxWidth)
			return false;
		if (height < minHeight || height > maxHeight)
			return false;
		return true;
	}

}

In case the aspect ratio is not supported, it will return the minimum area.

Floating elements

As we explained in the previous post, there are some cases where we need stuff that should be always at fixed positions in the screen, for example, the audio and music buttons in Clash of the Olympians. In order to do that we need to make the position of those buttons depend on the VirtualViewport. In the next section where we explain how to use all together we show an example of how to do a floating element.

Using the code together

Finally, here is an example showing how to use these concepts in a LibGDX application:

public class VirtualViewportExampleMain extends com.badlogic.gdx.Game {

	private OrthographicCameraWithVirtualViewport camera;
	
	// extra stuff for the example
	private SpriteBatch spriteBatch;
	private Sprite minimumAreaSprite;
	private Sprite maximumAreaSprite;
	private Sprite floatingButtonSprite;
	private BitmapFont font;

	private MultipleVirtualViewportBuilder multipleVirtualViewportBuilder;

	@Override
	public void create() {
		multipleVirtualViewportBuilder = new MultipleVirtualViewportBuilder(800, 480, 854, 600);
		VirtualViewport virtualViewport = multipleVirtualViewportBuilder.getVirtualViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
		
		camera = new OrthographicCameraWithVirtualViewport(virtualViewport);
		// centers the camera at 0, 0 (the center of the virtual viewport)
		camera.position.set(0f, 0f, 0f);
		
		// extra code
		spriteBatch = new SpriteBatch();
		
		Pixmap pixmap = new Pixmap(64, 64, Format.RGBA8888);
		pixmap.setColor(Color.WHITE);
		pixmap.fillRectangle(0, 0, 64, 64);
		
		minimumAreaSprite = new Sprite(new Texture(pixmap));
		minimumAreaSprite.setPosition(-400, -240);
		minimumAreaSprite.setSize(800, 480);
		minimumAreaSprite.setColor(0f, 1f, 0f, 1f);
		
		maximumAreaSprite = new Sprite(new Texture(pixmap));
		maximumAreaSprite.setPosition(-427, -300);
		maximumAreaSprite.setSize(854, 600);
		maximumAreaSprite.setColor(1f, 1f, 0f, 1f);
		
		floatingButtonSprite = new Sprite(new Texture(pixmap));
		floatingButtonSprite.setPosition(virtualViewport.getVirtualWidth() * 0.5f - 80, virtualViewport.getVirtualHeight() * 0.5f - 80);
		floatingButtonSprite.setSize(64, 64);
		floatingButtonSprite.setColor(1f, 1f, 1f, 1f);
		
		font = new BitmapFont();
		font.setColor(Color.BLACK);
	}
	
	@Override
	public void resize(int width, int height) {
		super.resize(width, height);
		
		VirtualViewport virtualViewport = multipleVirtualViewportBuilder.getVirtualViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
		camera.setVirtualViewport(virtualViewport);
		
		camera.updateViewport();
		// centers the camera at 0, 0 (the center of the virtual viewport)
		camera.position.set(0f, 0f, 0f);
		
		// relocate floating stuff
		floatingButtonSprite.setPosition(virtualViewport.getVirtualWidth() * 0.5f - 80, virtualViewport.getVirtualHeight() * 0.5f - 80);
	}
	
	@Override
	public void render() {
		super.render();
		Gdx.gl.glClearColor(1f, 0f, 0f, 1f);
		Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
		camera.update();
		
		// render stuff...
		spriteBatch.setProjectionMatrix(camera.combined);
		spriteBatch.begin();
		maximumAreaSprite.draw(spriteBatch);
		minimumAreaSprite.draw(spriteBatch);
		floatingButtonSprite.draw(spriteBatch);
		font.draw(spriteBatch, String.format("%1$sx%2$s", Gdx.graphics.getWidth(), Gdx.graphics.getHeight()), -20, 0);
		spriteBatch.end();
	}

	public static void main(String[] args) {
		LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();

		config.title = VirtualViewportExampleMain.class.getName();
		config.width = 800;
		config.height = 480;
		config.fullscreen = false;
		config.useGL20 = true;
		config.useCPUSynch = true;
		config.forceExit = true;
		config.vSyncEnabled = true;

		new LwjglApplication(new VirtualViewportExampleMain(), config);
	}

}

In the example there are three colors, green represents the minimum supported area, yellow the maximum supported area and red represents the area outside. If we see red it means that aspect ratio is not supported. There is a floating element colored white, which is always relocated in the top right corner of the screen, unless we are on an unsupported aspect ratio, in that case it is just located in the top right corner of the green area.

The next video shows the example in action:

UPDATE: you can download the source code to run on Eclipse from here.

Conclusion

In these two blog posts we explained in a simplified way how we managed to support different aspect ratios and resolutions for Clash of the Olympians, a technique that could be used as an acceptable way of handling different screen sizes for a wide range of games, and it is not hard to use.

As always, we hope you liked it and that it could be useful for you when developing your games. Opinions and suggestions are always welcome if you want to comment :) and also share it if you liked it and think other people could benefit from this code.

Thanks for reading.

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

Our solution to handle multiple screen sizes in Android - Part one

Tuesday, January 22nd, 2013

Developing games for multiple devices is not an easy task. Given the variety of devices, one of the most common problem is having to handle multiple screen sizes, which means different resolutions and aspect ratios.

In this blog post we want to share what we did to minimize this problem when making Ironhide's Clash of the Olympians for Android.

In the next sections we are going to show some common ways of handling the multiple screens problem and then our way.

Stretching the content

One common approach when developing a game is making the game for a fixed resolution, for example, making the game for 800x480.

Based on that, you can have the next layout in one of your game's screens:


Main screen of Clash of the Olympians in a 800x480 device.

Then, to support other screen sizes the idea is to stretch the content to the other device screen:


Main screen on a 800x600 device, stretched from 800x480.

The main problem is that the aspect ratio is affected and that is visually unacceptable.

Stretching + keeping aspect ratio

To solve part of the previous problem, one common technique is stretching but keeping the correct aspect ratio by adding dead space to the borders of the screen so the real game area aspect ratio is the same on different devices. For example:


Main screen in a 800x600 device with borders.


Main screen in a 854x480 device with borders.

This is an easy way to attack this multiple screen size problem, you can even create some nice borders instead of the black borders shown in the previous image to improve how it looks.

However, in some cases this is not acceptable either since it doesn't look so good or it feels like the game wasn't made for that device.

Our solution: Using a Virtual Viewport

Our approach consists in adapting what is shown in the game screen area to the device screen size.

First, we define a range of aspect ratios we want to support, for example, in the case of clash we defined 4:3 (800x600) and 16:9 (854x480) as our border case aspect ratios, so all aspect ratios in the middle of those two should be supported.

Given those two aspect ratios, we defined our maximum area as 854x600 and our minimum area as 800x480 (the union and intersection between 800x600 and 854x480, respecively). The idea is to cover the maximum area with stuff, but the important stuff (buttons, information, etc) should be always included in the minimum area.


The red rectangle shows the minimum area while the blue rectangle shows the maximum area.

Then, given a device resolution we calculate an area that matches the device aspect ratio and is included in the virtual area. For example, given a device with a resolution of 816x544 (4:3), this is what is shown:


The green rectangle shows the matching area for 816x544.


This is how the main screen is shown in a 816x544 device.

In case we are on a bigger or lower resolution than the maximum or minimum area we defined, respectively, for example a screen of 480x320 (3:2), what we do is calculate the aspect ratio and find a corresponding match for that aspect ratio in the area we defined. In the case of the example, one match could be 800x534 since it is 3:2 aspect ratio and it is inside our virtual area. Then we scale down to fit the screen.


The green rectangle shows the calculated area for a resolution of 800x534 (matching the aspect of the 480x320 device).


This is what is shown of the main screen in a 480x320 device (click to enlarge the image).

Floating elements

For some elements of the game, such as buttons, maintaining their fixed world position for different screen sizes doesn't look good, so what we do is making them floating elements. That means they are always at the same screen position, the next images shows an example with the main screen buttons:


Main screen's buttons distribution for a 854x480 device.


Main screen's buttons distribution for a 800x600 device. As you can see, buttons are relocated to match the screen size.

Finally, we want to show a video of this multiple screen sizes auto adjustment in real time:


Adjusting the game to the screen size in real time.

Some limitations

As we are scaling up/down in some cases to match the corresponding screen, some devices could perceive some blur since we are using linear filtering and the final position of the elements after the camera transformations could be not integer positions. This problem is minimized with better density devices and assets.

Layouts could change between different devices, for example, the layout for a phone could be different to the layout of a tablet device.

Text is a special case, when rendering text just downscaling it is not a correct solution since it could be not readable. You may have to re-layout text for lower resolution devices to show it bigger and readable.

Conclusion

If you design your game screens follow this approach, it is not so hard to support multiple screen sizes in an acceptable way. However there is still a lot of detail to take care of, like the problems we talked in the previous section.

In the next part of this blog post we will show some code based on LibGDX for those interested in how we implemented all this.

Thanks for reading and hope you liked it.

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

Clash of the Olympians for Android

Saturday, January 5th, 2013

For the last eight months approx we were working with Ironhide Game Studio on a port to Android of their game Clash of the Olympians originally made for Flash. We are happy to announce that it was released on Google Play on last December 6th.

It is not a direct port since it has new features like bonuses for making combos during the game, new enemy behaviors, a hero room to see your score when you finish the game and multiple save slots. Also, the game mechanics changed a bit since they were adapted to touch devices and the game was rebalanced to match the new controls.

If you didn't already, go and get it on Google Play:

https://play.google.com/store/apps/details?id=com.ironhide.games.clashoftheolympians

QR code:

Hope you enjoy it.

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

Android and Desktop games internationalization using Java and LibGDX

Wednesday, May 23rd, 2012

Recently, we had to add multiple language support for a game we are developing. As you may know, Java provides classes to simplify the task of making your application available in multiple languages. In this post we want to share a bit our experience when using Java localization classes in a LibGDX application to provide multiple language support for both Android and desktop platforms.

Quick introduction

Java provides a class named ResourceBundle which provides a way to store resources (mainly strings) for a given locale, so you can ask for a string identified by a key and it will return the text depending the current locale. You can read the article Java Internationalization: Localization with ResourceBundles if you want to know more about how to use Java classes for internationalization. The rest of the post assumes you know something about Locale and ResourceBundle classes.

Why we don't use Android resources

Android provides also a way to support multiple locale resources but it depends on Android API, so we prefer to use the Java API instead which should work on all platforms.

Our experience when using Java internationalization on Android

When letting ResourceBundle to automatically load resources bundles from properties files, Java expects them to be in ISO-8859-1 encoding. However, it seems Android behaves in a different way and expects another encoding by default. So, when resource bundles are automatically loaded in Android from an ISO-8859-1 properties file with special characters, it loads them wrong.

The first try

The first solution we tried to fix this was to call ResourceBundle.getBundle() method using a custom Control implementation which creates PropertyResourceBundles using an InputReader with the correct encoding. Here is a code example to achieve that:

public class EncodingControl extends Control {

	String encoding;

	public EncodingControl(String encoding) {
		this.encoding = encoding;
	}

	@Override
	public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) 
			throws IllegalAccessException, InstantiationException, IOException {
		String bundleName = toBundleName(baseName, locale);
		String resourceName = toResourceName(bundleName, "properties");
		ResourceBundle bundle = null;
		InputStream inputStream = null;
		try {
			inputStream = loader.getResourceAsStream(resourceName);
			bundle = new PropertyResourceBundle(new InputStreamReader(inputStream, encoding));
		} finally {
			if (inputStream != null)
				inputStream.close();
		}
		return bundle;
	}
}

After that, we customized the Control class to work with LibGDX FileHandle in order to place the properties files in the assets folder. Here is the final code for our Control implementation:

public class GdxFileControl extends Control {

	private String encoding;
	private FileType fileType;

	public GdxFileControl(String encoding, FileType fileType) {
		this.encoding = encoding;
		this.fileType = fileType;
	}
	
	public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) 
			throws IllegalAccessException, InstantiationException, IOException {
		// The below is a copy of the default implementation.
		String bundleName = toBundleName(baseName, locale);
		String resourceName = toResourceName(bundleName, "properties");
		ResourceBundle bundle = null;
		FileHandle fileHandle = Gdx.files.getFileHandle(resourceName, fileType);
		if (fileHandle.exists()) {
			InputStream stream = null;
			try {
				stream = fileHandle.read();
				// Only this line is changed to make it to read properties files as UTF-8.
				bundle = new PropertyResourceBundle(new InputStreamReader(stream, encoding));
			} finally {
				if (stream != null)
					stream.close();
			}
		}
		return bundle;
	}
}

And that can be called in this way:

	ResourceBundle.getBundle("messages", 
		new GdxFileControl("ISO-8859-1", FileType.Internal))

That worked really well until we discovered that Android API sucks and doesn't support ResourceBundle.Control before API level 9, that means our solution works only for users with Android 2.3+. That's a problem since we want to support 2.0+, so we had to think another way to solve this.

The second try

After some tests, we discovered that if we construct a PropertyResourceBundle using an InputStream, the expected encoding is ISO-8859-1 for both desktop and Android. That means that, if we use that specific PropertyResourceBundle constructor, we don't have to force the encoding. So, the new solution consists in building a PropertyResourceBundle for each locale and configuring the hierarchy ourselves by setting their parent ResourceBundle. Here is an example of what we do now:

	FileHandle rootFileHandle = Gdx.files.internal("data/messages.properties");
	FileHandle spanishFileHandle = Gdx.files.internal("data/messages_es.properties");
	ResourceBundle rootResourceBundle = new PropertyResourceBundle(rootFileHandle.read());
	ResourceBundle spanishResourceBundle = new PropertyResourceBundle(spanishFileHandle.read()) {{
		setParent(rootResourcebundle);
	}};

After that we created a map of ResourceBundles for each Locale we support, so we can call something like:

	ResourceBundle resourceBundle = getResourceBundle(new Locale("es"));

The good part is this solution works well for both Android and desktop despite the Android API level (PropertyResourceBudndle seems to be supported from API Level 1). The bad part is that we lost the ResourceBundle logic to automatically build the hierarchy of resources and we had to do that manually now.

UPDATE: The class we use for this stuff is available in our commons-gdx project, resources module with the name of ResourceBundleResourceBuilder.

Conclusion

Supporting multiple languages in an application is a way to say users of all around the world you care about them but translating text to several languages is not cheap at all, however, Java provides a good framework to simplify the job if you decide to support internationalization.

And as a side conclusion: never assume all the Java classes you are using are implemented for the minimum Android API you are targeting.

References

Vampire Runner version 1.0.4

Saturday, February 25th, 2012

There is a new version of Vampire Runner available, we changed to use a custom solution to store high scores and removed OpenFeint from the game.

One reason for that change was, we were experiencing a long delay when OF dialog loaded for the first time, and we believe some players preferred to close the game instead waiting for the OF dialog to show up. We wanted a seamless system which doesn't damage the user experience in any way.

Another reason for removing OF was that we wanted to have best scores by day, week, month and we couldn't do that easily using OF.

Finally, we can use now the scores server in both PC and Android devices without having to make custom code for each platform, something not so good when using OF (could be great if they add a desktop backend).

Don't get us wrong, OpenFeint is a great solution, it gives a lot of features (scores, achievements, friends and more) and it is not so hard to integrate in your Android project (although the typical way is not so clean). However, for now, we prefer to use our custom solution for our simple and casual games.

Since Christmas happened long ago now, we decided to remove all related decoration and add new one, hope you like it.

Here is the list of changes of the update:

  • Removed OpenFeint, using custom solution for scores with support for today, weekly and monthly best scores.
  • Removed Christmas theme.
  • Added alert to show new updates available (for future versions).

Here is the QR-code if you want to easy access from your Android device:


Vampire Runner Android Market Vampire Runner Icon

Android Market

Enjoy it.

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

Vampire Runner version 1.0.3 - some performance improvements

Thursday, January 5th, 2012

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:

  • Improved performance.
  • Improved graphics.
  • 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:


Vampire Runner Android Market Vampire Runner Icon

Android Market

Hope this new version works better as it is working for us and enjoy the game.

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

Vampire Runner Christmas Edition on Android Market

Friday, December 16th, 2011

We wanted to make something special for our most successful game and our players so we added some Christmas happiness to Vampire Runner:

Vampire Runner

The changes for this version were:

  • Christmas Theme - Presents, Trees, Christmas Hats, and Snow.
  • Musics are disabled the first time you run the game, to avoid a bug between OpenFeint dialog and LibGDX (you can enable the music in the main menu screen).
  • For the Android Version - We now support paging on our highscore screen so you can see more scores.
  • Created Vampire Runners Facebook Page and added a button to go there from the Credits Screen.

Here is the QR-code if you want to easy access from your Android device:


Vampire Runner Android Market Vampire Runner Icon

Android Market

If you installed and liked the game, please rate it on the market, and share it with your friends and everyone you know.

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

Vampire Runner version 1.0.0 on Android Market

Tuesday, December 6th, 2011

We were working hard to make a new release of Vampire Runner with some big changes.

Mainly, all graphics assets were remade by Estudio Egg, so the game looks tons of times nicer now. Take a look:

Then, we also improved game mechanics by adding different transformations to the vampire to move through different obstacles, so the game is a bit more interesting now.

Finally, if you play the game on Android, we also added OpenFeint integration, so if you already use OpenFeint with friends, you can compete with them to be the best Vampire Runner.

Here is the QR-code if you want to easy access from your Android device:


Vampire Runner Android Market

Android Market

The game changed a lot from what it was, hope you enjoy the changes.

If you installed and liked the game, please rate it on the market, and share it with your friends and everyone you know.

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

Super Flying Thing - Update 09

Wednesday, October 5th, 2011

There is a new version of Super Flying Thing available, here is the change log:

  • Changed to count the best time to end a level
  • Modified random level generation and changed random mode to be named training
  • Removed practice mode, go to training now
  • Removed Exit button, you can exit the game pressing back button on main menu
  • Added sound for the explosions
  • Added about us screen with links to blog and more games

Remember, you can play it right now, just follow the next links:

PLAY ON PC or PLAY ON ANDROID:

Play on Android

Hope you enjoy it.

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