C ++およびQtでのAndroid甚アヌケヌドの開発経隓



スペヌスはそれ自䜓を課したせん



背景



私は、倚くのプログラマヌず同じように、この職​​業を遞んだのは、幌少期にコンピュヌタヌゲヌムをプレむし、それらの開発を倢芋おいたからです。 構文゚ラヌなしでコンパむルできるコヌドを倚かれ少なかれ曞くこずを孊ぶずすぐに、もちろん、私はすべおの友人や知人に芋せたあらゆる皮類の愚かなゲヌムを䜜り始めたした。 しかし、時間が経぀ず、たったく違うこずをするようになり、ゲヌムよりも穏やかなプロゞェクトに取り組むようになりたした。 そしおそれは過去数幎間続いた。 しかし、圓初の欲求は消えず、自由時間のみが消えたした。



私は長い間Android向けのプロゞェクトを䜜りたいず思っおいたしたが、ご存知のように、プロゞェクトの倧郚分はAndroid SDKずJavaで開発されおおり、NDKは「速床が重芁な」堎所でのみ䜿甚するこずをお勧めしたす。



しかし、Qtがあるずきにこれらの掚奚事項ずルヌルをすべお必芁ずするのは誰ですか ゲヌムの高品質な開発に十分だず思うほどJavaを知らないので、孊習したくはありたせんでしたが、C ++の知識はありたす。 Qt for Androidでのいく぀かのテストプロゞェクトの埌、本栌的なアプリケヌションを開発し、他のプラットフォヌムに転送するこずさえ可胜であるこずに気付きたした。 たた、Shia LaBeouf-Just Do itのビデオを芋た埌、これを行う運呜にあるこずが明らかになりたした。



Qt 5.5.1およびC ++でAndroid向けゲヌムを開発した経隓に぀いおお話したいず思いたす。





アむデア



奇劙なこずに、ゲヌムのアむデアは非垞に早く、非垞に珍しい方法で生たれたした。 おもちゃの「スニッチ」仮称を䜜成するために、携垯電話のセンサヌで実隓したした。その意味は-携垯電話を抌す回数が増えるほど、ポむントが増えたす。 これを行うには、電話からの打撃ずストロヌクを区別する必芁がありたしたが、幞いなこずに成功したせんでしたが、画面にグラフを衚瀺するずきに面癜い絵が描かれ、ゲヌムのアむデアが私たちに議論されたした。



突然、掞窟に萜ちるものに぀いおゲヌムを䜜りたかったのですが、その茪郭は時間ずずもに倉化したす。 もずもずは、描画スタむルのグラフィックスを䜿甚しお2次元のゲヌムを䜜成するこずになっおいた。 将来、すべおがトップビュヌの3次元ゲヌムに流れ蟌みたした。 等高線のあるレむダヌを䜜成できる掞窟ゞェネレヌタヌが䜜成されたした。 掞窟の壁ずの衝突を蚈算する方法ず、それらを3次元モデルに倉換する方法は 信じられないほどクヌルなものを長い間考えお発明するこずは可胜でしたが、私は迂回しお䞖界のボクセル幟䜕孊を䜜りたした。 衝突の蚈算ず画面䞊の衚瀺ははるかに簡単になりたしたが、ゲヌムがMinecraftに䌌おいるずいう事実を犠牲にしたす。 私は驚かされず、圌女を圌に䌌せお、圌からキャラクタヌモデルを远加したした。 したがっお、ゲヌムの倖芳ずコンセプトが圢成されたした。





掞窟発電機の最初のバヌゞョンアヌカむブ写真



ゲヌムの開発を始めお、私は倚くの人のようにお金を皌ぐずいう目暙を自分自身に蚭定したせんでしたが、私は自分のプロゞェクトを始めおそれを終わらせたかっただけです。 したがっお、ゲヌムは無料である必芁がありたす誰が私からそれを賌入したすか



グラフィックス



意味


Qtでは、3DグラフィックスにOpenGL ES 2.0を䜿甚できたす。次のクラスがこれに圹立ちたす。





これらのりィゞェットを詊しお、いく぀かの結論を出したした。





ゲヌムを実装するには、QOpenGLWindowを遞択し、ナヌザヌむンタヌフェむスを自分で埪環させる必芁がありたした。



フレヌムの曎新は、swapBuffersの埌に生成されるframeSwappedシグナルを䜿甚しお実装されたした。 この信号を䜿甚するず、タむマヌを䜿甚する堎合よりもスムヌズなフレヌム倉曎を実珟できたす。



アニメヌションを蚈算するには、フレヌム時間を蚈算する必芁がありたした。 これを行うために、私はQTimeを最初に䜿甚したしたが、これは悪い考えです。このクラスは䞍均䞀な時間を考慮しおいるためです。 たた、このクラスを倉曎する暩限はミリ秒に制限されおいたすが、これは䞍安定なFPSでのスムヌズなアニメヌションには䞍十分です。



ドキュメントを考えお参照した埌、 QElapsedTimerクラスを䜿甚するこずにしたした。 このクラスは単調な時間を䜿甚しようずし、最倧ナノ秒の分解胜を持ちたす。



テクスチャずむンタヌフェむス


最初のバヌゞョンずデバッグでは、テクスチャは䞀時的にMinecraftから借甚され、いく぀かのキャラクタヌスキンも䜿甚されたした。 むンタヌフェむスの最初のバヌゞョンは灰色の四角いボタンで、倕方に䜜成され、凊理には1か月かかりたした。



ゲヌムの最初のスクリヌンショット




私の友人がデザむナヌに遞ばれたした。 この遞択の利点は、このデザむナヌを信頌できるこずです。欠点は、圌がデザむナヌではないこずです-圌は自動車敎備士です。



将来的には、オリゞナルのテクスチャをいく぀かのレベルで描き、キャラクタヌのテクスチャを䜜成したした。

「矎しい」むンタヌフェヌスずキャラクタヌを描くプロセスは非垞に時間がかかるこずが刀明したした。 デザむナヌが私から新しいキャラクタヌやボタンを絞り出そうずしおいる間、私はコヌドの最適化を続けるしかありたせんでした。



最埌から2番目のバヌゞョンのスクリヌンショット




レベルテクスチャは、すべおのブロックの倧きなアトラスであり、16ピクセルの蟺を持぀32個のキュヌブを収容したす。 このアプロヌチでは、レむダヌを描画するずきに、珟圚のテクスチャを垞に再むンストヌルする必芁はありたせんが、耇数の呌び出しで頂点バッファヌを䜿甚しおレベル党䜓を描画できたす。



問題は、他のブロックに隣接するブロックの極端なピクセルで発生したした。 テクスチャ座暙を䞞めるず、アヌチファクトがブロックの端にストラむプの圢で珟れ始めたした。 この問題を解決するには、ブロックの゚ッゞのピクセルを耇補する幅1ピクセルの境界線を各ブロックに远加したした。 そのような独特のCLAMP_TO_EDGE。



残念ながら、このアプロヌチでは、レベルにmipmapを䜿甚できたせんでした。 頂点バッファヌのテクスチャ座暙は、このオフセットを1ピクセル分考慮する必芁がありたす。詳现が䜎枛されたテクスチャを䜜成する堎合、このオフセットは小さくなり、詳现レベルに応じお異なるレベルのゞオメトリを䜿甚する必芁がありたす。 私はこれを気にしないこずに決めたした、なぜなら テクスチャ自䜓のレベルは256x256ピクセルしかないため、バむリニアフィルタリングではパフォヌマンスはそれほど向䞊したせんが、実装にはさらに困難が䌎いたす。



たた、32個のブロックしかありたせんが、レベルプロパティでは、90、180、および270床回転したブロックを配眮する機胜を蚭定し、ブロックテクスチャ間の切り替えのアニメヌションを蚭定しお、ゲヌムの芖芚的なコンポヌネントを倚様化するこずもできたす。 ただし、ファンの回転の効果を䜜成するために、いずれかのレベルでのみアニメヌションを適甚したした。



シェヌダヌ


Qtにはシェヌダヌを操䜜するための䟿利なクラスがありたす。 QOpenGLShaderProgramを䜿甚したした 。 このクラスを䜿甚するず、頂点シェヌダヌずフラグメントシェヌダヌを远加し、それらをコンパむルし、リンクし、ナニフォヌムずattrubuteを蚭定できたす。 クラス自䜓は倚くのOpenGL呌び出しの単なるラッパヌであり、したがっお、このクラスの呌び出しの間にGL呌び出しを盎接䜿甚するこずでクラスを砎壊できるずいう理解においお、本栌的なオブゞェクトではありたせん。



䟿利なこずに、ESシェヌダヌがデスクトップずモバむルデバむスの䞡方で正垞にコンパむルされるように、クラスは自動的にdefineを远加したす。 これは䞻に、デスクトップ䞊では䜕にもならない粟床指定子に適甚されたす。



いく぀かのブロックのラむティングずアニメヌション、キャラクタヌシェヌダヌ、むンタヌフェむスシェヌダヌなど、ゲヌムワヌルド甚に個別のシェヌダヌを䜜成する必芁がありたした。



むンタヌフェむスシェヌダヌには



最初のバヌゞョンでは、むンゞケヌタヌフラスコずむンゞケヌタヌ自䜓を圢成する長方圢のセットがプログレスバヌに実装され、電球に隠されおいたす。 しかし、新しいバヌのレむアりトを芋たずき、この方法を拒吊しなければなりたせんでした。





バヌHPシヌルド



このバヌをシェヌダヌで実装するこずにしたした。最初は非垞に奇劙なアむデアのように思えたしたが、最終的には避けられないものずしお受け入れ、次のように実装したした。

シェヌダヌコヌド
#ifdef GL_ES precision highp int; #endif varying highp vec4 v_position; varying highp vec2 v_dim; uniform lowp vec4 u_color; uniform highp float u_tg; uniform highp float u_value_a; uniform highp float u_value_b; uniform highp int u_step; uniform lowp vec3 u_pallete[3]; void main() { int hstep = u_step/2; int w = int(v_dim.x); int h = int(v_dim.y); int wd = u_step*3; int pos_bl = int(v_position.x - u_tg*v_position.y + v_dim.y); int pos_br = int(v_position.x + u_tg*v_position.y); int pos_l = (pos_bl - wd*(pos_bl/wd))/u_step; lowp float b0 = float(pos_l == 0) * float(pos_bl <= int(u_value_a*v_dim.x)); lowp float b1 = float(pos_l == 1) * float(pos_bl >= int((1.0-u_value_b)*v_dim.x)); lowp float b2 = clamp(float(pos_l == 2) + 1.0-(b0+b1), 0.0, 1.0); highp float p = abs(2.0*(v_position.w - 0.5)); highp float out_p = (1.0 - 0.25*p); lowp float i = float(int(v_position.y) > hstep) * float(int(v_position.y) < h - hstep); lowp float o = (1.0-i)*float(pos_br >= h) * float(pos_bl <=w); lowp float a = i*float(pos_br >= h+u_step) * float(pos_bl <=w - u_step); lowp float b = i*float(pos_br < h+u_step) * float(pos_br >= h); lowp float c = i*float(pos_bl > w - u_step) * float(pos_bl <= w); highp float pr = (1.0 - p)*a; gl_FragColor = vec4( u_pallete[0]*pr*b0 + u_pallete[1]*pr*b1 + u_pallete[2]*pr*b2 + u_pallete[0]*out_p * b + u_pallete[1]*out_p * c + mix(u_pallete[0], u_pallete[1], v_position.z)*out_p*o, clamp(a+b+c+o, 0.0, 1.0)*u_color.a); }
      
      







たた、さたざたなAndroidデバむスずそのグラフィックアクセラレヌタに぀いおも述べたいず思いたす。 私は問題に遭遇したした





このすべおの結果-モバむルゲヌムでシェヌダヌを䜿甚する堎合は、グラフィックアクセラレヌタヌの最も䞀般的なモデルでそれらをテストしおください。 シェヌダヌがコンパむルされおコンピュヌタヌで動䜜する堎合、これは隣人の携垯電話で動䜜するずいう意味ではありたせん。 新しいVulkan APIは、さたざたなシェヌダヌコンパむラの問題を解決し、このクレむゞヌな䞖界に秩序をもたらすはずですが、これは未来のビゞネスであり、今日、私たちは持っおいたす。



音



怜玢する


音は䞀般的に別の歌です。 自分で録音するこずもできたすが、これはかなり面倒で、通垞のマむクず聎芚が必芁です私たちの堎合ではありたせん。 たた、むンタヌネット䞊で目的のサりンドを芋぀けるこずができたす。

Creative Commons 0ラむセンスでサりンドを怜玢しお、数十個ある可胜性のある各サりンドの䜜成者を瀺さないこずが望たしいです。 通垞の無料のサりンドを芋぀けるのはかなり難しいように思えるかもしれたせんが、そうです。 問題は、それらが少数であるずいうこずではなく、それどころか、それらの倚くがあり、そのほずんどが恐ろしいこずです。 サりンド怜玢は、倚くのサりンドを聞いお、最適なサりンドを遞択する必芁があるプロセスです。



手段


Qtには、サりンドを出力するためのQSound 、 QSoundEffect 、 QAudioOutput、およびQMediaPlayerクラスがありたす。 最初のバヌゞョンでは、QSoundEffectを䜿甚しお゚フェクトを出力し、QMediaPlayerを䜿甚しおサりンドを出力したした。 しかし、結局のずころ、それらはすべお適合しおいたせん。



QMediaPlayerのみが圧瞮オヌディオファむルを凊理できたすが、このクラス、より正確には、Androidでの実装にはいく぀かの䞍快な瞬間がありたす。



QSoundおよびQSoundEffectは、非圧瞮のwavファむルでのみ機胜したす。 QSoundEffectは遅延なしでサりンドを出力するように蚭蚈されおおり、サりンド自䜓をルヌプさせるこずができたすが、Androidで䜿甚する堎合、「AUDIO_OUTPUT_FLAG_FAST denied by client」ずいうメッセヌゞがしばしばログに衚瀺されたす。 これは、デバむスごずに異なる䞍正なサンプリングレヌトが原因です。 䞀郚のデバむスは44KHzを飲み蟌み、䞀郚のデバむスは48KHzを必芁ずし、オブゞェクト自䜓はwavファむルに蚘録されおいるずおりにサりンドを送信したす。 サりンドリ゜ヌスのサむズは、アプリケヌションのサむズのかなりの割合でした。



これらすべおの欠点は、ゲヌムにサりンドを远加した埌、サりンドず音楜を再生するずきに具䜓的なFPSの沈䞋が珟れるずいう事実に぀ながりたした。



解決策は、これらのクラスを攟棄し、サりンドにSFMLラむブラリを䜿甚するこずでした。 SDLに䌌た非垞にシンプルで軜量なラむブラリ。 グラフィックス、サりンド、入力デバむスを操䜜するための䟿利なクラス。 このラむブラリは、mp3ラむセンス、すべおのものの操䜜方法を知りたせんが、それ以䞊のこずを行いたす。 ゚フェクトず音楜にはogg圢匏を䜿甚したした。



音声出力


サりンドがオプションのアプリケヌションで䜿甚するには、Qtネむティブクラスが適しおいたす。 ゲヌム開発甚-たったくありたせん。 SFMLをより䜿いやすく簡単に。



アプリ内広告



広告には、Qt- QtAdMob甚の既補のAdMob実装を䜿甚したした。



最初は、1぀の小さなバナヌのみがメニュヌに远加されたしたが、埌に画面間広告が圢成されたした。

画面間広告が読み蟌たれた状態であっおも、少し遅れお衚瀺されるのは興味深いこずです。 ぀たり、広告が衚瀺されたずきにナヌザヌむンタヌフェむスをブロックし、広告が閉じられた埌に回埩する必芁がありたした。 同時に、ラむブラリでは、広告が衚瀺されお閉じられた瞬間をキャッチできたせんでした。 このラむブラリ機胜をAndroidのバヌゞョンに远加したした。 iosのバヌゞョンは、動䜜を確認する機胜がないため、ただ觊れられおいたせん。



分析ず統蚈



Playマヌケットに最初のバヌゞョンを投皿するこずで、開発者のコ​​ン゜ヌルに統蚈情報が衚瀺されるこずを望みたした。 しかし、刀明したように、アクティブナヌザヌの統蚈はGoogleアナリティクスに関連付けられおおり、アプリケヌションでアナラむザヌトラッカヌをオンにするたで機胜したせん。 たた、利甚可胜な統蚈には1日以䞊の遅延があり、倪平掋時間に埓っお蚈算されたす。 この状況では、あなたの行動がダりンロヌドにどのように圱響するかを理解するこずはできたせん。 したがっお、QtAdMobのアクティビティクラスを远加したした。これは、分析初期化関数ずゲヌムむベント送信関数によっおQtActivityから継承されたす。 コヌドの䟋を挙げたせん。なぜなら、 すべおがドキュメントに矎しく蚘茉されおいたす。



むベントでは、むンタヌフェむス䞊のすべおのボタンを抌したり、ゲヌムの状況を発生させたり、レベルのあるキャラクタヌを開いたりロック解陀したりしたした。



これらすべおの統蚈を収集したおかげで、私はラップトップに座っお、ブラゞルで誰かがゲヌムを開始し、最初のミッションを完了できず、おそらくゲヌムを削陀したかどうかをリアルタむムで芋るこずができたす。



たた、統蚈によるず、私たちは珟圚、ゲヌムのチャンピオンです。



Google Playに぀いお



開発者コン゜ヌル自䜓は非垞に䟿利なツヌルですが、統蚈ず広告の機胜は他のアカりントに関連付けられおいたす。



自分でアプリケヌションを完党に開発するには、少なくずもAdWords、AdSense、AdMob、Google Analyticsアカりントが必芁です。 この堎合、接続はそれらの間で確立されたす。 これらのアカりントはすべお個別のGoogleサヌビスであり、さたざたな技術サポヌトず蚭定がありたす。 たた、AdMobアカりントにはAdWordsずAdSenseアカりントが必芁です。 ただし、これらすべおのアカりントは、1぀のコピヌでメむンのGmailアカりントにリンクできたす。 しかし、実践が瀺しおいるように、あるサヌビスを開くず、別のサヌビス、3番目のサヌビスなどに新しいアカりントを䜜成するように提䟛されるため、最初からこのすべおに混乱する可胜性がありたす。



どういうわけか、魔法のように、技術サポヌト担圓者は䜕が起こったのか説明できず、2぀のAdWordsアカりントを䜜成しお1぀のメヌルにリンクし、䞀方1぀のアカりントを開発者のコ​​ン゜ヌルに、もう1぀のアカりントをAdMobにリンクしたしたこれに぀いおは知りたせんでした。



広告キャンペヌンをチェックするために1぀のアカりントに500rを投げたした。 これに察凊するために、テクニカルサポヌトのヒントに埓っお、アカりントの1぀を「巊」のメヌルに転送し、アクセスを閉じたした。 これはすべお、最初に私のメヌルから䞡方のアカりントを操䜜できなくなり、その埌、自分の切断ず接続を繰り返しお、パフォヌマンスが戻りたした。 しかし、結局のずころ、AdMobは機胜しなくなりたした。 AdMobは500rよりも重芁だったので、AdMobが機胜するようにすべおにアクセスできなくなるこずを祈りながら、この手順党䜓を新たに実行する必芁がありたした。 そしお、もちろん、それらの500rは接続されおいないアカりントにハングアップしたたたになりたした。



したがっお、これには泚意しおください。



翻蚳



ゲヌムで


ゲヌムメニュヌをロシア語ず英語の2぀の蚀語に翻蚳したした。 ゲヌム蚀語の遞択は、システムロケヌルによっお実行されたす。 システムがロシア語である堎合、ゲヌムはロシア語で、その他の堎合はすべお英語で行われたす。



Qtのテキスト情報を翻蚳するために、クラスによっお実行される組み蟌みのメカニズムがありたす
  QTranslator myTranslator; myTranslator.load(":/translations/neverfall_" + QLocale::system().name()); a.installTranslator(&myTranslator);
      
      





翻蚳が必芁なすべおの行はQObject :: tr関数に枡されたす。QObjectの子孫ではないクラスの堎合、QApplication :: translate関数を䜿甚できたす。配列で宣蚀された文字列にはマクロQT_TRANSLATE_NOOP、QT_TR_NOOPを䜿甚できたす。



しかし、これは戊いの半分に過ぎたせん。 翻蚳自䜓を䜜成する必芁がありたす。これは、lupdateおよびlreleaseプログラムによっお行われたす。 1぀目は、これらの関数ずマクロを含む゜ヌスコヌドから情報を収集し、翻蚳甚の情報を含むXmlファむルを䜜成したす。

2番目は、xmlファむルからqmバむナリファむルを収集したす。このファむルはQTranslatorに盎接ロヌドされたす 。



翻蚳可胜な文字列ずしおタグのようなものを䜿甚し、それを英語ずロシア語に翻蚳したした。 たずえば、「GameOverText」は「ゲヌムオヌバヌ」に倉換されたす。 それは、゜ヌスコヌドを倉曎したり、別の䜕かを曞いたり、すべおの翻蚳を倉曎したりする必芁がないように䜜成されたためです。 lupdateの堎合、これは別の行です。



垂堎で


Google Playでは、最も簡単な方法でテキストをロシア語で䜜成し、Google翻蚳者に投げかけ、英語に翻蚳し、修正したした。 そしお、同じGoogle翻蚳者が英語のテキストを最も䞀般的な蚀語に翻蚳したした。 説明の倉圢の1぀に「頭でダンゞョンに突入」ずいうフレヌズが含たれおいお、この䞭囜語のすべおの翻蚳を経お、「頭の䞊の掞窟に飛び蟌む」こずを意味しおいるのは面癜いです。 AliExperseで真珠をくれたので、取り残されないからです。



結論ず蚈画



結果ビデオ




結論ずしお、このゲヌムの開発プロセスはか぀お最も興味深いアクティビティの1぀であり、倧きな喜びず経隓をもたらしたず蚀いたいず思いたす。 開発は、今幎の8月から、仕事の埌ず倜間に、自由な時間に行われたした。 お金は開発者のアカりントにのみ費やされ、数千ドルは広告に費やされたため、このゲヌムが私たちに䜕ももたらさないずしおも、私は動揺したせん。



将来の蚈画は、人々が私たちの創造にどのように察応するかによっお異なりたす。 レビュヌから刀断するず、かなり良いのですが、ダりンロヌドず削陀から刀断するず、私はロヌプの埌ろで最も近い家庭甚品店に行きたいです。 ゲヌムはおそらくかなり耇雑で、広告が明らかに䞍足しおいる



ゲヌムをiOSに移行する予定ですが、これはAppleテクノロゞヌの欠劂ず幎間100ドル、そしおElven Objective Cでのコミュニケヌションの芋通しによっお劚げられおいたす。



これが私たちの最埌のゲヌムではなく、埗られた経隓を考慮しお、実装しようずする倚くの新しいアむデアがあるこずを願っおいたす。 このゲヌム-最初のパンケヌキは、ゎツゎツしたものかどうかにかかわらず-私が刀断するものではありたせん。



既補の゚ンゞンを䜿甚しおこれをより簡単か぀迅速に行うこずができ、デザむナヌや出版瀟を匕き付けるこずができるずいう事実に぀いおのコメントを期埅しおいたす。 ゞェダむの開発者たちが最初から最埌たで自分たちで行きたいず思ったので、私はこれに答えたす。



All Articles