ゲームUIとしてのQtQuick / QML

記事は有用なコメントで更新されました。 重要な説明と追加について、すべてのコメンテーターに感謝します。



複雑なUIを備えたゲームでは、表示用の独自のライブラリと簡単な編集用のツールを作成することは、非常に長く困難な作業です。 私は本当にそれをきっぱりと解決したいと思っています。すべての新しいプロジェクトで、そしてすべての新しい会社でさえ、二度とそれをやりません。



解決策は、既製のユニバーサルUIライブラリを使用することです。 現在の世代は、 ScaleformCoherent UIなどの「モンスター」で表されますが、実際にHTMLでUIを作成する場合は、 Awesomiumを使用できます。



残念なことに、この三位一体にはすべての利点がありますが、重大な欠点が1つあります。特にモバイルデバイスではひどいブレーキがかかります(数年前、Scaleformの実際に空の画面がiPhone4でフレーム時間の50%を消費したことを個人的に観察しました)。



この背景に対して、私はいつも誰もゲームでQtを使用しないのだろうと考えていました-デスクトップアプリケーションでうまく機能するライブラリです。 実際、この声明は完全に真実ではありません-QtプロジェクトにはWiki ゲームのリストがありますが、現代のプロフェッショナルプロジェクトはほとんどありません。



ただし、おなじみの古いQtウィジェットがゲームで使用されない理由は表面にあります。OpenGLまたはDirectXレンダリングと組み合わせて使用​​するようには設計されていません。 それらを交差させようとすると、デスクトップパフォーマンスがかなり低下し、携帯電話については何も言うことがありません。



ただし、かなり長い間、Qtにはこのタスクにはるかに適したライブラリQtQuickがあります。 デフォルトのコントロールはより高速にレンダリングされ、UI形式の説明をテキスト形式で指定する機能は、ゲームの外観をすばやくカスタマイズおよび変更するのに最適です。



ただし、プロのゲーム開発者でのQtの使用についてはまだ聞いていません。 トピックに関する記事もありませんでしたので、私は自分でそれを理解することにしました-誰もが私が知らないことを知っています(しかし、言わないでください!)、または単に開発時間を節約する良い機会を見ません。



反対論:





技術的な問題から最も遠いもの、つまりライセンスから始めます。 Qtはデュアルライセンス-LGPL3と商用を使用します。 これは、動的リンクが不可能なプラットフォーム(iOS)にも興味がある場合、Qtを使用する各従業員に対して月額79ドルを分岐する必要があることを意味します。 私が理解しているように、「使用する」とは、少なくともライブラリを使用してプロジェクトを構築することです。つまり、プロジェクトの各プログラマーに支払う必要があります。



ChALkeRx は、静的リンクを使用するために商用ライセンスを購入したりソースコードをレイアウトしたりする必要はないことを明確にしています。オブジェクトファイルをレイアウトするだけで、Qtの新しい静的バージョンでアプリケーションを再構築できます。



お金はそれほど大きくないが、それでも無料ではない。 また、もう1つの非常に興味深い点があります。プロジェクトでQtの使用を開始したらすぐに商用Qtライセンスを取得することをお勧めします。 それ以外の場合、ライセンスを取得しようとすると、「条件について話し合うためにスペシャリストに連絡する」ように求められます。 彼らは理解できる:私たちの国だけでなく、賢い市民は5年間、開発全体に無料版を使用し、最終ビルドをビルドするために1か月間ライセンスを購入するだけだと推測していたでしょう!



おそらく、Qtに対する最も重要な技術的議論はその重みです。 QMLを使用するほとんど空のデスクトップアプリケーションは、40Mb以上を占有します(DLLの動的リンクを使用)。 Androidの場合、サイズは25Mbのオーダーでわずかに小さくなります(拡張された形式ではAPKが著しく簡単になります)が、モバイルプラットフォームの場合は非常にわずかです! Qtは、ユーザーの携帯電話にライブラリを一度インストールし、さまざまなアプリケーション( Ministro )からライブラリを使用できる松葉杖を提供しますが、この松葉杖は明らかにAndroidでのみ利用できます。iOSおよびWindows Phone ...



ただし、太りすぎのライブラリに嘆き、上記のScaleformとCoherentの競合他社がこの点でそれほど優れていないことを忘れないでください。どちらも数十メガバイトのサイズの空のアプリケーションを提供します。 ユニティ-少し軽量ですが、それでも約10Mbです。 したがって、ここでQtは、タスク最適化された独自の開発だけで多くのことを失います。



結論として、もう1つの潜在的な欠点に言及します。QtはWeb(Emscripten)で使用する準備ができていません。 ほとんどの開発者にとって、これはそれほど重要ではありませんが、ここでは、たとえば、この領域に取り組んでおり、ここではQtを使用することはできませんが、この領域では作業が進行中です。



以下の引数:





QtQuick / QMLを使用するための主な議論は、便利なUI記述形式と、そのための視覚的なエディターです。 さらに、大量の既製のコントロールセット。



QML内のJavaScriptでUIコードの一部を記述する機能、たとえば、異なるオブジェクトのフィールドの状態に関連する単純な算術-一時的なUIライブラリではめったに利用できない(そしてしばしば必要な)機会に言及する価値があります。



ただし、Qt DesignerはVisual Studioフォームデザイナーではないことに注意してください。 Qtに付属する基本的なコントロールであっても、可能なプロパティをすべて編集することはできません(たとえば、動的に追加できるため)。 特に、エディターを使用して、押したり放したりした位置のボタン画像を割り当てることはできません。 そして、これは問題の始まりに過ぎません。 一方、ビジュアルエディタとテキストエディタの使用を組み合わせると、これらの問題はすべて克服できます。 Qt Designerをアーティストに渡すことができることを期待する必要はありません。QtDesignerはテキスト表現に入らずにマウスですべてを構成します。



私の意見では、パフォーマンスはQtQuickで十分です。 Qt 5.7の最新リリースでは、モバイルプラットフォーム向けに強化された新しいQtQuick Controls 2.0でさらに大幅に改善することを約束しました。



技術的特徴





それでは、最も興味深いもの、つまりゲームでQtを使用する技術的な機能に移りましょう。



メインサイクル





最初に直面することは、Qtがメインループのマスターになることを好むことです。 同時に、多くのゲームエンジンもこれを主張しています。 誰かが屈しなければなりません。 私の場合、職場で使用しているNyaエンジンは問題なくメインループから切り離され、最小限の初期化の後、Qtによって作成されたOpenGLコンテキストを簡単に使用します。 しかし、エンジンが粘り強い足からメインサイクルを解放することを拒否したとしても、これは世界の終わりではありません。 ループ内で、アプリケーションのQtクラスのprocessEventsメソッドを呼び出すだけで十分です。 StackOverflowには 、批判とともに実装例が提供されています。



DmitrySokolov は、Qtレンダーとエンジンで友達を作る方法が少なくとも2つあることを指摘しています。まず、シーンをQtQuickステージグラフのコンポーネントの1つとして描画されるテクスチャにレンダリングすることができます。 次に、 QQuickRenderControlオブジェクトを使用できます。 後者に関しては、特に、Qtに2つの(共有)コンテキストを使用し、状態にあまり煩わされないようにゲームをレンダリングする可能性を実証するHabréに関する有用な記事があります。



メインループをQtに転送して行った場合、疑問が生じます-ゲームをいつレンダリングしますか? UIが表示のためにロードされるQQuickViewオブジェクトは、サブスクライブできるbeforeRenderingおよびafterRenderingシグナルを提供します。 最初はUIをレンダリングする前に動作します-ゲームシーンの大部分をレンダリングする時間です。 2番目-UIを描画した後、UIの上にあるはずのいくつかのモデル(たとえば、機器ウィンドウの3Dキャラクター人形)を描画することができます。 重要! 信号を接続するとき、接続タイプQt :: ConnectionType :: DirectConnectionを指定します。指定しないと、別のストリームからOpenGLコンテキストにアクセスしようとしたためエラーが表示されます。



この場合、UIを描画する前にQtが画面をクリアすることを禁止することを忘れないでください。そうしないと、すべての作業が消去されます(setClearBeforeRendering(false) )。



また、afterRenderingでは、QQuickView関数updateを呼び出すのが理にかなっています。 実際、Qtは通常、時間とお金を節約し、何も変更されない限り、UIを再描画することはありません。その結果、レンダリングの前後に同じ呼び出しは行われず、何も描画できません。 updateを呼び出すと、次のフレームですべてが再び描画されます。 1秒あたりのフレーム数を制限する場合は、すぐにスリープできます。



レンダリングに関する他の何か





Qtには一般的なOpenGLコンテキストがあることを覚えておく必要があります。 これは、慎重に扱う必要があることを意味します。 まず、Qtは彼が望むことをします。 したがって、自分で何かを描画する必要がある場合(レンダリングの前または後)、まず、このコンテキストを現在にする( m_qt_wnd-> openglContext()-> makeCurrent(m_qt_wnd) )、次に設定する必要があります彼には必要なすべての設定が必要です。 Nyaエンジンでは、これはapply_state(true)の1回の呼び出しで行われますが、エンジンではより複雑になる可能性があります。



次に、 独自のを描画した後、 m_qt_wnd-> resetOpenGLState()を呼び出して、コンテキストを受け入れ可能なQt状態に戻す必要があります。



ところで、OpenGLコンテキストはQtを作成し、エンジンではないので、コンテキストが作成される前にエンジンが余分なことを何もしないようにする必要があることを考慮する価値があります。 これを行うには、 openglContextCreatedシグナルをサブスクライブするか、 Renderingの前の最初の呼び出しで初期化を行います。



QMLインタラクション





そのため、ここではゲームのシーンを上に描画します-Qtは独自のコントロールを描画しますが、これまでのところ、これらすべては相互に通信していません。 あなたはそのように生きることはできません。



QtCreator、またはQtコードジェネレーター(MOC)への呼び出しが奇跡的にねじ込まれている別のIDEでコードを記述する場合、あなたの人生は簡単になります。 名前でスロットと信号を相互接続するだけで十分であり、QMLはC ++から呼び出しを受信し、その逆も同様です。



CodeRush は、Qtが.proファイルからプロジェクトを生成する手段を持っているため、MOCは一般的なIDEのどれにでも簡単に ねじ込む ことができることを示しています。



VSの場合、.PROファイルからのプロジェクトは次のように生成されます。



qmake -tp vc path / to / project / file.pro



Xcodeの場合:



qmake -spec macx-xcode path / to / project / file.pro



al_sh Visual Studio 2013および2015のアドインをリコールします



ただし、MOCなしで生活することもできます。 可能です! しかし、ザガシュニクからいくつかの松葉杖を取得する必要があります。



この方法(QML-> C ++)





Qtは、信号とスロットを接続する2つの方法をサポートするようになりました。名前による古い方法とポインターによる新しい方法です。 そのため、QMLには名前でしか連絡できません。 これは、第1に、QMLからの信号にラムダを掛けることができないことを意味します(これはC ++ 11が欲しかった!)、そして、第2に、スロットが宣言されているオブジェクトが必要であり、このオブジェクトはコード生成のためにQObjectの相続人になり、マクロQ_OBJECTを持つために自分の中にいます。 また、コード生成もありません。 どうする そうです、すべてのスロットが既に宣言されているオブジェクトを使用します。したがって、コード生成は必要ありません。



実際、これは一般に非常に有用なアプローチであり、ある程度の確率で必要になります。 ヘルパークラスQSignalMapperを使用します。 このクラスには、map()という1つのスロットがあります。 必要な数のオブジェクトからの信号をいくつでも添付できます。 応答として、各受信信号のQSignalMapperは、別の信号を生成します-マッピング()し、信号を生成したオブジェクトの事前登録ID、またはそのポインターさえ追加します。 使い方は? とても簡単です。



QMLから送信される信号の種類ごとに個別のQSignalMapperを作成します(クリック-ボタンなど)。 さらに、C ++でQMLのオブジェクトから信号をサブスクライブする必要がある場合、この信号を目的のQSignalMapperに関連付け、その信号またはクラスにラムダ(このレベルでは、C ++ 11がすでに機能している) 、ほら)。 オブジェクトIDが届き、そこから何をすべきかがわかります。



QObject *b1 = m_qt_wnd->rootObject()->findChild<QObject*>( "b1" ); QObject::connect( b1, SIGNAL( clicked() ), &m_clickMapper, SLOT( map() ) ); QObject *b2 = m_qt_wnd->rootObject()->findChild<QObject*>( "b2" ); QObject::connect( b2, SIGNAL( clicked() ), &m_clickMapper, SLOT( map() ) ); m_clickMapper.setMapping( b1, "b1" ); m_clickMapper.setMapping( b2, "b2" ); QObject::connect( &m_clickMapper, static_cast<void(QSignalMapper::*)(const QString&)>(&QSignalMapper::mapped), [this]( const QString &sender ) { if ( sender == "b1" ) m_speed *= 2.0f; else if ( sender == "b2" ) m_speed /= 2.0f; } );
      
      







テストプロジェクトのコード(記事の最後にあるリンク)には、このメカニズムを少し便利に使用するためにラッピングする例があります。



Zifix は、 QML- > C ++と対話する別の方法があり、C ++オブジェクトをQMLにスローし、そこからプルすることを示しています。 これを行うには、オブジェクトはQObjectの子孫であり、コードジェネレーターによって処理されるQ_OBJECTマクロを含んでいる必要があり、コンテキストに追加する必要があります。



 SignalsHub signal; engine.rootContext()->setContextProperty(QLatin1String("signal"), &signal);
      
      









あり(C ++-> QML)





ここで、コード生成のない待ち伏せに直面しています-C ++からQMLのスロットに信号を接続することはできません(より正確には、メソッドがありますが、私の好みでは、それらは複雑すぎます)。 一方、なぜですか?



実際、2つ(まあ、1つ半)の方法があります。 まず、C ++コードからQMLオブジェクトのプロパティを直接変更できます。これをsetProperty( "propName"、value)と呼びます。 つまり、あるフィールドに新しいテキストを置くだけでよい場合は、できます。 明らかに、この相互作用の方法はあらゆる意味で非常に限られていますが、実際にはどれだけのことも想像できません。 実際には、レンダリングスレッドからQMLオブジェクトのプロパティを変更しようとすると、エラーが発生します。 つまり、レンダリング前とレンダリング後のこれらのうち、何も触ることはできません。 そして、あなたはおそらくすでにゲームのロジックをそこに書いていますか? :)私-はい。



どうする まず、メインスレッドでタイマーを開始し、N秒ごとに起動してゲームロジックを処理します。 そして、レンダリングを個別にレンダリングします。 何らかの方法でそれらを同期する必要がありますが、これは解決された問題です。



しかし、これを行いたくない場合は、解決策があります! QMLシグナルを送信したり、プロパティを記述したりすることはできませんが、突然関数を呼び出すこともできます。 したがって、UIで作業する必要がある場合は、アクションを実装する関数(たとえば、setNewText)を宣言し、invokeMethodを介してC ++から呼び出すだけで十分です。



 QVariant a1 = "NEW TEXT"; m_fps_label->metaObject()->invokeMethod( m_fps_label, "setText", Q_ARG(QVariant, a1) );
      
      







重要な点:この呼び出しの引数はQVariant型のみであり、このマクロQ_ARGを使用する必要があります。 また、メソッドが何かを返すことができる場合は、Q_RETURN_ARG(QVariant、referenceToReturnVariable)を指定する必要があります。



tzlomは 、この方法で関数だけでなく、QMLで宣言されたシグナルとスロットも呼び出すことができることを明確にしています。 同時に、Qt :: QueuedConnectionパラメーターを指定すると、呼び出しは延期され、ストリーム内で正確に実行できます



Zifix は、QMLでC ++オブジェクトをスローする上記の手法は、C ++-> QMLの方向に信号をリンクするためにも使用できると言います。 これにより、C ++コードでのQMLオブジェクトの検索を回避できます。つまり、C ++とQMLの間の「名前による」不正な接続を削減できます。



 //  Connections { target: signal // signal -    C++ - ,    onHello: { console.log("Hello from ++!"); }); } //   Component.onCompleted: { signal.onHello.connect(function() { //   C++-   -  QML console.log("Hello from ++!"); }); }
      
      









資源





原則として、すべてはすでにほぼ順調です。 また、すべてのゲームのすべてのリソースが実行可能ファイルの横にプレーンテキストで配置されている場合、この記事を完了することができます。 残念ながら、人生は少し異なります。ゲーム内のリソースは、多くの場合、独自の特別な形式でさえも詰め込まれています。 どのゲームエンジンがディスクからメモリに効率的にストリーミングできますか。



UIに関連付けられているすべてのリソースを、ゲームの残りのリソースと同じ場所にプッシュしたいという要望があります。 さらに、それらは必ずしも明確に分離できるわけではありません-3DシーンとUIの両方で同じテクスチャを使用できる場合があります。 同時に、QMLファイルには「source:images / button_up.png」を記述したままにしておく必要があります。これにより、開発中にリソースが圧縮されていないときに、Qt DesignerでUIを編集できます。プラグインを作成します。



そしてこの瞬間、私たちは最も厳しい、そして非常に不快な嫌がらせを待っています。 実際、ファイルシステムを装ってリソースシステムをスリップする必要があります。 しかし、バージョン5.xのQAbstractFileEngineの形式での仮想ファイルシステムのサポートは、「パフォーマンスの問題のため」に正常に切り捨てられました説明 )。 そこに何がどんなヒールで書かれているのか分かりません。 すべてのゲームはVFSと完全に連携し、複数のリソースのソースを組み合わせており、パフォーマンスについて文句を言いません。 最も厄介なことは、Qtの作成者が代替を提案しなかったことです。



ただし、これまでのところ、このクラスは完全にはカットされておらず、「プライベート化」されているだけです。したがって、リスクのある生活を送りたい場合は、プライベートライブラリとヘッダーを接続して使用できます。



著者は、松葉杖を1つ残しました。QMLEngineにQQuickImageProviderを登録できます。 これにより、少なくともシステムからテクスチャをロードできます。



QMLEngineがQQuickImageProviderを使用し、ファイルに直接移動しないようにするには、QMLファイルで「images / button_up.png」だけでなく「image:/my_provider/images/button_up.png」(「my_provider」)の画像パスを指定する必要がありますQQuickEngineProviderをQMLEngineに登録した名前です)。 明らかに、これを行うと、カスタムプロバイダーについて何も知らず、知りたくないQt Designerでの画像の表示がすぐに停止します。



他の松葉杖で支えられない松葉杖はありません! QMLEngineに別のクラス-QQmlAbstractUrlInterceptorを登録できます このインターセプターを介して、QMLファイルの処理プロセスでロードされるすべてのURLが提供されます。 そして、それらを任意のものに置き換えることができます。 必要なもの! URLタイプがUrlStringであり、信頼性のために、URL自体にテキスト「.png」が含まれていることがわかり次第、すぐに実行します。



 QUrl result = path; QString short_path = result.path().right( result.path().length() - m_base_url.length() ); result.setScheme( "image" ); result.setHost( "my_provider" ); result.setPath( short_path ); return result;
      
      







setSchemeは、QMLが適切なImageProviderを探す必要があることを理解するためのものです

setHostはプロバイダーの名前です

setPath-そして、ここで明確にする必要があります。 実際、InterceptorのURLには既にQMLEngineのベースURLが追加されています。 デフォルトでは、これはQDir :: currentPathです。 明らかに、これは私たちにとって完全に不便なので、何らかの種類の「file:/// C:/Work/Test/images/button_up.png」ではなく、結果として「image:/ my_provider」を取得するために、パスの不要な部分をカットする必要があります/images/button_up.png "。



リソース2-誤トレース





視聴者を楽しませるために、Qtをだまして、システムからすべてのリソースをロードしようとした方法を説明します。



QMLEngineには、インストールできる3番目のタイプのクラスNetworkAccessManagerFactoryも含まれています。 消化できない名前は、独自のhttp要求ハンドラを設定する機能を隠します。 しかし、QQmlAbstractUrlInterceptorでQMLファイルのリクエストをhttpリクエストに置き換え、NetworkAccessManagerFactory(より正確にはNetworkAccessManagerとNetworkReply)で実際にリソースシステムからファイルを開くとしたらどうでしょうか?



計画はほぼ最後まで機能しました:) URLがインターセプトされ、httpリクエストが置き換えられ、qmlファイルも正常にロードされました。 しかし、http QQMLTypeLoaderでqmldirユーティリティファイルの内容を読み取ろうとする場合にのみアサートします:(そして、この動作を回避できませんでした。これがないと、アイデア全体が役に立たなくなります-リソースシステムからQMLモジュールをインポートできません。



Reduxリソース





ところで、Qtには独自のリソースシステムがあります! リソースをrccファイルにコンパイルし、そこから使用できます。 このために、Qtの奥深くで、独自の仮想ファイルシステムが作成されます。リソースにqrc:/プレフィックスまたは単に:/がある場合は、ディスクからではなく、必要な場所からロードします。 残念ながら、「どこにあるべきか」はまだリソースシステムからではありません。



リソースソースを登録するには2つの方法があります。 どちらも静的関数QResource :: registerResourceの異なるオーバーロードの呼び出しです。 最初は、ディスク上のリソースファイルの名前を受け入れます。 ここではすべてが明確です-ディスクから読み取り、使用します。 2番目-特定のrccDataへのベアポインタを取得します。 この時点でのドキュメントには、この関数がrccDataをリソースとして登録することが簡潔に記載されています。 さらに、ファイルに関するいくつかのナンセンスをさらに磨きます。 これは、コピーペーストが失敗した結果であり、変更なしでバージョン間をさまよいます。



2番目のregisterResourceオーバーロードのソースコードを調べると、rccファイルの内容を入力として受け入れていることがわかりました。 ポインタとともにデータサイズが渡されないのはなぜですか? 結局のところ-Qtは何もチェックしたくないが、読み取り-読み取り-読み取りおよびアクセス違反が必要だからです。 この時点で、ライブラリは、少なくとも見出し(マジック文字「qres」と、メモリブロックの残りの部分のサイズやその他のプロパティに関するデータ)を含む高品質のバイナリデータを受け取ることを期待しています。 有効なヘッダーが読み取られるまで、Qtはユーザーが挿入したメモリーを元気に読み取ります。 あまり信頼できませんが、大丈夫です。



このオプションは私たちに合っているように思えます-リソースシステムからrccファイルを読み取り、それをQResourceに入れ、問題なくqrc:/プレフィックスを持つすべてのリソースを使用できます。 これは部分的に真実です。 ただし、リソースシステムにデータを登録する前に、メモリに完全にロードする必要があることに注意してください。 したがって、すべてのUIテクスチャを1つのrccに詰めることは、おそらく悪い考えです。 画面ごとに個別のセットを準備するか、たとえばrccにQMLファイルのみを配置し、Interceptor + ImageProviderを介して上記の方法を使用してリソースシステムから画像をロードする必要があります。



リリース準備





Qtソフトウェアのすべての問題を克服し、コードを書き、美しいUIとパッケージ化されたリソースを作成した後、すべてのリリースの準備が整ったと思うなら、これは完全に真実ではありません。



実際のところ、Qtは多くのDLLおよびQMLモジュールです。 あなたのプログラムを配布するために、あなたはこれらすべてをあなたと一緒に運ばなければなりません。 しかし、それを運ぶためには、最初にそれを見つける必要があり、巨大なQtインストールディレクトリの隅に隠されています。 Qt Creatorはすべてを見つけて必要な場所に配置しますが、まだ別のIDEを使用している場合...必要なすべてのDLLやその他のファイルを手で切り取るのは退屈で退屈な作業であり、最も重要なことは間違いを犯しやすいことです。



ここで、Qtの作成者は単純なプログラマーを目指し、windeployqtやandroiddeployqtなどのツールを提供しました。 プラットフォームごとに、独自のキーを持つ独自の楽器は、異なる動作をします。 たとえば、windeployqtは、メインの実行可能ファイルへのパスと、QMLファイルが入力されているディレクトリへのパスを取得し、出力時に必要なすべてのDLLなどを指定された場所にコピーします。 それを自分で、自分で、自分で。



しかし、androiddeployqtはAPKパッケージのアセンブリに関与するハーベスタと同じであり、地獄は何を知っています。 iOSでも、状況は似ています。



結論





QtQuick / QMLを使用してゲームでUIを作成することは可能ですか? このライブラリを統合して使用した私の短い経験は、原則としてそれが可能であることを示しました。 しかし、多くは特定の目標と制限に依存します。



QtCreatorを開発に使用する準備ができている場合、軽微な不便さの大部分は自動的に消えますが、何らかの理由で最愛のVisual Studio、Xcode、またはviを使い続けたい場合は、苦痛に備える必要があります。



PC用のゲームを開発している場合、または数百メガバイトのリソースを備えた非常に大規模なモバイルプロジェクト(結局、そのようなものがある)の場合、25〜40 MBのライブラリは問題になりません。 Android向けに別のカジュアルゲームを作成し、アプリケーションごとに推奨される50MBで中国やイランの市場に目を向けている場合でも、このあまり役に立たない負荷のほとんどを占める前に3回考える必要があります。



ただし、独自のUIライブラリを作成したくない場合、QtQuick / QMLは、サイズとユーザビリティの面ではないにしても、パフォーマンスの面で競合他社よりも優れています。



プロジェクトへのQtの統合はそれほど複雑ではありませんが、メインループと初期化のロジックを強制的に変更することができます。 新しいプロジェクトでは、これはほぼ確実に生き残ることができますが、UIを別のQtQuick / QMLに変更してもそれほど苦労することはほとんどありません。



Qtのドキュメントはかなり優れていますが、場所によっては嘘をついているか不完全です。 これらの場合、ソースコードに移動する必要があります-そして、それが完全にオープンであることが非常に良いです! そのボリュームはしっかりしていますが、実際には、何かがどのようにロードまたは機能するかを把握することは非常に可能です。



ScaleformおよびCoherentと比較した場合のもう1つの欠点は、Scaleformを使用すると、使い慣れたAdobeプログラムのデザイナー向けのインターフェイスを作成でき、Coherentでは、HTMLスペシャリストを雇ってUIを開発できることです。 QMLでUIを開発するには、プログラマーとデザイナーのコラボレーションが必要です。 ただし、最終的には、ゲーム内のUIのパフォーマンスと動作の問題が始まると、これにまったく同じことが起こります。



一般的に、あなたはいつものように自分で決める必要があります!



GitHub MaxSavenkov / nya_qtでNyaエンジンとQt統合のコードを取得できます。



All Articles