Nokia N9へのゲームの移植

この記事では、 Forest Tower DefenseゲームをNokia N9電話に移植することに焦点を当てます。



私はQtに精通していますが、QMLには不向きです。幸いなことに、アプリケーションでの使用を完全に回避できました(はい、可能です!)。 この記事のすべてのコードはC ++であり、oldfagsは承認します。







メインで唯一のゲームウィンドウはQGLWidgetです



class Widget : public QGLWidget, public Platform { Q_OBJECT //...
      
      





プラットフォームとは何か、クロスプラットフォームゲームの設計方法については、 こちらをご覧ください



グラフィックス



すべてのペイントはQWidgetで行われます:: paintEvent



 void Widget::paintEvent(QPaintEvent *) { QPainter painter(this); m_painter = &painter; Application::instance().render(); flushFragments(); }
      
      





興味深い発見を共有したい-QPainter :: drawPixmapFragmentsメソッド (Qt 4.7で登場)。 すべての画像が1つのQPixmapに保存されている場合、 QPainter :: PixmapFragmentオブジェクトの配列を作成するだけで十分です 。各オブジェクトには、元のQPixmapの座標、寸法、角度、スケール、透明度、位置が含まれます。 その後、QPainter :: drawPixmapFragmentsを1回呼び出します。すべてのフラグメントが描画されます。



 void Widget::flushFragments() { m_painter->drawPixmapFragments(m_fragments.constData(), m_fragments.size(), pixmap); m_fragments.clear(); }
      
      





このアプローチは、 QPainter :: drawPixmapを個別に呼び出すよりも高速です



全画面モード



ツールバーとステータスバーを非表示にするには、 showFullScreenメソッドを呼び出すだけです



 int main(int argc, char** argv) { QApplication a(argc, argv); QWidget w; w.showFullscreen(); return a.exec(); }
      
      







これは明白なように思えますが、偶然に偶然見つけました。ドキュメントでこの方法に気付き、試してみることにしました。 Googleで「meego harmattan hide toolbar」のようなものを検索した場合、C ++ではなくQMLでこれを行う方法を見つけることができます。 QWidgetにはshowMaximizedメソッドもあり、showFullScreenとはまったく異なる動作をすることに注意してください。





Nokia N9のQSoundは機能しません。このオプションは消えます。 フォノンは機能しますが、BGMの再生にのみ適しています。 重複する可能性のある短くて速いサウンドエフェクトには、他の何かを見つける必要がありました。 私の選択は、Qtでゲームを開発するための一連のクラスであるQtGameEnablerでした



ゲームに効果音を追加する基本的な手順は次のとおりです。



a)qtgameenablerフォルダーをプロジェクトルートにコピーし、.proファイルに行を追加します



 include(qtgameenabler/qtgameenableraudio.pri)
      
      





b)オブジェクトAudioMixerAudioOutを作成します



 GE::AudioMixer audioMixer; GE::AudioOut audioOut(&audioMixer);
      
      





c)サウンドごとにAudioBufferを作成します



 GE::AudioBuffer* appleHit = GE::AudioBuffer::loadOgg("/opt/foresttd-n9/assets/audio/appleHit.ogg"); GE::AudioBuffer* iceCrash = GE::AudioBuffer::loadOgg("/opt/foresttd-n9/assets/audio/iceCrash.ogg"); GE::AudioBuffer* arrowFly = GE::AudioBuffer::loadOgg("/opt/foresttd-n9/assets/audio/arrowFly.ogg");
      
      





d)サウンドを再生するたびに、 AudioBufferPlayInstanceオブジェクトを作成してAudioMixerに追加します



 GE::AudioBufferPlayInstance* playOneTime = new GE::AudioBufferPlayInstance(appleHit); playOneTime->setDestroyWhenFinished(true); audioMixer.addAudioSource(playOneTime);
      
      







10を超える音が同時に再生され、不快なカカkが生じることがあります。 これを克服する簡単な方法は見つかりませんでしたが、かなりエレガントな方法を思い付きました-AudioBufferPlayInstanceを継承し、現在のサウンドのグローバルカウンターを作成しました。



 class SoundInstance : public GE::AudioBufferPlayInstance { public: SoundInstance(GE::AudioBuffer* buffer) : GE::AudioBufferPlayInstance(buffer) { ++ms_count; } virtual ~SoundInstance() { --ms_count; } static int count() { return ms_count; } private: static int ms_count; }; int SoundInstance::ms_count = 0;
      
      





各サウンドを再生する前に、カウンターが増加し、その後に減少します。 したがって、同時に再生されるサウンドの数を制御できます。



 if (SoundInstance::count() < MAX_SOUNDS) { GE::AudioBufferPlayInstance* playOneTime = new SoundInstance(sound); playOneTime->setDestroyWhenFinished(true); audioMixer.addAudioSource(playOneTime); }
      
      





AudioBufferPlayInstanceデストラクタを仮想化し、またsetDestroyWhenFinishedメソッドを作成してくれたQtGameEnabler開発者に感謝します! また、トランクの最新バージョンはogg形式をサポートしているためです!



もう1つの非常に重要な点:ハードウェアキーを使用してゲームで音量を変更するには、以下を行う必要があります。



a).proファイルに追加します



 # Classify the application as a game to support volume keys on Harmattan gameclassify.files += qtc_packaging/debian_harmattan/$${TARGET}.conf gameclassify.path = /usr/share/policy/etc/syspart.conf.d INSTALLS += gameclassify
      
      





b)qtc_packaging / debian_harmattan / your_target_name.confファイルは



 [classify gaming] /opt/usr/bin/your_target_name
      
      







入力処理



マルチタッチを使用しなかったため、 QWidget :: mousePressEventQWidget :: mouseMoveEventおよびQWidget :: mouseReleaseEventをオーバーライドする必要がありました。



 void Widget::mousePressEvent(QMouseEvent *e) { QGLWidget::mousePressEvent(e); float y = height() - e->y(); m_mouseDown = true; Application::instance().touch(e->x(), y); } void Widget::mouseReleaseEvent(QMouseEvent *e) { QGLWidget::mouseReleaseEvent(e); float y = height() - e->y(); m_mouseDown = false; Application::instance().release(e->x(), y); } void Widget::mouseMoveEvent(QMouseEvent *e) { QGLWidget::mouseMoveEvent(e); if (m_mouseDown) { float y = height() - e->y(); Application::instance().drag(e->x(), y); } }
      
      





ドレイン「float y = height()-e-> y()」に注意してください。 「y」の値をQWidget座標系からデカルト座標に変換するためです。



ゲームサイクル



最も単純なゲームサイクルを実装するために、次のことを行いました。



a) QObjectの再定義:: timerEvent



 void Widget::timerEvent(QTimerEvent *) { Application::instance().simulate(); // game logic update(); // repaint }
      
      





b)ゲームの開始時



 m_timerId = startTimer(0);
      
      





c)ゲームが一時停止状態になったとき



 killTimer(m_timerId);
      
      







一時停止



ユーザーがゲームを最小化すると、「一時停止」モードに切り替える必要があります。



a) QObjectをオーバーライドする:: eventFilter



 bool Widget::eventFilter(QObject* object, QEvent* event) { if (event->type() == QEvent::ActivationChange) { if (isActiveWindow()) { resume(); // start timers, resume music } else { pause(); // kill timers, pause music } } return QWidget::eventFilter(object, event); }
      
      





b)イベントフィルターを設定する



 int main(int argc, char** argv) { QApplication a(argc, argv); Widget w; w.show(); a.installEventFilter(&w); return a.exec(); }
      
      





Ovi Storeでモデレートのために最初にゲームを送信したときに、QAがバグを発見しました。アプリケーションを最小化し、.desktopアイコンをクリックして再起動しようとしても、アプリケーションは拡張しませんでした



バックグラウンドでアプリケーションを中断した後、アプリケーションアイコンをクリックしてアプリケーションを前に戻すことはできません。



この動作に非常に驚きました。ゲームは通常、実行中のアプリケーションの画面([アプリを開く]画面)から反転しましたが、アイコンをクリックしても何も起こりませんでした。 この問題の解決策の検索は失敗に終わり、見つかったのはMeeGo Harmattanアプリケーションのライフサイクルだけでした。 Stackoverflowは沈黙していました。developer.support@ nokia.comも自分で解決する方法を探す必要がありました。 アイコンをクリックすると、QWidget :: eventFilterにイベントが来るかどうかを確認することにしました。



 bool Widget::eventFilter(QObject *object, QEvent *event) { if (event->type() == QEvent::ActivationChange) { if (isActiveWindow()) { resume(); } else { pause(); } } qDebug() << event->type(); return QWidget::eventFilter(object, event); }
      
      





イベントにはコード50が付属していることが判明しました。どのようなイベントかを調べました。

QEvent :: SockAct-ソケットがアクティブになり、QSocketNotifierの実装に使用されます。

WTF? どのソケット?! 結局、私のゲームはオンラインになりません。 知って、教えてください。 面白いのは、私がキャッチした唯一のイベントです。



 bool Widget::eventFilter(QObject *object, QEvent *event) { if (event->type() == QEvent::ActivationChange) { if (isActiveWindow()) { resume(); } else { pause(); } } else if (event->type() == QEvent::SockAct) // pure magic { activateWindow(); resume(); } return QWidget::eventFilter(object, event); }
      
      







バイブロ



振動効果を追加するには、次のものが必要です。



a).proファイルに次の行を追加します



 CONFIG += mobility MOBILITY += feedback
      
      





b)必要なヘッダーファイルを接続する



 #include <QFeedbackHapticsEffect>
      
      





c)エフェクトオブジェクトを作成する



 QFeedbackHapticsEffect vibro; vibro.setAttackIntensity(0.0); vibro.setAttackTime(40); vibro.setIntensity(0.5); vibro.setDuration(80); vibro.setFadeTime(40); vibro.setFadeIntensity(0.0);
      
      





d)適切なタイミングで電話をかける



 vibro.start();
      
      





ここではすべてが簡単に思えますが、最初は、Nokia N9で仮想キーボードのボタンを押したときのような振動効果を達成したかったのです。 誰かがこれを行う方法を知っている場合は、共有してください。



資源



リソースを.rcファイルにパックしたくありませんでした。リソースフォルダーはAndroid /デスクトップ/ MeeGoで共有され、2レベル高いのに対し、QtCreatorではすべてのリソースがプロジェクトフォルダー内にある必要があるためです(少し奇妙です)要件、見つけられませんか?)



そこで私は別の方法で、リソースを.proファイルにコピーするためのルールを追加しました。



 assetsDir.source = ../../assets DEPLOYMENTFOLDERS = assetsDir installPrefix = /opt/$${TARGET} for(deploymentfolder, DEPLOYMENTFOLDERS) { item = item$${deploymentfolder} itemfiles = $${item}.files $$itemfiles = $$eval($${deploymentfolder}.source) itempath = $${item}.path $$itempath = $${installPrefix}/$$eval($${deploymentfolder}.target) export($$itemfiles) export($$itempath) INSTALLS += $$item }
      
      





../../assetsにあったすべてのファイルとフォルダーは、インストール中にN9にコピーされ、/ opt / foresttd-n9 / assetで利用可能になります。



アイコン





ここからファイルを使用すると、MeeGo Harmattanスタイルのアイコンを簡単に作成できます(アイコンテンプレート)







結果



このアプリケーションは、2viのコストであるOvi Storeにすでに登場しています。 これは、OviストアにあるNokia N9向けの唯一のタワーディフェンスゲームです。 QAプロセスはかなり速くなりました-バグを修正してから2日間、さらに1日間ゲームのレビューが行われていました。 Nokiaのエンジニアによるアプリケーションの無料テストは、良い機会です。



N9のNokiaに感謝します。電話はとてもクールです。

また、Android向けゲームの無料版を改善するための多数のバグレポート、レビュー、アイデアについて、すべての住民に感謝します 。市場では、新しいレベルのアップデートを見つけることができます。



All Articles