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

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

次に3匹の亀の中から任意の亀を選択して移動させる、「選択した亀を移動させる」の作成方法です。

選択した亀を移動する

まず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で作成すると安心でしょう)。[名前]欄には、ここでは「kamesMoveLeapMotion」と指定します。

ソリューション・エクスプローラー内にImagesというフォルダを作成して、3匹の亀の、上向き、下向き、右向き、左向きの、4枚の亀のpng画像(合計12枚の画像)を配置しています。

ダウンロードされたサンプルファイルには、これらの画像ファイルは追加済みです。

WPFの基本的な作成手順は、「第1回.5本の指によるオブジェクトの拡大・縮小」と同じ手順となるので、説明を割愛します。具体的な手順は、第1回の「参照の追加」「プロジェクトのルートに「LeapCSharp.dll」と「Leapd.dll」を追加する」「プロパティを設定する」を参考にしてください。

今回のLeap Motionアプリについて

今回のアプリは、5本の指で、画面を空中で上下、左右に動かすと、3匹の亀の中から選択された1匹の亀が現れて、手の動きに合わせて向きを変えて移動するアプリです(図2参照)。亀を選択する場合は必ず1本の指で選択する必要があります。タッチ・ポイントが亀の上に移ると、その亀が選択されますが、1本以外の2本の指が表示されている場合は選択できませんので、注意してください。

図2:TYPESWIPEで5本の指の動きに合わせて選択された亀が向きを変えて移動する(クリックで拡大)

実際に動かした動画は次のようになります。

画面のレイアウト(MainWindow.xaml)

最初に、Image1からImage3と言う名前のImageコントロールを3個配置します。SourceにkameSource1からkameSource3をバインディング、Canvas.LeftにkameLeft1
からkameLeft3をバインディング、Canvas.TopにkameTop1からkameTop3をバインディング、Canvas.RightにkameRight1からkameRight3をバインディング、Canvas.BottomにkameBottom1からkameBottom3をバインディングします。バインディングする名称は、後ほど作成する「kamesUpDownRightLeftModel.vb 」クラス内で定義するプロパティ名です。

次にBorderコントロールを3つ配置し、名前にBorder1からBorder3とつけておきます。BorderThicknessに3を指定して枠線の幅を3とします。CornerRadiusに12を指定して4隅を丸めます。

これらのBorder1からBorder3の子要素として、名前がsourceImage1からsourceImage3という名前のImageを3個配置し、Sourceプロパティに、Imagesフォルダ内の、各右向きの亀の画像を指定しておきます。一番手前に、タッチ・ポイントを表示させるための、paintCanvasという名前のInkPresenterを配置します。(リスト7参照)

リスト7(MainWindow.xaml.vb)

<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" 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>

レイアウトは図3のようになります。

図3:各コントロールをレイアウトした(クリックで拡大)

モジュールの作成

VS2012のメニューから[プロジェクト]−[モジュールの追加]と選択します。[名前]にはModule1.vbとしておきます。コードはリスト8のようになります。

リスト8(Module.vb)

3つの亀のうち、どの亀が選択されたかの判別に使用するPublic変数Indexを宣言しておきます。

Module Module1
  Public Index As Integer
End Module

クラスの作成(SwipeDirection.vb)

先のサンプルと全く同じなので割愛します。

クラスの作成(LeapListener.vb)

先のサンプルと全く同じなので割愛します。

クラスの作成(kamesUpDownRightLeftModel.vb)

先のサンプルとほとんど同じですが、亀を移動する距離を先のサンプルでは5を指定していましたが、今回は15という数値を指定しています。

プロパティの宣言が増えているのと、選択された亀の判別をIndexで行い、読み込む亀の種類を決定しています。Indexの値はMainWindow.xaml(後述)で取得します。

詳細は、サンプルをダウンロードしてコードをご覧ください。

プロパティ宣言のコードはリスト9です。

・・・コード略・・・

リスト9 プロパティの宣言(kamesUpDownRightLeftModel.vb)

' --------------------------Image1--------------------------
Private myTop1 As Double

  Public Property kameTop1 As Double
    Get
      Return myTop1
    End Get
    Set(value As Double)
      myTop1 = value
      OnPropertyChanged("kameTop1")
    End Set
  End Property
 
  Private myLeft1 As Double
 
  Public Property kameLeft1 As Double
    Get
      Return myLeft1
    End Get
    Set(value As Double)
      myLeft1 = value
      OnPropertyChanged("kameLeft1")
    End Set
  End Property
 
  Private myRight1 As Double
 
  Public Property kameRight1 As Double
    Get
      Return myRight1
    End Get
    Set(value As Double)
      myRight1 = value
      OnPropertyChanged("kameRight1")
    End Set
  End Property
 
  Private mykameSource1 As BitmapImage
 
  Public Property kameSource1 As BitmapImage
    Get
      Return mykameSource1
    End Get
    Set(value As BitmapImage)
      mykameSource1 = value
      OnPropertyChanged("kameSource1")
    End Set
  End Property
 
 ' ----------------Image2--------------------------
  Private myTop2 As Double
 
  Public Property kameTop2 As Double
    Get
      Return myTop2
    End Get
    Set(value As Double)
      myTop2 = value
      OnPropertyChanged("kameTop2")
    End Set
  End Property
 
  Private myLeft2 As Double
 
  Public Property kameLeft2 As Double
    Get
      Return myLeft2
    End Get
    Set(value As Double)
      myLeft2 = value
      OnPropertyChanged("kameLeft2")
    End Set
  End Property
 
  Private myRight2 As Double
 
  Public Property kameRight2 As Double
    Get
      Return myRight2
    End Get
    Set(value As Double)
      myRight2 = value
      OnPropertyChanged("kameRight2")
    End Set
  End Property
 
  Private mykameSource2 As BitmapImage
 
  Public Property kameSource2 As BitmapImage
    Get
      Return mykameSource2
    End Get
    Set(value As BitmapImage)
      mykameSource2 = value
      OnPropertyChanged("kameSource2")
    End Set
  End Property

 ' --------------------Image3------------------------------------
  Private myTop3 As Double
 
  Public Property kameTop3 As Double
    Get
      Return myTop3
    End Get
    Set(value As Double)
      myTop3 = value
      OnPropertyChanged("kameTop3")
    End Set
  End Property
 
  Private myLeft3 As Double
 
  Public Property kameLeft3 As Double
    Get
      Return myLeft3
    End Get
    Set(value As Double)
      myLeft3 = value
      OnPropertyChanged("kameLeft3")
    End Set
  End Property
 
  Private myRight3 As Double
  
  Public Property kameRight3 As Double
    Get
      Return myRight3
    End Get
    Set(value As Double)
      myRight3 = value
      OnPropertyChanged("kameRight3")
    End Set
  End Property
 
  Private mykameSource3 As BitmapImage
 
  Public Property kameSource3 As BitmapImage
    Get
      Return mykameSource3
    End Get
    Set(value As BitmapImage)
      mykameSource3 = value
      OnPropertyChanged("kameSource3")
    End Set
  End Property
・・・コード略・・・
  • 画面上のキャラクターを手の動きに合わせて操作する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メルマガ会員のサービス内容を見る

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