この記事は、Unreal Engine4(UE4) Advent Calendar 2015 その1の17日目の記事です。
前回の記事は、@tempkinder さんによる「CutomDepthを拡張して色も出力してみる」でした。
UE4で実装したモバイル端末において、マルチタッチは、ThirdPersonのテンプレートのThirdPersonCharacterのBPを見てもらえるとわかると思うのですが、InputTouchでタッチを
Press、Release,Move,Finger(指のインデックス)の情報をそれぞれ取れるようになっている
のが確認できると思います。
これをマルチタッチ対応のWindows機で実行してもらってDebugして驚愕の事実に
気づくと思うのですが、実は、Touch1以外の指に反応しないことがわかります。
このことについて、僕はハマったので、AnswerHubを検索してみると、
Windows 7/8 touch/ multi-touch supportと言う記事が見つかりました
読んでみると、Fingerの指の識別について、Windowsでは実装されてないとのこと。
iOSとかAndroidでは、実行してうまく指の認識をしてるのになんでWindowsでは
認識しないんだろうなーと思ってソースを読んでみようかなぁと思いながら、
4.9のUnrealBuildToolのコンパイルオプション的なところを調べていると、ちょっときになる記述を見つけました
if ((InBuildTarget.TargetType == TargetRules.TargetType.Program) && (GetCPPTargetPlatform(InBuildTarget.Platform) == CPPTargetPlatform.Win32)) { // Check if the target has requested XP support. if (String.Equals(InBuildTarget.Rules.PreferredSubPlatform, "WindowsXP", StringComparison.InvariantCultureIgnoreCase)) { SupportWindowsXP = true; } } if (WindowsPlatform.bUseWindowsSDK10 && WindowsPlatform.Compiler == WindowsCompiler.VisualStudio2015) { if (SupportWindowsXP) { throw new NotSupportedException("Windows XP support is not possible when targeting the Windows 10 SDK"); } // Windows 8 or higher required InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("_WIN32_WINNT=0x0602"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WINVER=0x0602"); } else { if (SupportWindowsXP) { // Windows XP SP3 or higher required InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("_WIN32_WINNT=0x0502"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WINVER=0x0502"); } else { // Windows Vista or higher required InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("_WIN32_WINNT=0x0600"); InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WINVER=0x0600"); } }
4.9は、VisualStudio2013でコンパイルされるはずなので、一番下の
InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("_WIN32_WINNT=0x0600");
InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WINVER=0x0600");
を通るのですが、VisualStudioのWindowsのタッチの定義、実はWINVER=0x06001からになってます。
このあたりは互換性の問題でこうなってるのか、VisualStudio2013でしかコンパイル対応してないからなのか、その辺はわかりませんが、こういう理由でTouchが対応してない状況でコンパイルされています。
(ちなみに、4.10では、VisualStudio2015対応になってますが 、このあたりまだ対応してないようでした。)で、対応するために、
InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WINVER=0x0601");
と書き換えてUnrealBuildToolをビルドし直して、UnrealEngine自体をビルドし直します。では、実際のプログラムに入っていきましょう。
実際のソースは、githubを見てもらうとして要点だけ説明します。コントーロールの操作なので、今回は、PlayerControllerを継承して実装します。BeginPlayで、アプリケーションハンドラを得て、アプリケーションに独自のメッセージハンドラを設定するようにします。このメッセージハンドラというのは、UE4用に定義されたWindowsのメッセージハンドラです。具体的に言うとWindowProcの部分のことと言っても間違いではないです。この部分の詳しいことは後で説明します。
void AMultiTouchPlayerController::BeginPlay(){ TSharedPtrGenericApplication = FSlateApplication::Get().GetPlatformApplication(); FWindowsApplication* WindowsApplication = (FWindowsApplication*)GenericApplication.Get(); WindowsApplication->AddMessageHandler(myMessageHandler); myMessageHandler.TouchController = this; myMessageHandler.InitVariable();
}
メッセージハンドラは、IWindowsMessageHandlerを継承して、定義します。
class GARDEN_API FMyWindowsMessageHandler : public IWindowsMessageHandler { public: void InitVariable(); virtual bool ProcessMessage(HWND hwnd, uint32 msg, WPARAM wParam, LPARAM lParam, int32& OutResult) override; AMultiTouchPlayerController *TouchController; bool isTouchInit; };
ProcessMessageと言うのがWin32のアプリを作ったことがある方なら知ってるであろうWinProc関数です。ProcessMessageの中身の詳しいところは、githubのソースを読んでもらうとして、概要を説明するとTouchのメッセージをHookして、処理してUE4側に投げるようにします。
あとは、注意点だけ書いておきます。Touchなどのメッセージ定義などは、WindowsAPIのWinuser.hに定義されていますが、これをincludeしようとすると、DWORDなどのWindows特有の定義などでエラーになってしまいます。
これを回避するために、"AllowWindowsPlatformTypes.h"と"HideWindowsPlatformTypes.h"のincludeで括ります。こうすることで、Windows特有の定義のエラーを回避することができます。
あと、 FSlateApplicationとかは、Slateに入っているので、*.Build.csに、"Slate"を追加しておきます。
以上マルチタッチについて駆け足でしたが書いてみました。
読んでいただきありがとうございます。
最後にMultTouchを使ったサンプル動画を貼って終わりにしときます。
明日は @rarihomaさんの「UE4+FMOD」です。FMODは前回のぷちコンの時@rarihomaさんが使っていて便利というのを聞いて調べようと思っていたところなのでありがたいです。