I always find it difficult to answer the question: where do ideas for games come from? But this time, I can more or less accurately say that this idea was born to me when I saw the World of Tanks banner on one of the sites. You know, there are banners that attract the user's attention with micro-games before redirecting them to the advertiser's site? So, on this banner was a tank, which by clicking could pass a particular distance, for some reason punching through the brick walls. It was from that moment that I began to think, on my way to work, about a tanker-related runner. A reference to the sensational hit from Wargaming in the title was also born immediately. It seemed funny to me, considering that the essence of my game is movement along a certain road, a path, in order to cover the maximum distance. Under Habrakat you will find a story about the game, development, technical details and everything, everything, everything that should be in the classic gamedev story.
About the game
So, what do we have here? Well, firstly, we have such a tank:

hole-holes-holes
')
Which goes along the road, virtually divided into 3 lanes (hello, Subway Surfers!). Swipe left and right, you can rebuild into adjacent lanes to avoid collisions with obstacles. Unlike other runners, the maneuvers here are not instantaneous (it’s still a tank), which also needs to be taken into account. I agree, it sounds weird, but our tank can jump (svayp up). What runner can be without jumps? In addition, it is a fan, jump over a trap pit and shoot anti-tank hedgehogs in a jump, slyly placed immediately behind it. Of course, the tank can and shoot (swipe down), although the shells in the game are limited. In my opinion, shooting is an analogue of skates in the same Subway Surfers, it allows you to go "by force" to the area where there is no time for a maneuver.
One of the really cunning traps
In general, I often peeped into top runners when I did “Way of Tanks”. Of course, I do not have many of today's fashionable chips, such as roulette, daily competitions, friends from Facebook, push notifications and other things that should increase ARPU, MAU, DAU and all these things I do not understand. But I want to believe that the main thing in the game is the gameplay made with a soul! However, I digress.
Secondly, the path of the tank is littered with obstacles placed by an invisible enemy. All obstacles can be divided into 2 types: those that can be jumped, they are at ground level and below (pit-traps, minefields) and those that cannot be jumped, but can only be driven around or destroyed (walls, anti-tank hedgehogs, pillboxes). Moreover, simply destroying everything in your path will not work. The tank cannon has a limited reloading rate, which does not allow shooting too often. Therefore, for a successful game you will need not only reaction and luck, but also the ability to quickly decide when to maneuver and when to shoot.
Initially, I planned to add a few mini-bosses to the game, but as usual, life and limited resources make their own adjustments. Therefore, from the mini-bosses, in "Way of Tanks" while there is a plane that is trying to destroy the player's tank, dropping bombs on him.
AI plane is pretty simple, one might even say, primitive. There are two main characteristics: the speed of decision making and the time of preparing the next bomb for bombing, in other words, “reloading”. So, when the bomb is ready, the bomber seeks to occupy one lane with the player, and when there is a recharge, on the contrary, to avoid being on the line of return fire. After the tests, I added a couple of complications: the plane records the beginning of the turn of the tank and then the algorithm works as if the tank was ALREADY rebuilt into a new lane. Thus, the bomber learned to "predict" the response of the player and work on the target proactively. Plus, a gradual improvement in performance to maintain balance in the game (the aircraft only gets to its maximum complexity from the fifth to the sixth approach).
As in any runner, there are temporary power bonuses (powerups), giving the tank super abilities. I have not fully decided on the list, now there are four of them:

Doubles collected coins

"Charge" - allows the tank to break through any obstacles, but only in a jump

Increases tank maneuverability

Armor-piercing charges - shooting, the tank destroys the entire line of obstacles in front of itself (as well as +1 charges)
Oh yeah, there was also the idea to make flying rockets, like in the Jetpack Joyride. But after consulting and thinking, they decided that the rockets would either fly too fast or look strange (if they were slowed down). As a result, the missiles turned into such kamikaze armored vehicles that would ram our tank:
In general, the game turned out to be simple, but, nevertheless, organic and gambling! At least, this is the only one of all my games, in which I myself continue to play with pleasure after all these endless testing and debugging.
Technical part
This is the fifth game I am doing on AndEngine. Yes, I know about Unity, but I do not chase for cross-platform. In my opinion, it’s better to make exclusive for one platform faster and better. Yes, and the game on a familiar field, so to speak, I have more or less obtained, in contrast to the attempts to at least somehow declare myself in the App Store. Although I look at LibGDX lately.
I'll tell you a little more about the internal structure of the game. The main thing in the runner is actually moving forward. I tried the approach with the movement of the camera after the character and the parallel generation of the world in front of it, but for various reasons, I stopped at the version with a static camera. That is, the tank and the camera stand still, and the entire game world moves towards it, creating the illusion of the tank moving forward. It seems that such an approach a priori loses in performance, but if everything is done correctly and optimally, then there should be no problems.
We have four variants of the background, the size of a camera (1280x720), which seamlessly go from any to any. At the same time, the player sees no more than two of them. Therefore, in the first step, we set the SpriteGroup with backgrounds to the position (0, -CAMERA_HEIGHT), and the two sprites inside it to (0, 0) and (0, CAMERA_HEIGHT), respectively. The remaining two - hide. Next, we move the SpriteGroup down at the speed of the tank. When it is in the coordinates (0, 0), we return it to its original position, while randomly selecting the next section of the background and hiding the distance. It's simple!
But here I am faced with an unpleasant bug: sprites inside SpriteGroup can “blink” when changing positions. On stackoverflow, I found this solution to this problem. For SpriteGroup, override onManagedUpdate and write:
@Override protected void onManagedUpdate(float pSecondsElapsed) { final SmartList<IEntity> children = this.mChildren; if (children != null) { final int childCount = children.size(); for (int i = 0; i < childCount; i++) { this.drawWithoutChecks((Sprite) children.get(i)); } submit(); } }
Together with the background movement, we need to create obstacles. It would be wrong to do this completely by chance, because in this case, the appearance of impassable parts is possible. All my traps are also divided into sections and prepared in advance. They are stored in a JSON file of approximately the following structure:
{
"Root": {
"Sections": [
[
["CELL_EMPTY", "CELL_EMPTY", "CELL_EMPTY"],
["CELL_COIN", "CELL_EMPTY", "CELL_EMPTY"],
["CELL_COIN", "CELL_EMPTY", "CELL_EMPTY"],
["CELL_COIN", "CELL_EMPTY", "CELL_HEDGEHOG"],
["CELL_PIT", "CELL_WALL", "CELL_WALL"],
["CELL_EMPTY", "CELL_EMPTY", "CELL_EMPTY"]
],
...
All variants have been repeatedly tested by me, unsuccessful, I either modify, or simply reject. After that, at each step of generating the world, we simply select a new random section with traps, or print the current line of the current section.
As in any modern Android-game, we have integration with Google Play Game Services (achivki and leaderboards). It's all pretty trite and described in detail in the manual off. Website:
developers.google.com/games/services/android/quickstart . I just use once written code in each new game, with almost no changes.
Optimization
I want to say a few words about optimization in AndEngine. For all objects that are not animated sprites, for which we do not override onManagedUpdate and do not use entity modifiers, we must not forget to set setIgnoreUpdate (true) immediately upon creation. This has a positive effect on performance by reducing the number of onUpdate calls on each clock cycle. Also, you need to do setIgnoreUpdate (true) when we hide any object (set setVisible (false)).
Further, everything that is created on the scene dynamically and not in a single quantity should be placed in pools (a special class for reusing objects). I have these traps, explosions, marks on the ground from tank tracks, etc. Here, for example, looks like a pool of traps:
public class TrapPool extends GenericPool<Trap> { @Override protected Trap onAllocatePoolItem() { return new Trap(0, 0, Assets.trapRegion, ContextHelper.getVBOM()); } @Override public synchronized Trap obtainPoolItem() { return super.obtainPoolItem(); } @Override protected void onHandleRecycleItem(Trap pItem) { pItem.setVisible(false); pItem.detachSelf(); super.onHandleRecycleItem(pItem); } }
Now, if a new obstacle appears on the scene, we do:
Trap trap = trapPool.obtainPoolItem(); trap.setPosition(nX, nY); trapLayer.attachChild(trap);
And when the trap is no longer needed (went beyond the visibility of the camera):
trapPool.recyclePoolItem(trap);
To speed up rendering, I put all the backgrounds in one SpriteGroup. The only caveat here is that only one atlas can be used for the SpriteGroup. Therefore, all the sprites of backgrounds are reduced by 20% in order to meet the maximum texture size of 2048x2048. I don’t know how true it is now, progress doesn’t stand still, and all my test devices support 4096x4096, but since this doesn’t really affect the image quality, it won't be overly accurate. It also makes sense to set the image format to RGBA4444 instead of RGBA8888. For such "cartoon" graphics, the image will not change, and the amount of memory used is halved (if you use TexturePacker, then just select the appropriate option when publishing an atlas).
But the trick that I spied in the "AndEngine for Android Game Development Cookbook" is disabling the rendering of the Activity background, it is not visible or used anywhere, and it affects the FPS noticeably. To do this, create your own theme in res / values:
<resources> <style name="Theme.NoBackground" parent="android:Theme"> <item name="android:windowBackground">@null</item> </style> </resources>
And in the manifest we install it for our Activity:
android:theme="@style/Theme.NoBackground"
Fragmentation
Another thing that is interesting to talk about - the struggle with various screen resolutions of devices on Android. Initially, the game was designed for a 16: 9 aspect ratio. I considered 3 options for scaling images for other screens, let's call them conditionally:
1. Original size - the correct aspect ratio, the picture completely fills the screen vertically, but due to this, unused areas appear on the sides
2. Zoom screen - the same, but the picture fills the screen horizontally, the “extra” part for the backgrounds is cropped at the top and bottom, and the interface elements are shifted to the center
3. Stretch screen - just stretch the game to fit the screen, without respecting the aspect ratio
I will show what it looks like on the example of the most inconsistent aspect ratio - 4: 3


From left to right: original size, zoom screen, stretch screen
Obviously, the fourth option suggests itself: redraw graphics under 4: 3, but use 16: 9 for game elements as well. That is, you get option 1, but with level decorations instead of side frames. A great option, in fact, sorry for me suggested it late, after all, redrawing graphics is not so easy and fast. But since the internal perfectionist didn’t want to calm down, as a result, the graphics were still redrawn (not all, mostly backgrounds) and now the game looks even better on tablets than on smartphones!

Screenshots from the tablet (4: 3) and smartphone (16: 9)
Someone will say: “Pfff! He discovered America! ”, But it is not always possible to learn from the mistakes of others, sometimes you have to reinvent your“ bikes ”to understand how to get better and better. In particular, in AndEngine "out of the box" there is no such type of Camera that I ended up on as a result. And in tutorials, they don’t write about such approaches.
Costs and thanks
Since I don’t have anything to say about income, I’ll tell you about expenses. The time to create a game from the first commit before publishing to Google Play was almost three months. I would rate my pure time as a programmer somewhere in a month and a half (the game was made in my spare time and sometimes I had to wait for the result from other team members, naturally). Let it be ~ 3000 $ at a rate. With a professional and very talented artist, Egor, we are already working on a second game on the basis of dividing the possible profit, so the absolute cost of creating art for the game, I do not know how to take into account (except in time too). Localization of the Google Play page into the main languages ​​cost me about $ 60 (a short description and captions for the screenshots).
For the sound design I want to thank the guys from Gamingearz. I also cooperate with them not for the first time, everything is as always at the highest level and as soon as possible. The guys with great attention and love relate to their work and, equally important, for indie developers like me, we are ready to offer options within a limited budget. For “Way of Tanks,” they recorded just an awesome soundtrack (plus a few game sounds) for a symbolic $ 200. And I made all kinds of interface sounds myself using the
diforb.com service.
The promo video for the game was created by a professional photographer and just a good person - Sergey Muratov from Minsk. And he, too, is not the first time making a video for my games. I, like everyone, tend to turn to people with whom I have already had successful work experience, earlier. This is plus $ 100 more. That's practically all the costs. I, of course, have a couple more ideas on marketing investments, but this is optional. First you want to understand whether the players will like Way of Tanks as much as I like it?
Summing up all the expenses, it turns out that your own simple runner on Google Play will cost about $ 3,500. It is a lot or a little - decide for yourself. For me, this is a fair price for the pleasure of an interesting and well-done work, for clicking the cherished “Publish” button in the Developer Console, for the opportunity to play the “lottery lot”, which is played by all indie. And maybe even win something, who knows ...