Expatriado

El pasado Jueves vendí mi coche, el Viernes unos amables transportistas se llevaron el contenido de mi piso, y el Sábado entregué las llaves del mismo. En 1999 abandoné la casa de mis padres y ayer, 12 años y 5 pisos después, abandoné Galicia y, en breve, abandonaré España también. Todavía pasaré dos semanas de transición en levante, pero mi llegada a Suiza es inminente.

Ayer, antes de embarcar en el avión, estaba muy nervioso, incluso más que cuando tuve mi primera entrevista de trabajo que, por cierto, duró unas 3 horas. Evidentemente, esta situación no tenía nada que ver con el propio vuelo, sino con la simbología implícita. Estaba dando el paso, iniciando el proceso de cambio, y a partir de ese momento, todo sería diferente. Sorprendentemente, cuando aterricé en Alicante, la gente seguía teniendo dos brazos y dos piernas, seguían hablando castellano y seguían amontonándose de forma absurda para terminar tardando lo mismo en salir del avión..

Quizás por la acumulación de nervios, quizás por la temperatura infernal en los vuelos de ryanair, o por la combinación de estos elementos con el cansancio, ayer me acosté con 37’5 grados de fiebre. La reacción del cuerpo humano al miedo es muy curiosa. No fue la primera vez que tuve fiebre tras una situación de muchos nervios y estrés.

La desorganización de ryanair durante el embarque tampoco ayudó mucho. Cuando la megafonía del aeropuerto SCQ ya estaba dando el último aviso a los pasajeros para embarcar urgentemente, todavía no había entrado nadie al avión, la cola atravesaba varias puertas de embarque diferentes, y la gente estaba muy desorientada, intentando meterse por todos los pasillos posibles con la esperanza de que los que guardábamos cola rigurosamente fuésemos idiotas. Tuve la suerte de toparme con un experimentado en este tipo de vuelos que me aconsejó quedarme en la cola, y me explicó que esa situación de caos era habitual y que la gente acabaría volviendo a la cola tarde o temprano. Dado que los asientos con ryanair no están numerados, también pude contemplar diversas técnicas más o menos elaboradas para intentar colarse. – No, si yo no vengo a colarme, vengo a informarme, pero ya que estoy aquí es tontería volver al final de la cola.

Dentro de dos semanas seré un inmigrante en Suiza. Dicen que esta experiencia cambia tu forma de percibir el mundo y a las personas. Como mínimo será un cambio de cultura e idioma radical. Aprovecharé la ocasión para aprender alemán y perfeccionar mi inglés, pues por la calle se habla “por defecto” alemán, y en la empresa se habla por norma inglés. Soy un afortunado, y estoy acojonado!

Posted in expat | 2 Comments

The one and only

I used to have several blogs with a very clear topic and very focused. I am sure this is the right path to go if you intend to become a professional publisher/writer. This has been never my case, because I just wanted to share my thoughts and learning about these topics. Of course I feel better if lots of people read my blogs, but ultimately, this is not the reason why I write them.

I have had an spanish blog about programming topics (the defunct pinguino.dyndns.org), another one about animation (squash y stretch), and an english blog about Android development (The organic android).

Now I am moving to Switzerland, and my friends started to ask me to write a blog about my expat experiences, and I thought “another blog? oh my!”. Actually, it happened several times that I had something to say, something that doesn’t fit in just 140 characters, something that could be better understood with images and even some markup, and did not fit into these topics covered by my blogs. Something had to be done!

Finally, I decided to merge all my blogs in a single one, multi-topic, and even multi-language. This is my new blog, and it will be the only one from now on.

Posted in Uncategorized | Tagged , | 3 Comments

Tater Hater, you have to try it!

Some time ago, I wrote an article about memory management in Android that was the result of some research with my friend Sergio about his own game. Now he has ended the first version of this game: Tater Hater, which you can download from the Android Market. But remember to try first the Lite version and give him some feedback before purchasing the great complete version.

Here you have the links to the android market web site:

I wish Sergio the best of luck with this new Android project, and I wish you to have lots of fun with his game.

Posted in android | Tagged | 1 Comment

OTempo is now open-source

After a long time of learning stuff about the android ecosystem, I have finally decided to go open-source, and even remove advertisement from OTempo in the source code. This has several implications:

  1. You can now contribute to this project if you have some programming or artistic skills.
  2. I will continue to publish new versions of OTempo in the market, completely free of Ads, as significant changes happen in the source code.
  3. Yes, the next version of OTempo in the market will be completely free of Ads.
You can check the google code page for the open-source project here:

http://code.google.com/p/otempo/

If you want to contribute to this project, download the code, play a bit with it, and when you feel confident to make some improvements, either send me a patch or ask me for write permission in the SVN repo.

| Tagged ,

Baking game levels in Egg Savior

This article covers the way Egg Savior handles the rendering of static objects in order to save both CPU and APK size. The method presented is implemented into the last version of Egg Savior and is working really well, given the limited size of game levels.

The problem

Egg Savior currently has 30 levels. Each one of these levels include a generic background and a lot of bricks that act as platforms for the main character (the chicken). The bricks are all 64×64 pixels in size, and placed in a grid. The obvious yet inefficient way of rendering and interacting with bricks is to handle all of them one by one:

for brick in brick_list:
    brick.render()
    character.detect_collision(brick)

This code is inefficient for two reasons:

  1. Renders the same bricks in the same way all the time, one by one.
  2. Forces to detect collisions with every single brick, even if they are stuck together creating a larget platform

The bricks are static, they don’t change during the gameplay. For this reason, it would be faster to render them just once into an intermediate buffer, and then just render this buffer on each frame. This saves a lot of CPU time at the expense of more memory usage. If you have huge levels it may not be a good solution, because devices limit the amount of memory granted to each application to a quite small value. For Egg Savior this worked very well, because the size of levels is somehow limited.

Different backgrounds

The first version of Egg Savior had only 10 levels, and the approach was to have a different background image for each level, with the bricks already included into it. It worked really well, but as more levels were added, it proved not very scalable, because each new level added a lot of data to the APK. This approach meant brick objects to be just invisible rectangles, without render code, because they were already drawn into the background. This enabled a way to optimize also point 2, because there were no reason for defining each brick individually. If three bricks were stuck together in a row, they were defined as a single larger brick, thus enabling less time to process collisions.

Run-time baking

The second iteration of the design, focused on solving the scalability problem with an algorithm that allowed baking the bricks above the background when loading a level. This also involved a way to easily define where to place the bricks. The solution was to use strings with spaces on empty cells and hashes on brick cells:

String levelPattern[] = {
        "           ",
        "           ",
        "#   #      ",
        "##  # #    ",
        "   ## # #  ",
        "## ## # # #",
};

With this language to define brick positions, we already know where to place the bricks on the background. Anyway, there is still a problem to solve: brick shape change depending on its neighbours. If a brick is the first or the last in a row, it has round corners, in other case, it has sharp corners in order to blend with the next or previous one. This leaves us with four cases to handle, depending on the previous, current, and next brick (the current brick is in the middle):

  1. [_#_]: The brick doesn’t have neighbours.
  2. [##_]: The brick has only a neighbour on the left.
  3. [_##]: The brick has only a neighbour on the right.
  4. [###]: The brick has neighbours on both sides.
Four brick shapes with enhanced contrast.

The algorithm to generate the background with the tiles is as follows (I removed some obvious code to compute drawBitmap rectangles to enhance algorithm readability):

public static Bitmap bake(String[] rows, Bitmap baseBackground) {
    int nRows = rows.length;
    int nCols = rows[0].length();
    Bitmap newBitmap = Bitmap.createBitmap(nCols * TILE_SIDE, nRows * TILE_SIDE, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(newBitmap);
    canvas.drawBitmap(baseBackground, null, ..., null);
    
    for (int row = 0; row < nRows; row++) {
        for (int col = 0; col < nCols; col++) {
            char left = '#';
            char right = '#';
            if (col > 0) {
                left = rows[row].charAt(col-1);
            }
            if (col < nCols - 1) {
                right = rows[row].charAt(col+1);
            }
            char c = rows[row].charAt(col);
            Bitmap toRender = getTile(left, c, right);
            if (toRender != null)
            {
                canvas.drawBitmap(toRender, null, ..., null);
            }
        }
    }  
    return newBitmap;
}

The getTile method just handles the four cases mentioned earlier, and returns the right bitmap from the app resources.

Automatic collision optimization

The baking of the bricks into the background solved the render part of the original problem (point 1). The bricks, which now consisted only in invisible rectangles, were defined by hand, looking at the hashes and chosing a smart way of arranging them in a minimum set of rectangles. This is a highly boring work that discouraged me to add more levels, and the perfect candidate for automatization.

Finding the minimum set of rectangles that covers all the bricks is not an easy task, because there usually exists more than one way of covering all the bricks with rectangles. Sometimes the best way involves using overlapping rectangles. Even though finding the optimal solution was an interesting challenge, I realized that including complex (and maybe slow) code to reach perfection was not worth in this case. Having 10% more rectangles than the optimal solution didn’t impacted the performance in a visible way. I decided to go with a simple algorithm that provided a good enough solution.

Original bricks

The basic idea of the algorithm is to process each row independently, looking for contiguous blocks which define single rectangles, and then try to mix rectangles from consecutive rows if possible. As I said, this doesn’t find the optimal solution, it is just a greedy algorighm that provides a good enough one.

Column joins Row Joins

This is the pseudo-code:

previousRow = new Set[Rectangle]
currentRow = new Set[Rectangle]
rectangles = new List[Rectangle]
for row in rows:
    currentRectangle = None
    currentRow.clear()
    for char in row:
        if char == '#':
           if currentRectangle == None:
               currentRectangle = new Rectangle(colNum, rowNum)
             else:
                 currentRectangle.grow()
        if (char == ' ' or isRowEnd) 
           and currentRectangle != None:
           if canMix(previousRow, currentRectangle):
                  mix(previousRow, currentRectangle)
            else:
                 rectangles.add(currentRectangle)
       currentRow.put(currentRectangle)
    previousRow = currentRow
return rectangles

The algorithm already tries to mix rectangles with the previous row ones while they are generated, and does a pretty good job joining lots of bricks into big rectangles. Another optimization that I did to the algorithm is to encode the previousRow as an array with the same width as one row, where each position of the array has a pointer to the rectangle that covers this cell or to null if it is empty. This way, finding the right rectangle to mix with in the previous row runs in constant time. Actually, my implementation doesn’t need a currentRow structure, I overwrite the previousRow one after reading it…

I will not go into the actual implementation to avoid making this article infinite, but if anyone has some doubt on how to implement it, feel free to leave a comment and ask.

Conclusion

With the background baker and the rectangle optimizator, generating new Egg Savior levels reduces to actually thinking them and mostly writing a string with hashes. This code runs each time that the player starts a level, and is so fast that it is actually overshadowed by resource loading time.

Posted in Uncategorized | Tagged , , ,

A very exigent market for games

It has been almost four months since I published the first version of Egg Savior in the market. This game was mainly an experiment to learn a couple of new things. First of all, I wanted to learn how to develop games for the Android platform. Secondly, I wanted to learn how the market reacts to games. And finally, I wanted to learn how global apps perform, since OTempo, my former app, is a local app targeted to galician users.

For the first target, I am quite proud. The game performs quite well even on middle-end hardware like my old Galaxy Spica, and I was able to try graphics, sound and input. You can read my post on Creating 2D games with Android and Blender where I share some of my gathered knowledge.

About market reaction to games, I have learned a quite hard lesson: The market is very exigent, even with free games. Actually, I think that gamers don’t care if your game is free or costs a couple of bucks, they expect a high quality product from the first version, and if the first version is not good enough, upgrading and enhancing it will not work like it would have done with other apps. Advertising has been very helpful on recognizing usage patterns on the first version and each upgrade.
I have to admit that this lesson was hard to fit, because I spent long hours working in this game, but sometimes one has to get back to planet earth and remember its objectives. It was a learning experience, and I have learned a lot. I realize that the artistic needs of the game far exceed my ability, and the number of levels is quite ridiculous, but it was not about fame and glory ;-)

About the global market, I also learned a valuable lesson. There is a lot of fragmentation. Every country behaves differently to this game. All the statistics that admob provides point to the fact that the usage pattern varies a lot from one country to another. The most obvious example is the case of Korea, where the game was a huge success, maintaining the first position in free games for several consecutive days. I believe that this is a great opportunity rather than a threat. It enables development of products with a strong personality, focused in a concrete market, and opens more opportunities for everyone. It also warns of the risk of starting a serious project (I mean, investing money) without any kind of market research.

Posted in android | Tagged , ,

Egg Savior reached 100K downloads in Korea

Some time ago, I made an agreement with UbiNuri to distribute Egg Savior in the korean market. On January 17, Egg Savior was published in the T Store, and the users reaction was really impressive. In Just five days it came to the first position in the free game category, with 50K downloads, which doubled during the weekend, making a total of 100K downloads after just eight days.

I want to thank UbiNuri and all the korean users who are enjoying this game, and promise new versions with more levels.

By the way, the korean name of Egg Savior is 달걀 지키기.

| Tagged ,