手の動きに合わせて画面上のキャラクターを操作するLeap Motionプログラムを作る

2013年11月7日(木)
薬師寺 国安

MainWindow.xaml内に[kamesUpDownRightLeftModel]を取り込む。

まず名前空間として「xmlns:local="clr-namespace:kamesMoveLeapMotion"」を定義します。

次にプロパティ要素内に「」と記述します。MainWindow.xaml内に「:kamesUpDownLeftRightModel」クラスが取り込まれる。リスト10のようになります。

リスト10 kamesUpDownLeftRightModelを取り込んだMainWindow.xaml

<Window x:Class="MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="clr-namespace:kamesMoveLeapMotion"
  Title="MainWindow" Height="1080" Width="1920" WindowState="Maximized">
  <Window.DataContext>
    <local:kamesUpDownLeftRightModel/>
  </Window.DataContext>
    <Canvas>
    <Image x:Name="Image1" Stretch="Uniform" Source="{Binding kameSource1}" Canvas.Left="{Binding kameLeft1}" Canvas.Top="{Binding kameTop1}" Canvas.Right="{Binding kameRight1}" />
    <Image x:Name="Image2" Stretch="Uniform" Source="{Binding kameSource2}" Canvas.Left="{Binding kameLeft2}" Canvas.Top="{Binding kameTop2}" Canvas.Right="{Binding kameRight2}" />
<Image x:Name="Image3" Stretch="Uniform" Source="{Binding kameSource3}" Canvas.Left="{Binding kameLeft3}" Canvas.Top="{Binding kameTop3}" Canvas.Right="{Binding kameRight3}" />
    
    <Border x:Name="Border1" BorderThickness="2" CornerRadius="12"  Canvas.Left="650" Canvas.Top="10">
      <Image x:Name="sourceImage1" Height="132" Canvas.Left="625" Canvas.Top="10" Width="202" Source="Images/kame_right.png"/>
    </Border>
    <Border x:Name="Border2" BorderThickness="2" CornerRadius="12"  Canvas.Left="915" Canvas.Top="10">
      <Image x:Name="sourceImage2" Height="146" Canvas.Left="906" Canvas.Top="10" Width="199" Source="Images/kame2_right.png" />
    </Border>
    <Border x:Name="Border3" BorderThickness="2" CornerRadius="12"  Canvas.Left="1151" Canvas.Top="10">
      <Image x:Name="sourceImage3" Height="146" Canvas.Left="1151" Canvas.Top="10" Width="190" Source="Images/kame3_right.png"/>
    </Border>
    <InkPresenter Name="paintCanvas"/>
  </Canvas>
</Window>

MainWindow.xaml.vbのプログラム・コード

第1回のMainWindow.xaml.vbとほとんど同じですので、異なる個所のみ解説します。

  1. デジタイザーとスタイラスから収集された単一のデータ・ポイントを表すStylusPoint構造体の「touchPointメンバー変数」「Private touchPoint As StylusPoint」を宣言する。
  2. 「Private windowWidth As Double = 1920」と「Private windowHeight As Double = 1080」メンバー変数を宣言する。
  3. タッチ・ポイントの座標を格納する「Private x As Integer」と「Private y As Integer」メンバー変数を宣言する。
  4. 変数「windowWidth」と「windowHeight」で表されたクライアント領域のウィンドウがある場合、このウィンドウ内のタッチ・ポイントの2D座標を得るための、「Private tx As Double」、「Private ty As Double」メンバー変数を宣言する。
  5. 表示する円の直径を20pxにする(MainWindow_Looaded内)

Updateメソッドの処理

第1回と同じなので割愛します。

Updateメソッドの処理(ホバー処理部分)

次にLeap Motionのタッチ処理になります。タッチのイメージは次の図4のようなイメージです。

手前側が「ホバー状態(hovering)」、奥側が「タッチ状態(touching)」を表します。空間の範囲は前後「1」~「-1」となっています。

図4:Leap Motionのタッチ検出イメージ(Leap Motion SDKのAPIドキュメントから引用)(クリックで拡大)

今回のサンプルでホバーの場合は、表示されている円の色をNavyにします。その際、タッチ・ポイントの位置をメンバー変数「x」と「y」に格納します。

画面に表示されている指の数をleap.Frame.Fingers.Countプロパティで取得して、メンバー変数「FingersCount」に格納しておきます。

具体的にはリスト11のようになります。

リスト11 ホバー時の処理(MainWindow.xaml.vb)

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

それと同時に、ホバーした各Imageコントロールの座標を取得して、どのImageがホバーされたかを判別します。ホバーされたImageによって、モジュール変数「Index」の値を初期化し、例えばImage1がホバーされた時は、Border1のBorderBrushの色を赤にします。Image2とImage3がホバーされた時も同じです。それ以外のImageのBorderBrushはWhiteとしておきます。ホバーされた亀の周囲に赤枠線が表示させます。

具体的には次のリスト12のようになる。

リスト12 ホバーしたImageの座標を取得し、モジュール変数「Index」の値を初期化し、そのIndexの値で条件分岐を行う(MainWindow.xaml.vb)

' ホバー
    If Pointable.TouchDistance > 0 AndAlso Pointable.TouchZone <> Global.Leap.Pointable.Zone.ZONENONE Then
      touchIndicator.Color = Colors.Navy
      x = touchPoint.X
      y = touchPoint.Y
 
      FingersCount = leap.Frame.Fingers.Count
 
      If FingersCount = 1 Then
' 表示されている3匹の亀の座標値を取得して、選択された亀の座標値によって、
' モジュール変数Indexの値を初期化する。
        If x > sourceImage1.GetValue(Canvas.LeftProperty) And x < sourceImage1.GetValue(Canvas.LeftProperty) + sourceImage1.Width AndAlso y > sourceImage1.GetValue(Canvas.TopProperty) And y < sourceImage1.GetValue(Canvas.TopProperty) + sourceImage1.Height Then
          Index = 1
          Border1.BorderBrush = New SolidColorBrush(Colors.Red)
          Border2.BorderBrush = New SolidColorBrush(Colors.White)
          Border3.BorderBrush = New SolidColorBrush(Colors.White)
        End If
 
        If x > sourceImage2.GetValue(Canvas.LeftProperty) And x < sourceImage2.GetValue(Canvas.LeftProperty) + sourceImage2.Width AndAlso y > sourceImage2.GetValue(Canvas.TopProperty) And y < sourceImage2.GetValue(Canvas.TopProperty) + sourceImage2.Height Then
          Index = 2
          Border1.BorderBrush = New SolidColorBrush(Colors.White)
          Border2.BorderBrush = New SolidColorBrush(Colors.Red)
          Border3.BorderBrush = New SolidColorBrush(Colors.White)
        End If
 
        If x > sourceImage3.GetValue(Canvas.LeftProperty) And x < sourceImage3.GetValue(Canvas.LeftProperty) + sourceImage3.Width AndAlso y > sourceImage3.GetValue(Canvas.TopProperty) And y < sourceImage3.GetValue(Canvas.TopProperty) + sourceImage3.Height Then
          Index = 3
          Border1.BorderBrush = New SolidColorBrush(Colors.White)
          Border2.BorderBrush = New SolidColorBrush(Colors.White)
          Border3.BorderBrush = New SolidColorBrush(Colors.Red)
        End If
 
      ElseIf Pointable.TouchDistance <= 0 Then
        touchIndicator.Color = Colors.Red
 
      End If
      'タッチ
    End If
  Next
End Sub

※注意
サンプルをダウンロードして動かす場合は、「LeapCSharp.NET4.0.dll」や「LeapCSharp.dll」、「Leap.dll」を読者自身のフォルダ内にあるDLLファイルに指定し直さなければ動かない可能性があるので、動かない場合は再指定してください。

  • 画面上のキャラクターを手の動きに合わせて操作するLeap Motionプログラム(1)

  • 手の動きに合わせて画面上のキャラクターを操作するLeap Motionプログラム(2)

薬師寺国安事務所

薬師寺国安事務所代表。Visual Basic プログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。
1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。1997年に薬師寺聖とコラボレーション・ユニット PROJECT KySS を結成。2003年よりフリーになり、PROJECT KySS の活動に本格的に参加、.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。Windows Phoneアプリ開発を経て、現在はWindows ストア アプリを多数公開中

Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。Microsoft MVP for Development Platforms-Windows Platform Development (Oct 2014-Sep 2015)。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています