Hello! We are a small team of two people trying to make games in our free time. Most recently, we finally released our first modest creation and decided to share the experience of its creation with the community.
“Everyone has their own runners, and why are we worse?” We will also be able to cut an extremely simple game for phones in a month, ”we thought a little more than a year ago, and everything started to turn out.
We drew a couple of sketches, wrote a 2-page dizdok and took Unity, with whom we already had some experience. Having decided that we will cope with a simple runner in about a month or two, we set to work.
')
Carefully, under a cat there are a lot of pictures!
Prototype
So, we decided to create something very simple, one-button. The main idea is a character who runs and breaks stones on the move. The player needs at some point to tap on the screen to destroy the barrier.
In about a week, a prototype was created, which consisted of the main character - the Ogre, the Dinosaur pursuing it and a stone generator, which scattered into pieces even with the use of physics.
Graphically, all this is wrapped in a simple and bright flat-style. For the first steps - that is necessary.
One of the first sketchesPrototype development
We, of course, love hardcore games, but not like when, after one wrong push, you lose. Therefore, it was decided that in one round the player will be entitled to 3 errors, after which the Dinosaur will eat the main character.
After playing a bit in the prototype, we realized that we needed at least some variety of gameplay. So we got chickens. Their final implementation is quite different from what was originally.
In the first implementation, the Ogre threw a boomerang in the hens. The player at the same time it was necessary to “cut” the chicken with a finger, as fruit is cut in Fruit Ninja. And get on the hen had to be twice. For the first time a part of the plumage flew from it, for the second it turned into several chicken legs that flew to the Dinosaur in the mouth. Dino ate and dobrel. They let in at least one chicken - Dinosaur was angry and came closer. But this not only sounds cumbersome, but also played. The hens were completely redone: instead of several birds and a boomerang, a flock of birds and, suddenly, a shotgun. No, well, in fact, it's a game, anything can happen here. Blue ogre running away from a dinosaur? YES! Shotgun? Why not? Chicken in the sky? Yes, this is not one hen, but a whole flock, and we will now hesitate them!
Now, to kill the chicken, it was enough to tap it. The chicken legs were removed, and if the feathery was not killed in time, it would crash into the dinosaur face, it would get angry and come closer.
A draft version of all these ideas was ready approximately 2 weeks after the start of development. The funny thing is that the gameplay that prototype was not much different from the current release.
Total we got gameplay, consisting of two alternating parts: breaking stones and shooting flocks of chickens from a shotgun.
After the gameplay was more or less clear, we cut out unnecessary content and began to add the necessary elements. So over the next couple of months they appeared: an initial splash screen, several variants of the backdrops that succeeded each other, other decorations, such as bushes and flowers, a simple tutorial, and Ogre began to appear bruises after hitting the stone. After that, it was time to put everything in order, which left most of the time.
Chicken legs and boomerangs were almost immediately sent to the trashGraphics and Animation
All the characters underwent changes compared to the original images, more and more details were added. Only the chickens immediately turned out great and graphically did not change at all.
Screenshot from the release versionIn this game, I wanted to try out the skeleton animation. In the end, we decided to try the CCD plugin, which was
demonstrated at one of the Unity conferences. Slightly modified, he lived to see the release version, and for this project we had it in general enough. However, in the future, if skeletal animation is needed, we will definitely use more advanced tools.
Since the gameplay requires the player to be constantly focused on breaking stones, we wanted to make the animation smooth and without unnecessary details. But a couple of nice little things we added, such as playful eyebrows, jumping tum and a moving bundle of hair.
Music and sound
It turned out pretty smoothly. For release voice acting, we bought several libraries with sounds in the asset store, we recorded a couple of sounds ourselves. Music ordered from an independent composer.
The only interesting fact was that as many of the first Half-Life sounds were used for the draft voice acting. In particular, the stone was broken with the characteristic sound of death from falling from Gaussgan. Replacing it in the end with something more like breaking stones, for some time we could not get used to the new sound after such a native Gauss.
End of the round menu
Well, what could be the menu in such a small game? But it was not there that it turned out that a considerable number of buttons would have to be crammed in order to have a minimum set today: help, records, app evaluation, and sound cut-off. And you need to remember to add the ability to disable ads. And also you need points, the best result and the player's reward for setting a new record. Well, in the end, a more pleasant receipt of earned coins than just a counter jump.
Such rewards were a smoothly increasing amount of money with a characteristic ring of coins and animation of a cup with applause in the event of a record. Little things, but nice.
One of the menu sketches. Almost the same way it looks in the release version.By the way, after Unity 4.6, creating UI has become a much simpler process, so here we are lucky.
In-Game Store
After our prototype began to look more and more like a game, we thought about what else can entice the player to come back again, except for the table of records, which we had originally planned.
As a basis, we decided to take the idea of ​​collecting. Unlockable characters - cool, but long. It takes a lot of art, a lot of animations, more testing of how they all behave in the game. We also thought of making background landscapes and stones openable, but in the end we decided to collect eggs.
So we added the egg shop, which, however, turned out to be a variety of trophies.
Shop "eggs." Before shopping, you can only guess what is behind the silhouetteBy the way, this store was not as easy as it seemed initially. As a result, we made a custom shader for eggs that have not yet been purchased and finalized the standard ScrollRect.
Monetization
We decided to try to add some monetization. So to say, try this thing technically and, perhaps, collect a little tip.
As a result, our choice fell on one of the easiest options - advertising. Since we did not intend to insert banners directly into the game, thereby disfiguring the game scene, we decided to show interstitial advertising on the full screen at the end of every third round. It seems more or less democratic. We also added the ability to disable ads for the minimum payment (0.99 USD). Here we were helped by the In-App Purchasing service from Unity. Everything is pretty trivial, you can read more in the official
tutorial . Works for both iOS and Android.
It can also be mentioned that the UI for this payment is slightly different for iOS and Android. The difference is that in iOS it is necessary to give the user the opportunity to manually restore his already made payment when changing the device or reinstalling the game (Android, as far as we know, does it automatically).
In addition, we added viewing video ads for coins, but everything is strictly at the request of the player.
From advertising, they started to connect AdMob first, but rather quickly switched to
Appodeal . Of the benefits - a fairly simple integration and a good tech. support for free service.
By the way, there were several problems with advertising, some of which still remain: the game podlagivaet at the beginning on weak and not very devices, not all users display video for a fee (usually treated by resetting the advertising ID, but who among the users will do it) ).
Leaderboard connection
To work with achievements and leaderboards in Unity there is the Social interface, which by default has an implementation for iOS. For Android, the implementation is, for example, in a plugin from Google -
play-games-plugin-for-unity . When building for Android, you only need to thrust the initialization of the PlayGamesPlatform into the #if UNITY_ANDROID block, and the code associated with Social, for both Android and iOS, can be used the same.
By default, play-games-plugin-for-unity tries to build for iOS builds as well. To exclude it and use the implementation from Unity, you need to add the NO_GPGS key in Scripting Define Symbols (located in Player Setting → Other Setting):
By the way, after adding play-games-plugin-for-unity to the project, we encountered
a 65k problem when building for Android. They were saved by creating an empty project and throwing only Appodeal and play-games-plugin-for-unity into it.
Optimization
When almost everything was ready, despite the tests on real devices, we faced a performance problem. Looking ahead, I will say that optimization has taken a significant amount of time.
Here are a few links to some of the most useful articles for us:
about everything ,
about allocation in C # part 1 ,
about allocation in C # part 2 .
Butches, batches, batches
Our first problem was an indecently large number of Draw Calls - about 50. And then
FrameDebugger came to the
rescue , which first appeared in Unity 5.0. Looking at the step-by-step frame construction, repacking the texture atlases and setting Order in Layer, we received an average of 15 Draw Calls. Already not bad. A little later, we again returned to this issue - we combined some atlases (for example, Ogre, Dinosaur, Chicken and Nest, we now store in one texture), reduced the number of Sorting Layer, and as a result, on average we had 7-8 Draw Calls.
In addition, FrameDebugger allows you to find graphics that are rendered, but which ultimately is not visible on the resulting scene. For example, we didn’t remove a cloud over the head of the Dinosaur, which is necessary only in the splash screen:
FrameDebugger in actionIn addition to FrameDebugger, Xcode also perfectly shows what happens with rendering. It also allows you to see the frame construction, and it may differ from what you were shown by FrameDebugger:
Profiling with XcodeAlso with the help of Xcode, we learned about the second problem: an unreasonably large number of vertices. Perhaps some will ask: "Sprite - these are 2 triangles, from where there will be a heap of peaks?". The fact is that on modern graphics accelerators it is cheaper to draw a mesh with a reasonable number of vertices than to process a bunch of transparent pixels. Therefore, Unity builds a mesh along the contour of the sprite, but it does not always optimally.
Here we came to the aid is not free, but extremely useful asset
SpriteSharp . After its application, the number of vertices in the scene rarely exceeds a thousand.
By the way, this feature can be disabled, and then the sprites will be built classically from two triangles. These settings are in the texture parameters:
The number of Draw Calls and the number of vertices can be found without using profilers - just look in Stats:
And some more tips:
- Leave the final union of the texture atlases for later, when you have really finished the contents of the scene.
- Look carefully at how you change the color of the sprites. SpriteRenderer.color does not break the batch, but SpriteRenderer.material.color, like any other material change, breaks.
- Remember that dynamic batching has a number of restrictions, for example, meshes that will be combined, in total, cannot contain more than 900 vertex attributes. More details can be found on the official website of Unity .
A bit about fonts
Initially, the score counter was made with the use of a dynamic font and an option, which could cause jerking at each successful breaking of the stone, since the counter was incremented by one, and with it the label mesh was rebuilt. Output - use Custom set in the fonts themselves and turn off Best Fit in UI.Text.
Optimization of logic and physics
About physics in Unity it is possible to gather from good
article on Habré . About us, we say that in the release version we don’t use it at all.
For example, at first we had colliders on all stones and Ogre. However, there is no need to count the intersection of the Ogre with all the stones, you just need to know the distance to the nearest one. And the distance is only on x - no square roots are needed.
We also had colliders in the form of a circle on each hen. Again, it makes no sense to check the intersection of the coordinates of the tapas with all the colliders. Since one tapa can kill up to two chickens, it suffices to find the first two crossings and stop further calculations.
We searched for hits by using the distance from the center of the chicken to the coordinates of the tapas, and here, too, you can do without square roots - you only need to use sqrMagnitude and the square of the radius. A little more
here .
For stones, we used the “baking” of physics in animation. On each stone 3 animations were recorded for successful smashing with a fist and 3 when Ogre crashed into a stone. In fact, it looks almost the same as with the use of physics simulation. The scripts that we wrote for baking can be found on the
bitbucket - all of a sudden someone will come in handy.
We also moved from the approach “each element of the scene itself is engaged in its update” to the scheme “manager and the set of elements for which he is responsible”.
For example, in the case of the hens, it was possible to endow each of them with its own Update method, in which she would look for the rest of the hens and apply the logic of behavior in the pack. However, the chicken script we have contains only basic methods, such as turn around or die. For the behavior of all the birds in the bundle is responsible script flocks.
This approach allows for more flexible and centralized control of the scene update. For example, elements that do not affect the gameplay can be updated only a few times per second, instead of updating each frame. Or, if the collection is very large, not all elements are updated for one Update, but to post their updates on frames: frame N - update of the first half of the collection, frame N + 1 - update of the second half.
And you should always remember that every call to the MonoBehaviour method, like Update or Start, has a certain overhead. Read more about this in the
Unity blog .
The pool of objects is “must have” when using Unity (and any other engine in principle). Fortunately, we had it initially.
Well, you should never forget about the “overflow” float:
Metamorphosis in distant worlds. At the top right, the coordinate value along the X axisIn our case, when the value of 100000 is reached along the X axis, the scene shifts by -100000. Another technique that could be applied is to imitate movement. Ogre and Dinosaur stand still, and the whole environment moves from right to left.
To search for bottlenecks, always use profilers, both Unity itself and Xcode. And do it on a specific device, and not in the editor.
In conclusion of the optimization chapter, I would like to add that, despite all the efforts, lags still happen: activities related to advertising, payments, Google Play / Game Center and the operating system itself.
And, of course, somewhere we ourselves overlooked.
Accommodation on the App Store
Probably everyone knows that in order to release their application on iOS, a mac device is needed? Yes, of course, you can try all sorts of tricks such as “hakintosh” or get friends - the happy owners of the MacBook.
It is not known how Apple will behave, if it suddenly finds out that the application was flooded with hakintosh. But I don’t feel like getting a banhammer and losing all my apps in the App Store. This option was abandoned immediately.
The alternative to constantly getting friends who have a poppy is questionable, since building, debugging, profiling, and then pouring the application, appruve, additional editing or fixing, rolling out updates, and so on - all this requires more than one evening of work.
As a result, we got Mac mini medium configuration. Here, by the way, the scheme works well: developing on a powerful PC, and using a weak poppy only for activities related to the App Store.
Another interesting fact about the App Store is the description and screenshots you can upload from any platform, but the video from Safari is at least 8, running OS X at least 10.10. Moreover, video processing after casting is given up to 24 hours.
Well, in general, the rules of publication are more severe, rather than on Google Play, so if you received Apple’s applet, you’ll definitely understand Android.
By the time of receiving the appruva, it now takes about two days. The article about the pitfalls of the market was not very long ago
on Habré .
Well, the official manual is also pretty well described the
requirements for the posted materials.
Placement on Google Play
Placing on Google Play is much easier. Video and screenshots for phones have already been prepared, we just have to make versions for tablets 7 and 10 inches in size and upload videos to YouTube.
After that, we prepared a release apk and checked everything on the beta test. Further it was necessary to send it for consideration. And here you should be careful if you do not want to immediately release your application. We now knew that it was easy to do this, and still stepped on this rake, releasing the Android version a bit earlier than planned.
On this occasion, you can say: always make sure that what is selected in the drop-down list on the Production page on the right above:

And remember that after each postponed publication, this parameter is reset to the standard publication.
By the time of receiving the appruva - now it usually takes several hours.
Again, more details can be found all in the same
article with Habra and the official
manual on the preparation of materials.
Conclusion About timing
Well, for dessert, the main question is: “Why so long ?!” (and almost a year and a half has passed since the start of work until release).
In fact, the main gameplay, which almost without any changes was released, was created in the first month of development.
And then adding a store, menus, rework, rework, redrawing, repairing after updating Unity and waiting for bug fixes from them, optimization and a lot of technical difficulties that were inexperienced to be done very slowly. For example, we spent a few evenings just to organize the process of building and testing the beta under iOS.
There were problems with advertising, there were problems with the build for Android, when we connected all the plugins.
And of course the “human factor”, he's lazy. Because as a game we were engaged only in our free time and rather as a hobby, it was not always possible to do after a hard day’s work.
something useful.
However, the main goal for us was to go through the full development cycle: from prototype to release, and we did it.