Some time ago I’ve started to prototype a multiplayer game, it is some kind of super simplified RTS game for mobile devices where macro decisions are encapsulated into one action through a button.

First versions were prototyped in a multiplayer hot seat fashion by using only one device (a tablet or a phone), that allowed me to quickly iterate between different ideas and find fun as soon as possible. That was a successful approach since the idea of the game proved that it was indeed fun to play with friends, so the next step was to go remote multiplayer with two or more devices.

Since networking is a whole new world for me, I started by reading lots of different articles about making multiplayer games.

The first thing to know is that the common solutions around depend on each kind of game, and knowing that beforehand helps you deciding the best solution for your game, and how your game must be adapted to support it.

In my case, I am developing a really simplified version of a RTS game for mobile, similar to Clash Royale. It is a 1v1 game where each player controls multiple units by giving high level orders like “everyone attack!” or “build new supply depot”.

The common networking approach for this kind of games, where synchronizing the whole world is a bit heavy given there are tons of units, is to do a synchronized simulation where only the main actions are transmitted (to save bandwidth) and each machine/device perform the same simulation. This implies the game should be deterministic in order to avoid desynchronization between players, so given one start state of the game and a list of actions over time, the final state should be always the same.

Making a game deterministic is a really hard problem, but it also has its rewards, like being able to replay the game given the actions of each player over time. This is a great debug tool for developers and at the same time a great freature for players since it is used to see other strategies or to share a great victory with your friends, everything with almost no storage cost.

The idea is to start writing my findings in the remote multiplayer journey to share all the lessons learned.

References

These are some of the articles I read:

What every programmer needs to know about game networking

1500 Archers on a 28.8: Network Programming in Age of Empires and Beyond

Fast-Paced Multiplayer

Why adding multiplayer makes game coding twice as much work

Core network structures for games

Making Fast-Paced Multiplayer Networked Games is Hard

How to create an online multiplayer game with Unity

Networking in Unity

Creating a Cross-Platform Multiplayer Game in Unity

Understanding Fighting Game Networking

Desyncs and FPU synchronization

Cross platform RTS synchronization and floating point indeterminism

Minimizing the Pain of Lockstep Multiplayer

The Tech of Planetary Annihilation: ChronoCam

Synchronous RTS Engines and a Tale of Desyncs

Don’t Store That in a Float

Developing your own Replay System


We want to talk a bit about how we migrated from our custom highscores system to use Google Play Game Services (GPGS) Leaderboards for Vampire Runner and the consequences of that change.

Before GPGS was released, we worked on our custom solution for highscores for Vampire Runner. That solution consisted in having scores for multiple time intervals (daily, weekly, monthly and all times scores) and letting guest users play and make scores without the need to log in. You could play the game, make scores and then, if you thought your scores were good, link those scores with your name, really simple and easy, it worked fine.

That custom solution was running on an amazon server and costed about 15 USD/month and since the game was making around that money with the ads, we thought it was acceptable.

A while after GPGS was released, we thought, why maintain and pay money for our own server when we can use GPGS instead? It was very logic, they have some of the features we had on our system and everybody was starting to use it. Also, we trust Google, so we changed Vampire Runner to use GPGS.

However, some time after we changed Vampire Runner, we started to see an important decrease in the number of people playing the game. The problem was something we were aware of but we thought it wouldn’t be so significant. We had a lot of players that didn’t have a Google account or even Google Play (they probably downloaded the game from other store), and they couldn’t log in to compete with other players so the game was less interesting for them since part of our game is based on that, competing to be better than other players.

The truth is the game is not a good game by itself and the main thing that kept our players was being able to compete with others (for a while at least), now that we are forcing them to log in they feel it isn’t worth it so they just go away or they play without logging in, hence without making scores.

Conclusion

We don’t think Google Play Game Services is the bad guy here but it is not good if you want to capture users from outside Google, same example would apply if we had forced Facebook or Twitter accounts. So if you have a game where you need players to catch other players, consider that. Of course, if you have a great game maybe with only Facebook, Google or Twitter you could keep your game alive but if you consider the three of them, you will get more players. In our case, we had all the world and then we restricted our game to only G+ accounts and that is why we lost players.

That was part of the story of the dying Vampire Runner, hope you like it.


Hi guys, long time no see.

It’s been a while since we came here and write, and we want to share why.

What happened

By the end of 2012, after we finished Clash of the Olympians to Android and iOS working hand in hand with Ironhide Game Studio, we had no ideas to work on. We weren’t really excited in working by ourselves anymore because we didn’t feel we could create something of the quality of Clash. Also, we really enjoyed working with Ironhide’s team. In addition, Ironhide was looking for programmers and they told us they enjoyed working with us as well, so they offered us a job and we couldn’t refuse (and we are still glad we did not).

Working at Ironhide

Two words: Indescribable awesomeness.

We are part of an excellent and diverse team composed by artists, developers, game designers and more. The workplace is comfy and the game development workflow is pretty dynamic. We can participate in a lot of game decisions and that rocks!

Working really close with artists allowed us to validate how much we needed one at Gemserk to define ideas and visualize, in an easy way, how our games should look like. It also works as motivation since you really want to see that art in the game.

Game design was another flaw at Gemserk, and we now see and understand it much better.

We learn new stuff each day and we also collaborate and share our knowledge to make the game and the team better. And at the end of the day, that feels really good. We hope it lasts long.

What about Gemserk

As company, Gemserk is kinda dead. We never reached what we wanted with our creations, and in those terms, we weren’t successful. However, we don’t see Gemserk as a failure either since we accomplished a lot in terms of technical knowledge and relationship with other game developers and tool makers and we are really happy with that.

We have no plans to work on anything Gemserk related for now but we believe we still have some stuff to share.

Thanks for reading our blog and hope we could still write interesting posts in the future.

The Gemserk team.


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.


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.