UnrealEngine4用プラグイン DirectInputPadPluginの使い方
UE4(Windows)でDirectInputのゲームパッドを使えるようにするプラグインを作りました。
DirectInputPadPlugin Ver.0.9のものです。
これ以降、DirectInputのゲームパッドのことをDIパッド(DIPad)、XInputのゲームパッドのことをXIパッド(XIPad)、両方合わせた場合はたんにゲームパッド(GamePad)と表記します。
インストール
- 上のGithubからソースをチェックアウト、もしくはZIPをDOWNLOADします。
- それらのソースを「DirectInputPadPlugin」という名前のフォルダを作って、そこに入れます
- 「DirectInputPadPlugin」フォルダを、[プロジェクトフォルダ]/Plugins に移動します
あとは、
を参考にソースをビルドしてください。
DirectInputのゲームパッドの接続確認
ゲームパッドをPCに挿した状態でUE4エディタを立ち上げます。動的な抜き差しには対応していませんので、エディタやゲーム起動前には挿しておいてください。
接続が成功していれば、アウトプットログに
DirectInputPadPlugin: DirectInputDriver initialized. DirectInputPadPlugin: DirectInputPad detected: 1 DirectInputPadPlugin: DirectInput Joystick Create Success. : Elecom Wired Gamepad
見つかったDIパッドの数と、その数だけ接続が確認できたDIPadの名前が表示されます。
これでDIパッドを使用する準備が完了です。
キーイベント
GamePadイベントをそのまま使うことができます。
など。
基本的には、GamePadイベントを使うことを想定しています。なぜなら、GamePadイベントはXIパッドのイベントでもありますので、ユーザーがXIパッドでもDIパッドでもどちらのゲームパッドを使っていても良くなるからです。
パッドキャリブレーション
GamePadイベントをDIパッドでも使うには、DIパッドをXIパッドの配置にする必要があります。XIパッドというのは、ようはXBOXのパッドのことです。
デフォルトでは以下のような対応になっています。
XIパッド | DIパッド |
---|---|
左スティックX | X軸 |
左スティックY | Y軸 |
右スティックX | Z軸 |
右スティックY | Z回転軸 |
方向パッド上 | POV上 |
方向パッド右 | POV右 |
方向パッド下 | POV下 |
方向パッド左 | POV左 |
A | ボタン1 |
B | ボタン2 |
X | ボタン3 |
Y | ボタン4 |
LB(L1) | ボタン5 |
RB(R1) | ボタン6 |
Lトリガー(L2) | ボタン7 |
Rトリガー(R2) | ボタン8 |
BACK | ボタン9 |
START | ボタン10 |
左スティックボタン | ボタン11 |
右スティックボタン | ボタン12 |
変更に使うノードは、SetKeyMapです。
Ver.0.9からの機能として、軸にボタン、ボタンに軸を割り当てられるなど、キャリブレーションの自由度を上げました。
図の左から
- 「XIパッドの左スティックX軸として、DIパッドのX軸を割り当てる」
- 「XIパッドの右スティックY軸(下方向)として、DIパッドのボタン1を割り当てる」
- ボタン1が押されていないなら0,ボタン1が押されていると-1 が返るようになります
- 上方向に割り当てる時は、Negativeフラグをオフにします
- 「XIパッドのボタンAとして、DIパッドのX回転(正方向)を割り当てる」
- X回転の正方向の値に応じて、ボタンAが押されているという判定がされます
- X回転の負方向の値を使うならば、Negativeをオンにします
Ver.0.8では対応できていなかったLT(L2)/RT(R2)への軸の割り当てもできるようになっています。
SetKeyMapは重複してキーを割り当てられるのでご注意ください。KeyMapを削除するには、DIKeyの項目を「DIGamePad END」にすることでできます。
GetDirectInputPadJoystickノード
PlayerIndexを使ってDIパッドを取得するノードです。DIパッドは見つかった順番にPlayerIndexが割り当てられて、対応するプレイヤーの入力として使われます。
XIパッドが同時に挿しこまれていた場合は、XIパッドを優先します。DIパッドにはXIパッドの次のPlayerIndexが割り当てられます。つまり、XIパッドが挿しこまれてないないなら0番から、XIパッドが1つ挿しこまれていたら1番から割り当てられます。
PlayerIndexに対応するDIパッドがなかった場合は、nullが返ります。
(回転)軸の反転
DIパッドによっては、XIパッドと軸の値が逆になっていることがあります。XIパッドの左スティックYは上がプラスで下がマイナスになりますが、私が普段使っているDIパッドのY軸は上がマイナスで下がプラスになっています。
このまま軸を割り当てると上下が反転した状態で処理されてしまいますので、軸の値を反転させる必要があります。その時は、SetAxisReverseノードを使います。
引数上ではボタンも選べますが、当然意味はありません。
反転フラグの値を調べるには、IsAxisReverseノードを使います。
ChangedState系ノード
パッドキャリブレーションをサポートするノード群です。
呼び出したフレームで状態に変化のあったキー情報を取得するノードです。
状態の変化とは、軸なら初期値(通常は0)以外の入力値になっている、ボタンなら押されたか離されされたか、ということになります。
IsChangedKeyStateノード
状態が変化したキーがあるかをチェックします。変化したキーがあればtrueが返ります。
Get(All)ChangedKeyStateノード
GetChangedKeyStateノードは変化のあったキー1つだけ、GetAllChangedKeyStateは変化のあったキーすべて取得します。
変化のあったDIパッドとしてのenumと変化値が取得できます。変化値は、軸の時は軸の値、ボタンの時は正だとPressed、負だとReleasedの意味になります。
Real引数をtrueにすると、反転フラグなどキー設定を無視したパッドの実入力値で変化値を取得できます。
GetChangedKeyStateは、通常は軸の変化を優先しますが、Btn引数をtrueにすることでボタンの変化を優先的に取得するようになります。
ユーザーに「Aボタンの場所を押してください」などと促し、押されたボタンを検出(GetChangeKeyState)、そのボタンをAボタンとして設定する(SetKeyMap)、という使い方を想定しています。
ユーティリティー
ゲームパッドの名前と識別子
ゲームパッドの名前はGetProductNameノード、識別子はGetGUIDノードで取得できます。
名前はまったく同じパッドの場合、同じ名前になることがあるので識別には使えませんが、ユーザーがコントロールしているパッドを示すのには使えます。
キーコンフィグ情報を保存/復元する際など、個々のパッドを識別するためにはGUIDを使用してください。ただし、このGUIDはローカルでのみ一意性が保証されてるGUIDですのでご注意ください。
入力値のクリア
現在保持している入力値をクリアします。
プラグインが初期化できたか
コンフィグ
BACKGROUND設定にするか
DefaultInput.ini に以下のセクションを追加してください
[DirectInputPadPlugin] Background=true
エディタ起動時は、常にBACKGROUND動作となります。
以上になります。
UnrealEngine4で2Dゲームを作ろう! その14 DirectInputプラグイン作った編
前回紹介したJoystickPluginは問題が発覚したために、結局自作しました。
ひとまず、
を参考にソースからビルドしてUE4に追加してください。
通常のゲームパッドイベントとして受け取れるようにしましたので、すぐに使えると思います。
とはいえ、ボタン配置がパッドごとに違うDirectInputのゲームパッドを扱うにはもう少し手を入れる必要があるので開発は続けます。
詳しい使い方は、近いうちに記事にします。
JoystickPluginの問題
あれからソースをさらに読み込んだ所、JoystickPluginは入力の取得をActorのTickタイミングで行っていることがわかりました。
ちょっとこれは問題で、ゲームジャンルによっては致命的な問題となりかねません。
ゲームパッドなどのデバイス入力は、全Actorが動く前に取得するのが望ましいです。
UE4もその辺りの事情は当然わかっているので、独自入力デバイスをさしこんで、しかるべきタイミングで入力取得メソッドを呼んでくれる仕組み*1があります。それに沿った形で実装したプラグインとなっています。
その辺りのソースを読んでいたら、キーイベント放出あたりの事情も理解できたので、通常のゲームパッドイベントと統合できたという感じです。
UnrealEngine4で2Dゲームを作ろう! その13 DirectInputを使おう編
UE4でゲームパッドを使おう!(Windows)というお話です。
※追記※ JoystickPluginを本採用するのはオススメできなくなりましたので、DirectInputのプラグインを作りました。こちらを見てみてください。
UE4のゲームパッド対応
UE4(4.10現在)が対応してるパッドは、XInputパッドのみです。
XInputというのはWindowsでXboxのパッドを使えるようにするものでAPIが整理されてて使いやすくはあるんですが、Xboxのパッドしか使えないという欠点を抱えています。もちろん、XInput対応をうたっているゲームパッドは使えますが、世の中に出回っているほとんどのPC用ゲームパッドはXInputに対応されていません。*1
多くのゲームパッドに対応するには、DirectInputへの対応が必須なのですが、UE4はサポートしていません。
フォーラムでもDirectInput対応して欲しいという要望は上がっていますが反応がよくないので、公式サポートは期待できません。
UE4でDirectInputゲームパッドを使う!
やり方は、2つあります。
Xbox 360 Controller Emulatorを使う
DirectInput入力をXInput入力に変換してアプリに渡してくれるフリーソフトです。通称360ce。使い方は、適当にググってください。
ざっとですが使ってみた所、UE4でも動きます。UE4エディタで動かすには出てきたDLLをエディタのexeファイルがあるフォルダにコピーしてください。ゲーム本体で使うなら、パッケージ化してゲームexeと同じフォルダにDLLをいれてください。
DLLを同梱して、適当にコンフィグファイルをでっち上げれば動かせるかなと思ったのですが、動作を調べた所、パッド名などを使って変換すべき入力を判定してるようです。つまり、制作側でコンフィグファイル用意しても意味がないという……。
そうなると、360ceの設定をユーザーに強いることになるので、どうなんだろうなぁ、と思ったので自分は使わないことにしました。元々使ってるユーザー向けに360ceでも大丈夫だよ!みたいなことをマニュアルに書く分にはありかなとは思います。
JoystickPluginを使う!
というわけで、UE4でDirectInputパッドを使えるようにするプラグインを使用します。ここでは、Ikarus76氏が作ったオリジナル版を対象に話を進めます。DirectInputを使いたいという要望は多いので、このプラグインをベースに派生がいくつも作られていますので気になる方はそちらも見てみると良いかと思います。
DLできるプラグインは、古いバージョンのUE4でビルドされたものですので、4.10で使うにはビルドしなおす必要があります。
ビルド方法は、前記事を参考にして下さい。
JoystickPluginを4.10でビルドを通す
そのままではコンパイルエラーでビルドが通りませんので、以下の場所を修正します。
JoystickSingleController.h 15行目/18行目
- 変更前
15: int64 ButtonsPressedLow; 18: int64 ButtonsPressedHigh;
int64をint32に変更
- 変更後
15: int32 ButtonsPressedLow; 18: int32 ButtonsPressedHigh;
この変数は、DirectInputから取得したボタンの押下情報をbitごとに保存する変数です。
int64となっていたのは、DirectInputの仕様である128個のボタン押下情報を保存するつもりだったようですが、実際には32個ずつ64個の情報しか保存してませんのでint32で問題ありません。(WinJoystick.h 878行目~898行目の処理)
WinJoystick.h 467行目
- 変更前
467: INT_PTR WINAPI WinProcCallback(
INT_PTRをLRESULTに変更
- 変更後
467: LRESULT WINAPI WinProcCallback(
これはWinAPIの仕様です。
WinJoystick.h 643行目/646行目
- 変更前
643: if (strVid && swscanf_s(strVid, L"VID_%4X", &dwVid) != 1) 646: if (strPid && swscanf_s(strPid, L"PID_%4X", &dwPid) != 1)
swscanf_sでの受け取り型の不一致ですので、適当にキャストします。
- 変更後
643: if (strVid && swscanf_s(strVid, L"VID_%4X", reinterpret_cast<uint32*>(&dwVid)) != 1) 646: if (strPid && swscanf_s(strPid, L"PID_%4X", reinterpret_cast<uint32*>(&dwPid)) != 1)
DWORDはunsined longなので、uint32と(VCでは)互換があるはずなのですが、なぜかエラーになるのでキャストします。
以上のことをしてビルドを通して、JoystickPluginを有効にすると、DirectInputのゲームパッドから入力を取る準備ができたことになります。
JoystickPluginを動作させる
JoystickPluginを有効にしてエディタを起動します。アウトプットログに「JoystickPluginLog: Direct Input initialized.」と出れば使用準備が完了です。Failになってたり、ログに何もなかったらプラグインの起動に失敗していますので、ビルドをやり直して見て下さい。
入力データを取る方法は2つあります。どちらかを選択してください。両方同時には動きません。*2
JoystickPluginActorを使う
JoystickPluginが用意している基本のActorです。これをJoystickを使いたいレベルに配置することで、Joystickの入力をBPで取得することができるようになります。
こちらの方法で大体のことはできると思います。通常の入力イベントは使えますし、アクションマッピングも動作します。
ただ、JoystickInterfaceに実装されている一括イベントが、JoystickPluginActorを使う方法では取得できませんので、それが必要な時は次の方法を使います。
自前のJoystickActorを作る
JoystickPluginActorを継承したActorか、JoystickComponentとJoystickInterfaceを両方持たせたActorを作ります。
そうすることで、何かボタンが押された、軸入力があったなどのイベントを取ることできるようになります。キーコンフィグとか作る時は便利です。
データ接続はActorのTickで行われている
入力データの接続はActorのTickで行われているので、ポーズするとJoystickの入力が取得できなくなります。JoystickActorはポーズ中もTickを呼ぶ設定にしておくと良いと思います。
JoystickPluginから取得できる情報
ボタンはゲームパッドカテゴリ、軸系はなぜかキーボードカテゴリになっています。
通常の入力イベント
キーボード入力やマウス入力と同様に、Joystick入力イベントが使えるようになります。
一括イベント
上図のように、入力の変化を一括して取得することができます。同時に複数の変化があった場合(ボタンの同時押しなど)は、変化があった回数だけイベントが呼ばれます。
この動作イベントは、JoystickInterfaceを持ったActorのグラフでのみ使用することができます。
詳細情報(JoystickSingleController)
イベントに頼らず入力情報を確認する方法もあります。
上図のGetLatestFrameノードを使うことで、最新の入力データを見ることができます。コンパイルを通す時に紹介したJoystickSingleControllerがそのデータです。詳細は、右クリしてJoystickFrameで検索すると以下のような感じです。
よく使うプロパティの使い方を軽く説明しますと、
Buttons Pressed High/Low
ボタンが押されているかをビット単位で持っています。下位ビットから始まって、Lowがボタン1から32、Highがボタン33から64まで持っています。そのため、ボタンの押下情報は「bitwise and」を使って取得します。
GetAxis/RAxis
Axisが軸入力、RAxisが回転入力です。Vectorになっていまして、VectorのXがX軸の値という風に、XYZがそのまま対応しています。
DirectInputの場合、多くのパッドは、左スティック横X軸・縦Y軸、右スティック横Z軸・縦Z回転に割り当てられてるのをちょっとだけ覚えておくと良いかもしれません。
GetPOV
POV入力です。0~2まで3つあるのはDirectInputの仕様だからですが、通常はPOV0しか使いません。いわゆる十字キーに割り当てられてることが多いです。押されてる方向のEnum値が取得できます。
XInputとの共存
JoystickPluginは、XInputパッドとして見つかったとしてもDirectInputパッドとして動作するようになっていますので、パッドはすべてJoystickとして実装する場合は特に問題はありません。*3
XInputならXInputとして扱いたい場合は、UE4のゲームパッド入力をチェックしてイベントがあったらJoystick動作を止めるとかそういう処理を書くことになるかと思います。
JoystickPlugin使用上の注意
入力を取得してるJoystickは1つだけ
最初に発見したJoystickのみ入力を取りにいっています。複数のJoystickを使う必要があるときは、派生JoystickPluginを使いましょう。
複数のJoystickActorを切り替えながら使うのも非推奨
同時に動かせなくても切り替えられるだろう? と思いきや、JoystickPluginの設計上の問題で簡単にはいきません。
JoystickActorを切り替える時はTickのON/OFFだけではダメでBeginPlayも呼ぶ必要があります。いらなくなったActorをDestoryして、新しいActorをSpawnすれば良いということではあります。
ただ、どうやっても一括イベントを取得できるActorは必ず1つだけです。
*1:XInput対応パッドはちょっとお値段が上がるので、よほどわかってる人以外買って無いと思われます
*2:両方使ってしばらく悩みましたとさ
*3:はじめはXInputパッドはDirectInputパッドから削除する実装にしようとしてたみたいですがコメントアウトされてました
UnrealEngine4で2Dゲームを作ろう! その12 プラグインをソースからビルドする
JoystickPluginについて書いていたんですが、その前章としてプラグインのビルド方法について書きます。
対応バージョンは、UE4.10です。
VS2015をインストールする
まずは、UE4.10で対応となったVS2015をインストールする必要があります。
DL先は、「Visual Studio 2015 製品の概要」。これのCommunity版を落としてインストールします。
デフォルト設定では、VC++がインストールされませんので、カスタムを選択して、プログラミング言語→Visual C++のインストールにチェックをいれてください。
それ以外の項目は、UE4だけで使うなら必要ありませんのでチェックを外しても大丈夫です。
UEプロジェクトのC++プロジェクトを作る
すでにUEプロジェクトでC++を利用している場合は、C++プロジェクトは作成済みですので、この項目は飛ばして下さい。
BPオンリーで作業をしていると、C++プロジェクトがありませんので、まずはそれを作ります。
1.エディタのファイルメニューから、「新規C++クラス...」を選択
2. 親クラスはNoneのままで、[次へ>]を押す
プラグインのソースをプロジェクトに追加してビルドする
1. UEプロジェクトに[Plugins]というフォルダを作り、そこにプラグインを入れる
UEプロジェクトを作ったばかり時には、Pluginsフォルダはありませんのではじめてプラグインを導入する時はフォルダを作ります。
なお、[Plugins]と複数形です。
2. UEプロジェクトのファイルを右クリックし、[Generate Visual Studio Project Files]を選択
UnrealEngine4で2Dゲームを作ろう! その11 見下ろしマップの回り込み処理
たまには「2Dゲーム作ろう!」らしいネタで、キャラクターとマップ上のオブジェクトとの描画順をどうするのかというお話です。
回り込み
回り込みという表現はサークルローカルかもしれないので、実例のgifアニメが下の通り。(マチネででっち上げたので歩きアニメになっていのはただの手抜きですw)
回り込み処理 あり | 回り込み処理 なし |
像の周りを回った時に、キャラクターの位置に応じて像の前後にグラフィックが表示されるかどうかということです。
3Dだと奥行き情報をモデルやコリジョンが持っているので特別考える必要はないのですが、2Dだと相変わらず自前で処理する必要があります。とはいえ、内部的には3D処理されていますので、奥行き軸(見下ろしの時はZ軸、サイドビューの時はY軸)の値を変更するだけで対応ができます。
奥行き値の計算
見下ろしの場合は画面下方にあるほど、画面手前にきますので、Y座標をZ座標にコピーしています。
あとで、ある程度調整ができるように基本Z値を指定できるようにしてあります。
AdjustZ関数のScene引数はSceneComponentのことで、本ゲームではPaperFlipbookComponentを引数に渡しています。移動を行うActorはこの関数を適切なタイミングで呼んでいます。
回り込みはグラフィックだけで良いのでActor自体のZ値は書き換えません。ActorのZを書き換えてしまうとコリジョンがめんどくさいです。
この計算だとマップが広いとカメラのZ値を超えてしまうこともあるので、カメラのZ値はかなり大きい値を入れておきます。
また、マップ上の静的スプライトもこの計算式を念頭に置いたZ値をPaper2Dのコンポーネントに入れておきます。
奥行き計算アルゴリズムとソート軸
この辺の処理を作っている時に見つけたのですが、奥行き計算をどうするのかという設定が、プロジェクト設定にありました。
[プロジェクト設定]→[Rendering]→[透過性] です。
見下ろしマップの場合は上図のように設定すると良いと思います。
項目 | 意味 |
Translucent Sort Policy | 奥行きソートのアルゴリズム。[Sort Along Axis]は指定軸の値に依存する。2Dゲームの場合はこれで十分です |
Translucent Sort Axis | アルゴリズムを[Sort Along Axis]にした場合のソート軸。見下ろしの場合はZ軸になりますので、(x, y, z)=(0.0, 0.0, -1.0) と値を入れておきます。 |