📜 ⬆️ ⬇️

How to fill a bunch of cones and release the game

It all started back in 2013. Then there were a lot of toys on Android, but less so than now. And by releasing your game on the then-Android Market, you could get some kind of money. And since I like to make games, there was no doubt - we are releasing the game. We are a small team of programmer, artist, and tester / idea generator. Looking ahead - we have collected enough cones and rakes. Basically there will be a review of technical issues, so the article will be useful to anyone who is in any way connected with the development of games. Do not repeat our mistakes.

Idea of ​​the game


Of the games existing at that time, we liked the game where the ball rolls through the maze, dodging holes, and trying to get to the final pocket. At that time there were already a few such games, but in terms of graphics they were not very good. Therefore, we decided to make our own, with an emphasis on color. I would like to mention the artist, he painted very, very cool. Thanks to him, the game turned out like it is - beautiful.

As an engine, it was decided to use libGDX. I knew him well at that time, and I liked him, there were already completed projects on it. I was sure that we would reach a victorious end. As it turned out - reached.

Gameplay Features


In principle, the gameplay turned out to be standard for games of this type - we roll the ball with the help of an accelerometer. An additional feature is that we have teleports, and the walls can be more than just boring rectangles. But more about that further.
')
Of the features I want to mention the management. We have long picked up the accelerometer settings for a comfortable game, but our tester constantly noted that something was wrong. As a sample, he brought a similar game with the Android Market. In the end, I downloaded this game, decompiled it (I was also surprised that it was not obfuscated), and looked at the moment with the controls. I found that the code is identical to mine, only the coefficients differ. I note that the decompiled game was also written in libGDX - that is, at that time, mass games were already written on it.


We can customize the management

Technical part


As I mentioned, the game is written in libGDX. The game uses many resources - graphics, sounds, maps, fonts. Let's go through each moment.

Graphics. The game has several hundred sprites. For performance purposes, all the sprites were packed into textural atlases. A separate atlas for the menu screen, a separate one for selecting levels, etc. Standard technology that saves both video memory and performance draws. Atlases were packed with the Texture Packer program (available for download on the libGDX website). If I did it now - I would use the built-in class TexturePacker. Packaging of the atlas looks like this - TexturePacker.pack (“folder-with-sprite”, “output-folder”, “atlas-name”). The advantage of this approach is that you do not need to switch from IDE to another program to repack atlases.


This is what a reduced atlas with different balls looks like. This is a small part, we have several such atlases.

Atlas format - 32 bits, png. Some pictures, that without transparency, are packed in jpeg atlases. If I did now - atlases without transparency, I would pack in ETC1. LibGDX has native support for this format, and for Android, this is an economy of video memory.

To control the graphics (loading / unloading atlases, getting the desired image), a self-made class Images was written. I knew about the built-in AssetManager, but at that time I needed a more convenient solution. For example, if I want to get some kind of background image, I want the previous requested background to be automatically unloaded. My decision allowed me to do such things.

Moving a little to the side - when I write a game, I often do my resource managers. Often based on standard AssetManager. The goal is easier access to resources. In later stages of development, code readability plays a very important role. A well written code, like a book. It is easier to understand the line images.createButton (“green-button”) than assetManager.get (TextureAtlas.class, “data / atlases / buttons”). FindRegion (“green-button”). From the minuses of this approach - when you return to the game after a long time, you need to remember the features of these managers. Of the benefits - when you remember, to continue to edit something is already simple.

Sounds. All sounds in the game in .ogg format. Why not mp3? On some phone models at that time there were problems with playing several sounds in a row in .mp3 format. I admit that these were my crooked hands, but there were no problems with .ogg. The benefit of libGDX supports both formats, replacing .mp3 with .ogg was easy.

In order to optimize the sounds were shaken to the minimum bitrate, the format is mono. Development was conducted on linux, for conversion I used Sound Converter. In my opinion, Sound Converter is a sample of an excellent utility that I still use today. One small window with settings for the output format, and the "Convert" button. An excellent answer to monstrous converters.

Fonts. The game uses two types of fonts.

The first type is .ttf fonts and the gdx-freetype library. It allows you to generate bitmap fonts from .ttf fonts at runtime. The advantage of the library - you can set the desired font size right at the time of launching the program. This ensures that the font will always be exactly the size you need. Among the shortcomings, since the font is generated “on the fly” into the texture, this means that it will be RAM. And the larger the font size, the more it is needed, this very memory. Another unobvious moment is that since the font is a separate texture, when drawing any lettering, there will be an additional draw call (except for the moment when we draw several labels in a row). On this basis, the scope of .ttf was limited only by the “About” screen.

The second type of fonts is distance field fonts. The idea is simple - using the Hiero program (available for download on the official libGDX website), a special font texture is generated. In the texture for each letter highlighted its own area. But this area is not drawn "as is". Instead, a special shader is used, which specifically draws this region (of course, this also breaks the batching). The advantage is that with a relatively small texture, you can draw a font with a very large size without losing quality. Disadvantages - the font needs to be generated in advance, and no effects are available for the font (shadow, stroke, etc.). Also, as I mentioned, it breaks the batching. You can only set the font color during drawing. This was enough for our needs, so Distance Field fonts are commonly used in the game.


This is how the Distance Field font looks. The background should be transparent, I just made it black for clarity.

Cards. One of the “tricks” of a good game is the amount of content. You can generate it automatically, or you can prepare level sets. We went the second way - we have more than a hundred levels. Levels are divided into boxes - in a box of 15 levels. It is clear that with so many levels the question arises of their convenient editing and storage. Need some kind of map editor. The matter is complicated by the fact that we have two types of cards - simple and “original” (during the development we called them that way).

Simple maps are standard mazes for this type of games with rectangular obstacles. To edit such maps, I wrote an editor — a simple Java program using Swing as a graphical library. Manually you can place obstacles, holes, etc. Obstacles can be rotated, resized as you like - in this regard, the editor turned out to be quite convenient. The tester complained that it was inconvenient, that it was impossible to undo actions - I understood him, and wrote cancellation / repetition of actions, having studied the pattern Command.


Map editor in action


Simple banal card - nothing unusual

The chip is to quickly test the cards, the editor had the ability to switch to the game. Immediately (in the same window) a game was launched where you could check the map. In the role of the accelerometer mouse acted. I can say that the writing of the editor is like that phrase, “it’s better to lose a day, then fly in five minutes”.

Original cards. So we called the pictures manually drawn by the artist, where the individual elements of the picture are obstacles. Below is an example of such a card.


Football field is more interesting

It is clear that the standard map editor is not suitable in this case. I thought, and solved the problem as follows - take the editor tiled . In it we create two layers - one background, there will be a picture of the original level. The second layer is the markup layer. On it, primitives (circles, squares and polygons) mark the map. For example, a hole is a circle with the name “hole” (tiled allows each object to assign its own name). At the output, we get an xml file in tiled format. But this format does not suit us. Therefore, I wrote an additional utility that takes the generated tiled xml and converts it into my level format. At the same stage, it turned out that box2d does not support polygons that consist of more than 4 vertices — in other words, quadrilaterals (at least the box2d port for libGDX).


Mark up the original map

All of this "Frankenstein", though it looked awkward, but its task performed perfectly well. Almost half of the game levels are “original”, and thanks to tiled, we did without writing another editor. Conclusion - sometimes you don’t need to write your own something complicated and big, just look around and take a ready-made solution with minimal doping.

Ball animation


When the ball moves, it must somehow animate, create the illusion of movement. Some games of this genre do not bother with this, and use a simple static image. We decided to be confused.

We have several ball skins — glass, fire (lava), football, etc. At that time I was not aware of the 3D capabilities in libGDX, and could not use the 3D model. Therefore, we decided to do time-lapse animation. A full turn of the ball took about 50 frames. Depending on the speed of movement, I changed the frame rate, creating the illusion of faster or slower rotation. And of course I changed the turn of these frames. I can not say what happened perfectly, the 3d model would definitely give a more beautiful picture, but that is, that is.

Physics


The game uses the physics engine box2d (more precisely, its port under libGDX). Of the benefits - it is fast, and he has a lot of opportunities. Of the minuses - you need to know it :) The ball is a dynamic body, the obstacles are static bodies. When the level is loaded, a physical model of the world is created, and, in fact, the game begins. When paused, the simulation stops. In principle, this is all that can be said about physics - there were no special problems with it.

Additional chips


Our menu screen is not easy. It is also made as part of the game. The ball rolls along it, obeying the accelerometer. And when the ball hits the buttons, it bounces off. And if the ball touches certain buttons in a certain order, the portal will open to the secret level :)


The ball rolls around and bounces off the buttons - like in a pinball

There are many achievements - for completing levels, for a certain amount of wins, for a certain time in the game, etc. We did not use standard Android Google Play achievements, but made our own system of achievements.


A small part of the achievements

Moments that I would have done differently.


It is clear that there are no ideal solutions, and with experience comes an understanding that this or that part is not optimal. I will say that I would remake, do I play now.

The first point is the choice of boxes. If you open the game and look at the boxes, you will see that there are dots on each box. Depending on the complexity, these points are larger or smaller. So - for the arrangement of these points, I wrote a class that loads a json file, and puts dots on this config file. The motivation for why I did it is to save space in texture atlases. That is, we store the general picture-background of the box, one point, and the order of arrangement of these points for a particular box. Why it is bad - the complexity of the modification. If each box were a separate picture, it is enough to correct the picture - and now you need to go into the config files and figure out what and how. It would be better to keep it just pictures.


Each box is not just a picture. This is a substrate + text file-config with the location of points.

The second point - I was very confused with optimization (the example above is a confirmation of this). All screens (menu, box selection, game, etc.) I created in one copy, and just switched between them. This eliminated the creation of the same screens every time we move to a different screen, but led to the problem of cleaning. For example, a game screen stores many parameters for a particular level (for example, points, time, etc.). When we load a new level, you must first reset the state of the game screen. But as new chips were added, it was easy to forget to clear something. This is “ate” a decent piece of time, debugging such problems. When I make a game now, I do it differently. If you need to change the screen - I save the necessary parameters for this screen in a class of settings, then create a new screen. That new screen is created and reads the necessary data from the settings class. At the same time, resources are spent more, but this time is unnoticed against the background of modern powerful phones.

The given example about the screens is only one of. Plus, this approach - the game does not lag even on the worst phones. The minus of the approach is, how many of them, such bad phones, to spend so much time on optimization? For myself, I solved the problem like this - when buying a new smartphone, I deliberately chose characteristics that were slightly below average. If the game goes without brakes on it, I don’t bother with optimization - for most people the game will start and go fine.

Conclusion


There are no perfect games, just like there is no perfect development. After a while, we brought the game to the end, and it was released on Google Play. What can I say - despite all the bumps and rakes, it is interesting to develop games. There are a lot of moments, some moments are not solvable, and you have to look for workarounds. But solving these problems raises your level as a developer. It was interesting for me to write this game, and I believe that it will be interesting to play in it.

Source: https://habr.com/ru/post/313986/


All Articles