📜 ⬆️ ⬇️

Qt 5.2, from desire to google play

Hello colleagues.

It so happened that I was told about Qt5.2 and its new ability to quickly and easily create cross-platform applications for Android and iOS. I was familiar with Qt long ago, but recently the work has been connected with other technologies and I have launched its development a bit. Having learned this, I went to the Qt website, watched a beautiful video, where in 10 minutes HelloWorld application is created immediately under android and ios. The impressions were very positive.

It was decided to engage in mobile development. There was a plan to go from the desire to make the application to its publication on Google Play. But at the first stage, I wanted to go through it with the fact that it is not a pity, and where you can make mistakes. And all this on the new Qt5.2.
')

At about the same time, I heard about the well-known Flappy Bird and the fact that its author decided to delete his application. Well, here it is already clear that the next decision was to make another copy of this game, but the main goal is to test the new features of Qt permanently.

Choice with ++ or javascript


Of course, I love c ++, but I did not dare to write such a trifle on it. C ++ forces the developer to write thoughtfully and be very careful not to "shoot himself a leg", I also wanted to do a project in the style of XP, quickly and most importantly so that it worked. The choice fell on QML and javascript, at the same time the opportunity to deal with these technologies so promoted by Digia.

First sketch


Quickly installing Qt, reading the qml documentation and examining the game mechanics of Flappy Bird (I hadn’t heard about it before) the first draft of the game was made. Simple NumberAnimations were used to simulate the flight of a bird and the movement of pillars. Everything worked fine, but there were questions:


Physics


The only correct solution for the above 2 problems, I decided to use the well-known Box2D. The plugin for qml was found quickly - github.com/qml-box2d/qml-box2d . A couple of days of experimentation, reading the box2d documentation and everything is rewritten and works great. But problems still lay ahead.

Sound


I refused background music because I do not like it myself, and I couldn’t find a good option, let alone do it myself. So on www.freesound.org 3 sounds were picked up: a flap of wings, a collision and a new point.
A nice example of creating Flappy Bird from V-play with AudioManager was used for playback. But without a file has not done.
import QtQuick 2.2 Item { id : audioManager property QtObject effect1: Qt.createQmlObject("import QtMultimedia 5.0; SoundEffect{}", audioManager); property QtObject effect2: Qt.createQmlObject("import QtMultimedia 5.0; SoundEffect{}", audioManager); property int hit: 22 property int point: 33 property int silence: 44 property int wing: 55 property bool effectSwitcher: false; function play( sound) { var effect; if( !effectSwitcher){ effect = effect1; effectSwitcher = true; }else if( effectSwitcher){ effect = effect2; effectSwitcher = false; } if(effect == null) return; switch(sound) { case hit: effect.source = "audio/sfx_hit.wav" break case point: effect.source = "audio/sfx_point.wav" break case silence: effect.source = "audio/sfx_silence.wav" break case wing: effect.source = "audio/sfx_wing.wav" break } effect.play(); } } 


reproduction:
 audioManager.play( audioManager.wing); 


Everything worked on the desktop machine, on the phone the application fell. The reason turned out to be banal, it was necessary to add the following to the .pro file:
QT += multimedia

Why are there two SoundEffects here and why sfx_silence will become clear below in the description of encountered bugs.

Scaling


Scaling was done as standard. The resolution was taken as a basis at 480x800 (the smallest but probably the most common one at the moment). Regarding him, the sizes of the bird and the pillars were rigidly set. Then it was just done the calculation of the scaling factor for the current resolution relative to the reference one, and then all the sizes requiring scaling were simply multiplied by it. With all of this, this bitbucket.org/wearyinside/cute-plane example helped me a lot , but as usual many problems were not solved there.
  width: Screen.width height: Screen.height property int defaultWidth: 480 property int defaultHeight: 800 property double measure: Math.min(Math.min(width, height) / defaultWidth, Math.max(width, height) / defaultHeight) property double textScale: Math.sqrt( measure) 

All physical objects are mapped linearly, but the text with this stacked at high resolutions broke all the frames. For him, I had to scale the square root of the main scaling factor.

Design


Since I am a programmer, the design was a dense forest for me, but our internet is everything and after a day of reading various articles on this topic, vector graphics and Inkscape editor were chosen. In order to draw a cartoon bird, it also took just 1-2 days. Initially, a sketch was made on paper and several options were drawn. Then the best one was moved to svg. Further and all other images were made in vector format. In order to use svg files in qml in the .pro file you need to add the following:
 QT += xml svg QTPLUGIN += qsvg 


Monetization


The main part was written and the question of monetization arose. This project was a test one, but I already wanted to understand it with monetization. Monetization admob was chosen. And here the first serious problems began. It turned out that for qt / qml there are no plugins for embedding admob. An obsolete qadmob implementation and a closed implementation of the V-play AdMob plugin was found. Clouds thickened and thoughts began to appear to leave Qt until better times. Breaking the entire Internet, it became clear that it was necessary to search through the Qt sources and figure out how it was made for Android. And after 4 days of excavation, a test advertising banner was displayed in the game. Here is an example of how this is done github.com/AlexMarlo/AdMob-Qt5.2-Example . On the banner display in general, it took a week.

Bugs


Then it became clear that all the main parts are made and it is necessary to correct small, pending for later, bugs.

Memory leak


Memory leaked 100 MB per minute of the game. After periodically commenting on the qml code and checking the results, the problem was found. It turned out that the memory flowed away with this assignment:
  linearVelocity.x = 220; linearVelocity.y = -420; 

changing this option to
  var flyImpulseVelosityY = -420 * measure; var flyImpulseVelosityX = 220 * measure; var impulse; impulse = Qt.point( flyImpulseVelosityX, flyImpulseVelosityY); applyLinearImpulse( impulse, getWorldCenter()); 

leaks have stopped. It looks like a problem with qml-box2d, but I didn’t dig deeper.

Loss of sound


With very frequent taping and therefore very frequent playback, the sound disappeared steadily before playing another sound file. Then there were two SoundEffect. And it manifested itself only on androids. In order for this loss to disappear, SoundEffects are played in turn. I came to this decision simply by practical consideration. Apparently this is some kind of problem in Qt itself.

Application terminated on assert in Box2D with scaling enabled


  width: Screen.width height: Screen.height property int defaultWidth: 480 property int defaultHeight: 800 property double measure: Math.min(Math.min(width, height) / defaultWidth, Math.max(width, height) / defaultHeight) 

The problem lies in the first 2 lines. As it turned out until the qml element in which Screen is called is constructed, Screen.width and Screen.height will be equal to 0. It turns out that the scaling factor is initially 0 and here box2d terminates the application on assert, since the physical objects cannot be of zero size.
This was only corrected by dynamically creating objects at the moment when the scaling factor assumes a non-zero value.

Not working volume control


As it turned out, in the current version of Qt for android, the volume control buttons do not work. All tips on the forums of the same Qt offered to intercept button presses in the Activity, which was done.
  @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if ( keyCode == KeyEvent.KEYCODE_VOLUME_UP) { AudioManager am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE); int index = am.getStreamVolume( AudioManager.STREAM_MUSIC) + 1; if( index <= am.getStreamMaxVolume( AudioManager.STREAM_MUSIC)) am.setStreamVolume( AudioManager.STREAM_MUSIC, index, 0); } if( keyCode == KeyEvent.KEYCODE_VOLUME_DOWN){ AudioManager am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE); int index = am.getStreamVolume( AudioManager.STREAM_MUSIC) - 1; if( index >= 0) am.setStreamVolume( AudioManager.STREAM_MUSIC, index, 0); } return super.onKeyDown(keyCode, event); } 


Testing on different devices and again bugs


Then came the stage of testing on different androids, here is an exemplary list of devices:


Samsung


And all the problems got out on the Samsung, and the better the phone the more pronounced the bugs, and judging by this statistics www.appbrain.com/stats/top-android-phones, it’s just impossible to leave bugs on the Samsung .

Lag when playing first sound


For some reason, the first sound playback through SoundEffect hung and then everything worked fine. This was particularly pronounced on the Samsung Galaxy S3, on the other Samsung, too, it was, but not so noticeable. On devices from other manufacturers this problem was not. This is where sfx_silence.wav appeared. This is essentially an empty sound file that plays when the game loads.

Lag during dynamic creation of Box2D objects


The next problem was due to the fact that Box2D objects were created dynamically for proper scaling and this creation was very slow on Samsung, especially on the same Samsung Galaxy S3.
Creating land objects:
Nexus one97 ms
Samsung Galaxy S Duos986 ms

The difference is an order of magnitude, but I didn’t understand the nuances of the implementation of qml-box2d and Box2D itself, but simply transferred all the creation at the time of loading the game. Loads longer, but during the game, no brakes.

Findings:


Qt for Android in spite of a lot of incomprehensible bugs and shortcomings is quite suitable for development. Especially if you are already familiar with Qt. But you have to be prepared for the fact that you will encounter problems for which there are no answers on the network yet.

One of the downsides that could not be solved was the large size of the application:

The saddest thing is that about 70% of this is the library of Qt itself, and this will have to be tolerated. On the other hand, this size is not so critical for modern devices.

PS:
Screenshots of the result:
Screenshot 1

Screenshot 2

Screenshot 3

Screenshot 4

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


All Articles