加速度センサーやジャイロスコープセンサーを使った、3つのセンサーサンプル
複合モーションを使った、針を回転させるサンプル
3つ目は、複合モーションを使ったサンプルです。「複合モーション」は、「複合モーションセンサー」という1個のセンサーが用意されているのではなく、加速度センサー、ジャイロスコープセンサー、コンパスセンサーにより取得可能なデータを連携して扱える複合APIです。
ここでは、デバイスの姿勢を表すAttitudeプロパティの値を取得して、視覚的に表示してみます(図5)。
今回紹介しているのは、Silverlightアプリですが、複合モーションを使うメリットは、Quaternionなどの値を利用する、.Xna Frameworkによるゲームに顕著です。
図5:複合モーションで取得されたデータを角度に変換して、針の画像を回転させる(クリックで拡大) |
プロジェクトの作成
VS 2010のメニューから[ファイル(F)/新規作成(N)/プロジェクト(P)]「Windows Phone アプリケーション」を選択して、「MotionSample」プロジェクトを作成します。Windows Phoneのバージョンは7.1です。
Imageという名前のフォルダを作って、4枚のPNG画像を追加しておきます。ダウンロードされたサンプルファイルには画像ファイルは追加済みです。
MainPage.xamlの編集とコントロールの追加
ツールボックスからButtonコントロールを1個、TextBlockコントロールを7個配置します。また、Imageコントロールを4個配置して、画像を参照しておきます。
XAMLコードは、リスト5のように編集します。
リスト5 編集されたXAMLコード(MainPage.xaml)
前掲のリスト1同様、Image要素の中に、Image.Projection要素を追加します。さらに、その子として、PlaneProjection要素を追加します。
~前略~ <!--LayoutRoot は、すべてのページ コンテンツが配置されるルート グリッドです--> <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!--TitlePanel contains the name of the application and page title--> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock x:Name="ApplicationTitle" Text="複合モーション" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBlock x:Name="PageTitle" Text="針の回転表示" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> </StackPanel> <!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="0,0,0,0"> <Button Content="開始" Height="80" HorizontalAlignment="Left" Margin="140,0,0,0" Name="Button1" VerticalAlignment="Top" Width="200" /> <!--●計測結果(Attitude ラジアンと角度)--> <!--Pitch--> <TextBlock Height="48" HorizontalAlignment="Left" Margin="80,80,0,0" Name="PitchRad" Text="Pitch" VerticalAlignment="Top" Width="150" FontSize="30" /> <TextBlock Height="48" HorizontalAlignment="Left" Margin="200,80,0,0" Name="PitchAngle" Text="(Angle)" VerticalAlignment="Top" Width="150" FontSize="30" Foreground="DeepSkyBlue" TextAlignment="Right" /> <Line x:Name="Line1" X1="0" Y1="130" X2="480" Y2="130" Stroke="#FFDDDDDD" StrokeThickness="1"></Line> <!--Roll--> <TextBlock Height="48" HorizontalAlignment="Left" Margin="80,130,0,0" Name="RollRad" Text="Roll" VerticalAlignment="Top" Width="150" FontSize="30" /> <TextBlock Height="48" HorizontalAlignment="Left" Margin="200,130,0,0" Name="RollAngle" Text="(Angle)" VerticalAlignment="Top" Width="150" FontSize="30" Foreground="Orange" TextAlignment="Right" /> <Line x:Name="Line2" X1="0" Y1="180" X2="480" Y2="180" Stroke="#FFDDDDDD" StrokeThickness="1"></Line> <!--Yaw--> <TextBlock Height="48" HorizontalAlignment="Left" Margin="80,180,0,0" Name="YawRad" Text="Yaw" VerticalAlignment="Top" Width="150" FontSize="30" /> <TextBlock Height="48" HorizontalAlignment="Left" Margin="200,180,0,0" Name="YawAngle" Text="(Angle)" VerticalAlignment="Top" Width="150" FontSize="30" Foreground="LimeGreen" TextAlignment="Right" /> <Line x:Name="Line3" X1="0" Y1="230" X2="480" Y2="230" Stroke="#FFDDDDDD" StrokeThickness="1"></Line> <!--針の表示--> <Image Height="332" HorizontalAlignment="Left" Margin="70,240,0,0" Name="Image1" Stretch="Fill" VerticalAlignment="Top" Width="332" Source="/MotionSample;component/Image/AngleImage.png" /> <Image Height="332" HorizontalAlignment="Left" Margin="70,240,0,0" Name="YawHand" Stretch="Fill" VerticalAlignment="Top" Width="332" Source="/MotionSample;component/Image/YawHand.png"> <Image.Projection> <PlaneProjection x:Name="MyYawHandProjection" /> </Image.Projection> </Image> <Image Height="332" HorizontalAlignment="Left" Margin="70,240,0,0" Name="RollHand" Stretch="Fill" VerticalAlignment="Top" Width="332" Source="/MotionSample;component/Image/RollHand.png"> <Image.Projection> <PlaneProjection x:Name="MyRollHandProjection" /> </Image.Projection> </Image> <Image Height="332" HorizontalAlignment="Left" Margin="70,240,0,0" Name="PitchHand" Stretch="Fill" VerticalAlignment="Top" Width="332" Source="/MotionSample;component/Image/PitchHand.png"> <Image.Projection> <PlaneProjection x:Name="MyPitchHandProjection" /> </Image.Projection> </Image> <TextBlock Height="30" HorizontalAlignment="Left" Margin="15,570,0,0" Name="TextBlock1" Text="センサーの状態" VerticalAlignment="Top" Width="450" FontSize="24" /> </Grid> </Grid> <!--ApplicationBar の使用法を示すサンプル コード--> ~後略~
リスト6 ロジックコード(MainPage.xaml.vb)
名前空間のインポートと変数の宣言
Microsoft.Devices.Sensors名前空間と、Xna.Framework名前空間もインポートしておきます。
複合モーションのセンサーオブジェクトと、計測間隔、X軸の回転・ピッチ(ピッチング)、Y軸の回転・ロール(ローリング)、Z軸の回転・ヨー(ヨーイング)の生データおよび角度データを代入する変数を宣言します。
Option Strict On Imports Microsoft.Devices.Sensors Imports Microsoft.Xna.Framework Partial Public Class MainPage Inherits PhoneApplicationPage ' Constructor Public Sub New() InitializeComponent() End Sub Dim MyMotion As Motion '複合モーションのセンサー Dim MyTimeSpan As Integer = 300 '計測間隔。 Dim MyPitch, MyRoll, MyYaw As Single 'Pitch、Roll、Yaw の生データ(rad) Dim MyAttitudeX, MyAttitudeY, MyAttitudeZ As Single 'デバイスの角度データ
このページがロードされた時の処理
デバイスがセンサーをサポートしているかどうかをチェックして、サポートしていなければ、メッセージを表示します。
Private Sub MainPage_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded '複合モーションがサポートされていない機種への対応 If Motion.IsSupported = False Then MessageBox.Show("このデバイスは複合モーションをサポートしていません。") Button1.IsEnabled = False Exit Sub Else Button1.IsEnabled = True End If End Sub
ボタンがタップされた時の処理
このサンプルでは、1個のボタンをタップする都度、センシングの開始と停止を切り替えます。センサーオブジェクトが有効であれば、センサーを停止し、ボタンの文字列を「開始」にします。
一方、センサーオブジェクトが空であれば、複合モーションの新しいインスタンスを作成して、ボタンの文字列を「停止」にしたうえで、センシングを実行します。
Private Sub Button1_Tap(sender As Object, e As System.Windows.Input.GestureEventArgs) Handles Button1.Tap If MyMotion IsNot Nothing AndAlso MyMotion.IsDataValid Then Try MyMotion.Stop() MyMotion = Nothing TextBlock1.Text = "実行中の複合モーションを停止しました。" Button1.Content = "開始" Catch MessageBox.Show("複合モーションの停止に失敗しました。") End Try Else If MyMotion Is Nothing Then MyMotion = New Motion MyMotion.TimeBetweenUpdates = TimeSpan.FromMilliseconds(MyTimeSpan) AddHandler MyMotion.CurrentValueChanged, Sub(senderValue As Object, eValue As SensorReadingEventArgs(Of MotionReading)) Deployment.Current.Dispatcher.BeginInvoke(Sub() CurrentValueChanged(eValue.SensorReading)) End Sub End If Try Button1.Content = "停止" TextBlock1.Text = "計測を開始しました。" MyMotion.Start() Catch MessageBox.Show("計測を開始できませんでした。") End Try End If End Sub
センサーデータが更新された時の処理
センサーデータが更新された時、ピッチ・ロール・ヨーの生データを取得し、これをMathHelper.ToDegreesで角度に変換します。
生データと角度データをTextBlock内に表示し、角度を指定して3軸の針の図形を時計回りに回転させます。
Private Sub CurrentValueChanged(MyReading As MotionReading) 'デバイスの姿勢 (ピッチ、ロール、ヨー) 'MotionReading 構造体 Attitude プロパティで取得される、Pitch、Roll、Yaw の値(rad) MyPitch = MyReading.Attitude.Pitch MyRoll = MyReading.Attitude.Roll MyYaw = MyReading.Attitude.Yaw 'デバイスの姿勢 (ピッチ、ロール、ヨー) を角度に変換 MyAttitudeX = MathHelper.ToDegrees(MyPitch) MyAttitudeY = MathHelper.ToDegrees(MyRoll) MyAttitudeZ = MathHelper.ToDegrees(MyYaw) 'ピッチ、ロール、ヨーのデータを表示 PitchRad.Text = CStr(MyPitch.ToString("F1")) RollRad.Text = CStr(MyRoll.ToString("F1")) YawRad.Text = CStr(MyYaw.ToString("F1")) 'ピッチ、ロール、ヨーの角度データを表示 PitchAngle.Text = CStr(MyAttitudeX.ToString("F1")) & "°" RollAngle.Text = CStr(MyAttitudeY.ToString("F1")) & "°" YawAngle.Text = CStr(MyAttitudeZ.ToString("F1")) & "°" 'もとめた角度を指定して、3軸それぞれの図形を時計回りに回転 MyPitchHandProjection.RotationZ = 360 - MyAttitudeX MyRollHandProjection.RotationZ = 360 - MyAttitudeY MyYawHandProjection.RotationZ = 360 - MyAttitudeZ End Sub End Class
このように、Windows Phone のセンサーにより取得したデータを利用すると、実機を傾けたり、振ったりした時に処理を実行するインタフェースを実現できます。
さて、今回の「Marketplaceのアプリから解説するWindows Phoneの実践サンプルコード集」で、Windows Phoneのサンプル解説は一応完結です。先日、Windows Phone 8が発表されましたが、リリースされたらぜひ試してみたいですね。
→参照:Windows Phone 8のスタート画面は「最高にエレガント」(ギズモード・ジャパン)
ここまで、いろいろなサンプルを紹介してきましたが、皆さまのWindows Phoneアプリ作成の一助になれば幸いです。皆さんもどしどしアプリを開発して、APP HUBより申請していただければと思います。
長い間お疲れさまでした。
APP HUB登録の一連の流れについては、下記リンクの記事も参照してください。
→参照:Windows Phoneアプリ制作からマーケットプレイス公開までを完全ガイド!
【参考リンク】
センサーを使ったアプリのサンプル