Leap Motion実用サンプル(Visual Basic編)
Leap MotionによるWPFアプリ上のオブジェクトの移動
Leap Motionの動くサンプルを実際に作ってみる。今回はWPFの画面上に配置したオブジェクトを、Leap Motionによる操作で移動させるアプリを作成。
今回は、画面上に配置したオブジェクトを、Leap Motionによる操作で移動させるデスクトップ・アプリを作成する。さっそく、その開発内容を説明していこう。
まずWPFプロジェクトを作成しよう
今回のLeap Motionのデスクトップ・アプリは、WPFで作成する。
これには、Visual Studio 2012(以下、VS 2012)のIDEを起動して、メニューバーから[ファイル]-[新規作成]-[プロジェクト]と選択して、それにより表示される[新しいプロジェクト]ダイアログで「Visual Basic」のテンプレートから「WPF アプリケーション」を選択する(Leap Motionは、.NET Framework 3.5と4.0に対応しているが、.NET Framework 4.5でも動作する。今回のアプリは全て.NET Framework 4.5で作成している。しかし、あくまでも対応しているのは、.NET Framework 3.5と4.0だ。心配な方は、.NET Framework 4.0で作成すると安心だろう)。[名前]欄には、ここでは「SelectedObjectMove」と指定する。
[ソリューション エクスプローラー]内に「Images」というフォルダーを作成して、4枚の(任意の)画像を配置しておく。
WPFの基本的な作成手順は、第1回と同じ手順となるので、説明を割愛する。具体的な手順は、第1回の「参照の追加」「プロジェクトのルートに「LeapCSharp.dll」と「Leapd.dll」を追加する」「プロパティを設定する」を参考にしてほしい。
今回のLeap Motionアプリについて
今回のアプリは、画面上に配置した4枚の画像を、Leap Motionでタッチして、任意の場所に移動するアプリだ(次の画面を参照)。画像が重なっている場合は、選択された画像が一番前面に表示され、移動が可能になる。
画面のレイアウト(MainWindow.xaml)
前回と同じように、デフォルトでGridコントロールが配置されているのをCanvasコントロールに変更する。その理由は、座標値が取得しやすいからだ。
XAMLデザイナー画面上で、先ほどのCanvasコントロール上に、Imageコントロールを4個配置する。名前には「Image1」~「Image4」としておく。各ImageコントロールのSourceプロパティに、あらかじめ[ソリューション エクスプローラー]内に作成しておいたImagesフォルダー内の画像を指定する。
またLeap Motionのタッチ・ポイントを表示させるために、「paintCanvas」という名前のInkPresenterコントロールをCanvasコントロール上に配置する。このInkPresenterコントロールは、どのコントロールよりも一番手前に配置しておく必要がある、レイアウト配置は次のようになる。
名前が「Image1」~「Image4」のImageコントロールを4個配置し、それぞれのSourceプロパティにImagesフォルダー内の画像を指定する。
全てのコントロールの一番前面に「paintCanvas」という名前のInkPresenterコントロールを配置する。この領域にタッチ・ポイントが表示される。
XAMLデザイナーで上記のレイアウトを行うと、書き出されるXAMLコードはリスト1のようになる。
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="1080" Width="1920" WindowState="Maximized">
<Canvas>
<Image x:Name="Image1" HorizontalAlignment="Left" Height="240" VerticalAlignment="Top" Width="320" Source="Images/林_01.png" Canvas.Left="91" Canvas.Top="26" />
<Image x:Name="Image2" HorizontalAlignment="Left" Height="240" VerticalAlignment="Top" Width="320" Source="Images/林_02.png" Canvas.Left="432" Canvas.Top="26" />
<Image x:Name="Image3" HorizontalAlignment="Left" Height="240" VerticalAlignment="Top" Width="320" Source="Images/林_03.png" Canvas.Left="777" Canvas.Top="26" />
<Image x:Name="Image4" HorizontalAlignment="Left" Height="240" VerticalAlignment="Top" Width="320" Source="Images/林_04.png" Canvas.Left="1111" Canvas.Top="26" />
<InkPresenter Name="paintCanvas"/>
</Canvas>
</Window>
|
前回も説明したが、ルートのCanvasコントロールの最後に<InkPresenter>要素が記載されているが、これによりInkPresenterコントロールが最前面に表示されるようになる。
プログラム・コード(MainWindow.xaml.vb)
では、次にプログラム・コード(MainWindows.xaml.vbファイル)を見ていこう。プログラム・コードも、タッチ処理以外は第1回と基本的に同じ内容となるので、説明を割愛する。まずは第1回の「名前空間の読み込み」「メンバー変数の宣言」「MainWindow_Loadedメソッドの処理」「Updateメソッドの処理」の開発手順を参考にタッチ処理の前までを実装してほしい。相違点として、下記の2点を修正してほしい。
(1)第1回のリスト3にある「Private Message As String」という行を削除して、「Private no As Integer」という行を追加: 今回はメッセージは表示せず、代わりにZインデックス番号を管理する必要があるため。
(2)第1回のリスト4にある「TextBlock1.Foreground = New SolidColorBrush(Colors.White)」という行を削除: 今回はTextBlockコントロールを使わないので。
Updateメソッドの処理(タッチ処理部分)
第1回でも説明したが、Leap Motionのタッチ処理について簡単に説明しておこう。
次の図に示すように、Leap Motionでは手前側が「ホバー状態(hovering)」、奥側が「タッチ状態(touching)」を表す。空間の範囲は前後「1」~「-1」となっている。
今回のサンプルでホバーの場合は、表示されている円の色をNavyにする。その際、タッチ・ポイントの位置をメンバー変数「x」と「y」に格納する。
画面に表示されている指の数をleap.Frame.Fingers.Countプロパティで取得して、メンバー変数「FingersCount」に格納しておく。
具体的には下記のコードのようになる。
For Each Pointable As Pointable In leap.Frame.Pointables
……コード略(前述)……
' ホバー状態のときの処理
If Pointable.TouchDistance > 0 AndAlso Pointable.TouchZone <> Global.Leap.Pointable.Zone.ZONENONE Then
touchIndicator.Color = Colors.Navy
' タッチ・ポイントの位置をメンバー変数「x」と「y」に格納する
x = touchPoint.X
y = touchPoint.Y
' 表示されている指の本数を取得して、メンバー変数FingersCountに格納しておく
FingersCount = leap.Frame.Fingers.Count
……コード略(続きは後述)……
End If
Next
|
次に、タッチした際の処理になる。タッチした場合は、表示されている円の色がRedに変わる。
それと同時に、タッチした各Imageコントロールの座標を取得して、どのImageがタッチされたかを判別する。タッチされたImageによって、メンバー変数「Index」に値を格納する。
Indexの値によって条件分岐を行う。例えばImage1がタッチされたときは、メンバー変数「Index」は「1」で初期化される。Indexが「1」のとき、Image1のSetValueメソッドで、画像のTopPropertyとLeftPropertyに、タッチ・ポイントのY座標とX座標を指定する。こうすることで、移動するタッチ・ポイントに追従して画像が移動する。選択した画像が前面に表示されるには、Canvas.ZIndexPropertyに1ずつ増加するメンバー変数「no」の値を指定する。こうすることで、選択された画像が前面に表示される。移動している画像の移動をやめるには、Redタッチ・ポイントをNavyまたは、それ以外(Gold)の色に変えればよい。
具体的には次のコードのようになる。
If Pointable.TouchDistance > 0 AndAlso Pointable.TouchZone <> Global.Leap.Pointable.Zone.ZONENONE Then
……コード略(前述)……
ElseIf Pointable.TouchDistance <= 0 Then
touchIndicator.Color = Colors.Red
' Image1の座標を取得し、メンバー変数「Index」を「1」で初期化する
If x > Image1.GetValue(Canvas.LeftProperty) And x < Image1.GetValue(Canvas.LeftProperty) + Image1.Width AndAlso y > Image1.GetValue(Canvas.TopProperty) And y < Image1.GetValue(Canvas.TopProperty) + Image1.Height Then
Index = 1
End If
' Image2の座標を取得し、メンバー変数「Index」を「2」で初期化する
If x > Image2.GetValue(Canvas.LeftProperty) And x < Image2.GetValue(Canvas.LeftProperty) + Image2.Width AndAlso y > Image2.GetValue(Canvas.TopProperty) And y < Image2.GetValue(Canvas.TopProperty) + Image2.Height Then
Index = 2
End If
' Image3の座標を取得し、メンバー変数「Index」を「3」で初期化する
If x > Image3.GetValue(Canvas.LeftProperty) And x < Image3.GetValue(Canvas.LeftProperty) + Image3.Width AndAlso y > Image3.GetValue(Canvas.TopProperty) And y < Image3.GetValue(Canvas.TopProperty) + Image3.Height Then
Index = 3
End If
' Image4の座標を取得し、メンバー変数「Index」を「4」で初期化する
If x > Image4.GetValue(Canvas.LeftProperty) And x < Image4.GetValue(Canvas.LeftProperty) + Image4.Width AndAlso y > Image4.GetValue(Canvas.TopProperty) And y < Image4.GetValue(Canvas.TopProperty) + Image4.Height Then
Index = 4
End If
' 画面上に表示されている指が1本の場合は、メンバー変数「Index」の値で条件分岐を行う。
' Indexの値で、各ImageのTopPropertyとLeftPropertyに、タッチ・ポイントのY/X座標を指定する。
' ZIndexPropertyにも1ずつ増加するメンバー変数「no」の値を指定する。これで、選択されたImageが前面に表示される。
If FingersCount = 1 Then
Select Case Index
Case 1
Image1.SetValue(TopProperty, touchPoint.Y)
Image1.SetValue(LeftProperty, touchPoint.X)
Image1.SetValue(Canvas.ZIndexProperty, no)
Exit Select
Case 2
Image2.SetValue(TopProperty, touchPoint.Y)
Image2.SetValue(LeftProperty, touchPoint.X)
Image2.SetValue(Canvas.ZIndexProperty, no)
Exit Select
Case 3
Image3.SetValue(TopProperty, touchPoint.Y)
Image3.SetValue(LeftProperty, touchPoint.X)
Image3.SetValue(Canvas.ZIndexProperty, no)
Exit Select
Case 4
Image4.SetValue(TopProperty, touchPoint.Y)
Image4.SetValue(LeftProperty, touchPoint.X)
Image4.SetValue(Canvas.ZIndexProperty, no)
Exit Select
Case Else
Exit Select
End Select
End If
no += 1
' タッチ対象外
Else
touchIndicator.Color = Colors.Gold
Image1.SetValue(Canvas.ZIndexProperty, 0)
Image2.SetValue(Canvas.ZIndexProperty, 0)
Image3.SetValue(Canvas.ZIndexProperty, 0)
Image4.SetValue(Canvas.ZIndexProperty, 0)
End If
|
なお、実際にこのサンプルを試す際に、Imageをうまく選択できない場合は、一度、Leap Motionの範囲から指を離して、再度トライするとうまくいく。
このサンプルのコードは、下記のリンク先よりダウンロードできる*1。
- *1サンプルをダウンロードして動かす場合は、「LeapCSharp.NET4.0.dll」や「LeapCSharp.dll」、「Leap.dll」を読者自身のフォルダー内にあるDLLファイルに指定し直さなければ動かない可能性があるので、動かない場合は再指定していただきたい。
■
今回はこれで終わりだ。第1回目もそうであったように、配置したオブジェクトの座標値さえ取得できれば、いろいろな処理を行える。しかし、この方法では、動的に作成したImageオブジェクトには使用できない。
次回は動的に作成したImageオブジェクトのイベント取得方法を解説する。
では、また次回の記事でお会いしよう。
- (※C++の連載記事「連載:C++で始めるLeap Motion開発 ―― タッチUIの先のカタチ ――」はこちら。「連載:Leap Motion開発入門(C#編)」はこちら)
- (※C#の記事「特集:コードで理解するLeapアプリ開発の概要 C#開発者から見たLeap Motion開発のファースト・インプレッション」はこちら)
※以下では、本稿の前後を合わせて5回分(第1回~第5回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
1. オブジェクト(Button)をLeap Motionでタッチして背景色を変化させる
Leap Motionの動くサンプルを実際に作ってみる連載スタート。今回はLeap Motionのタッチ操作で背景色を変化させるWPFアプリをVBで開発する。
2. 【現在、表示中】≫ Leap MotionによるWPFアプリ上のオブジェクトの移動
Leap Motionの動くサンプルを実際に作ってみる。今回はWPFの画面上に配置したオブジェクトを、Leap Motionによる操作で移動させるアプリを作成。
3. Leap Motionによる、WPFアプリ上に動的に作成したオブジェクトのイベント処理
Leap Motionの動くサンプルを実際に作ってみる。今回はWPFの画面上に動的に作成したオブジェクトを、Leap Motionによる操作でアニメーションさせるアプリを作成。
4. Leap Motionでパーティクルを使用して軌跡に無数の円や画像を表示する
さまざまな色の粒子(パーティクル)が、Leap Motionによる手の指の動きに合わせて飛び散りながら追従するサンプル・アプリを作ってみよう。
5. Leap MotionでBing Mapsを扱う
リスト内に表示された住所項目をLeap Motionによりタッチすることで、Web上のサービス「Bing Maps」での地図検索を行うサンプル・アプリを作ってみよう。