✈️

Prepar3DにおけるSimConnect APIの使い方

2021/04/18に公開

概要

本記事では、Prepar3Dの機能拡張方法の1つであるSimConnect APIに関して簡単な例を交えて説明します。この記事を読んで頂ければ、SimConnectを通じてPrepar3Dを制御する基本的な方法が分かります。

目次

  • 1.Prepar3Dとは?
  • 2.Prepar3Dの機能拡張方法
  • 3.SimConnect APIの開発環境
  • 4.SimConnectによるPrepar3D制御方法

1.Prepar3Dとは?

一般にあまり馴染みが無いかもしれませんが、Prepar3D(以降P3D)はLockheed Martin社が製造するフライトシミュレーターソフトになります。

以下に、Prepar3Dの良い点を示します。

  • 初期状態で世界中の外界環境が用意されている(ただし初期は粗いテクスチャ)
  • 初期状態で複数の機体モデルが複数用意されている
  • 各種VR機器に対応している
  • 多くのAdd-onがある
  • プラグインを開発することで機能拡張可能(ただし本気でやると大変)

用途としては、ゲームなどの凝った作りは必要無く、とりあえず飛行機飛ばしてみるか・・・という人には中々便利なソフトになります。特にUnityでフライトシミュレーターを作ろうとした時、広大なマップの切替や正確な位置制御など少し面倒な部分を作る必要がありますが、とりあえず試すにはこれで十分なことが多いかもしれませんね。

もちろん、私は自分で作りたい派!というのもありますが、Unityなどで作る方がカスタマイズ性も含めて良いとは思います。

2.Prepar3Dの機能拡張方法

Prepar3Dには機能拡張するための方法が用意されています。大きく2つありますが、4項以降ではSimConnectと呼ばれる方法に関して説明していきます。

API 概要 出力
SimConnect 外部プロセスからP3Dを制御したい場合に使う *.exe
Prepar3D Development Kit(PDK) P3Dで最も低レベルなことをしたいならコチラ。SimConnectと違いdll形式で作成しP3Dの内部から呼ばれる構成になる *.dll
上記の通り、SimConnectAPIを使うことでP3Dの制御を外部から行うことが可能です。例えば、外部からP3Dを制御したい時はどんな時でしょうか?

例として、以下のようなことが挙げられます:

  • 既存の機体運動やシミュレーターシステムと連携して、視界映像だけ生成したい
  • シミュレーション中にカメラ位置や天候などを変更するツールを独自に作りたい

ちなみに、P3Dは例の一つ目のIG機能(Image Generator)を公式にサポートしています。しかし、細かい制御をする時にSimConnectから操作した方が簡単なので、本記事ではこの方法を紹介します。

3.SimConnect APIの開発環境

4項は以下の構成で確認しました。

公式サイトからSDKをダウンロードし、インストールして下さい。
何も変更しない場合、C:\Program Files\Lockheed Martin\Prepar3D v5 SDK 5.1.12.26829\にSDKがインストールされます。

上記フォルダ内にサンプルプロジェクトが幾つか入っています。どれもとても参考になりますが、最低限の動作を理解するならOpenAndCloseというサンプルが一番良いでしょう。

4.SimConnectによるPrepar3D制御方法

4.1 開始と終了

まずはSimConnectでP3Dを制御するために、P3Dにとのセッションを確立する必要があります。
この処理はP3Dのプロセスが存在しないと失敗します。つまり、P3Dを起動してから実行するか、P3Dが立ち上がるまで一定周期毎にセッション確立を試みるリトライ処理を組んでおくと良いです。
そして、処理が全て終わったら切断処理を行います。

HANDLE hSimConnect = NULL; // SimConnectとのセッション
// 開始処理
if (S_OK == SimConnect_Open(&hSimConnect, "セッション名", NULL, 0, 0, 0)) {
    // 成功
} else {
    // 失敗
}//else
//終了処理
if (S_OK == SimConnect_Close(hSimConnect)) {
    // 成功
} else {
    // 失敗
}//else

4.2 制御したいシミュレーション変数の登録

SimConnectを通じて制御したいP3Dのシミュレーション変数を定義します。
標準で用意されたシミュレーション変数は公式サイトに記載されています。

この中から必要なシミュレーション変数をピックアップします。ここでは例として、機体の位置と姿勢を登録する方法を記載します。

まずはP3Dで用意されたシミュレーション変数を自分のプログラムから呼ぶ時のIDを定義します。
IDは重複しない一意の番号であれば何でも構いません。

enum class P3dVariableId {
    PLANE_LATITUDE,
    PLANE_LONGITUDE,
    PLANE_ALTITUDE,
    PLANE_PITCH_DEGREES,
    PLANE_BANK_DEGREES,
    PLANE_HEADING_DEGREES_TRUE,
    MAX
};

登録はSimConnect_AddToDataDefinition関数で行います。

引数 内容
1 接続に成功したセッション
2 ID
3 P3Dで規定されたシミュレーション変数名
4 単位(データに応じて複数の単位に対応している場合がある)
5 データ種別(SIMCONNECT_DATATYPEに定義されている)
// 以下は簡略記載のため返り値を判定していないがOpenやCloseと同様に処置すること
SimConnect_AddToDataDefinition(hSimConnect, static_cast<unsigned long>(P3dVariableId::PLANE_LATITUDE),             "PLANE LATITUDE",             "degrees", SIMCONNECT_DATATYPE_FLOAT64);
SimConnect_AddToDataDefinition(hSimConnect, static_cast<unsigned long>(P3dVariableId::PLANE_LONGITUDE),            "PLANE LONGITUDE",            "degrees", SIMCONNECT_DATATYPE_FLOAT64);
SimConnect_AddToDataDefinition(hSimConnect, static_cast<unsigned long>(P3dVariableId::PLANE_ALTITUDE),             "PLANE ALTITUDE",             "meters",  SIMCONNECT_DATATYPE_FLOAT64);
SimConnect_AddToDataDefinition(hSimConnect, static_cast<unsigned long>(P3dVariableId::PLANE_PITCH_DEGREES),        "PLANE PITCH DEGREES",        "degrees", SIMCONNECT_DATATYPE_FLOAT64);
SimConnect_AddToDataDefinition(hSimConnect, static_cast<unsigned long>(P3dVariableId::PLANE_BANK_DEGREES),         "PLANE BANK DEGREES",         "degrees", SIMCONNECT_DATATYPE_FLOAT64);
SimConnect_AddToDataDefinition(hSimConnect, static_cast<unsigned long>(P3dVariableId::PLANE_HEADING_DEGREES_TRUE), "PLANE HEADING DEGREES TRUE", "degrees", SIMCONNECT_DATATYPE_FLOAT64);

4.3 シミュレーション変数の値更新

4.2項で制御したいシミュレーション変数の番号付け(ID)を定義しました。そのIDに対して値を設定すればP3Dに反映されます。

double latitude, longitude, altitude = 0.0; // 実際にはココに値が入っている
double pitch, roll, yaw              = 0.0; // 実際にはココに値が入っている

// 以下は簡略記載のため返り値を判定していないがOpenやCloseと同様に処置すること
SimConnect_SetDataOnSimObject(hSimConnect, static_cast<unsigned long>(P3dVariableId::PLANE_LATITUDE),             SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(double), &latitude);
SimConnect_SetDataOnSimObject(hSimConnect, static_cast<unsigned long>(P3dVariableId::PLANE_LONGITUDE),            SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(double), &longitude);
SimConnect_SetDataOnSimObject(hSimConnect, static_cast<unsigned long>(P3dVariableId::PLANE_ALTITUDE),             SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(double), &altitude);
SimConnect_SetDataOnSimObject(hSimConnect, static_cast<unsigned long>(P3dVariableId::PLANE_PITCH_DEGREES),        SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(double), &pitch);
SimConnect_SetDataOnSimObject(hSimConnect, static_cast<unsigned long>(P3dVariableId::PLANE_BANK_DEGREES),         SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(double), &roll);
SimConnect_SetDataOnSimObject(hSimConnect, static_cast<unsigned long>(P3dVariableId::PLANE_HEADING_DEGREES_TRUE), SIMCONNECT_OBJECT_ID_USER, 0, 0, sizeof(double), &yaw);

ここでは説明のため、あえてコードを全て平で記載しましたが、実際に使う際はテンプレート化してパッキングした方が楽です。楽というのもありますが、アーキテクチャ構造を考慮するとAPIを直接呼ぶより機能分離出来るのでオススメではあります。

おしまい

ここまで読んで頂き、ありがとうございました。
簡単にですが、これでSimConnectを利用したPrepar3Dの制御方法の基礎が分かったかな?と思います。

他にもSimConnectで実現出来る機能は色々ありますが、きっとニッチ過ぎて皆さんの役に立たないので備忘録も兼ねて今回はこの程度の内容で終わりたいと思います。

どうもお付き合い頂き、ありがとうございました!

Discussion