Статьи

31 Дней Манго | День № 6: Движение

Эта статья является 6-м днем ​​в серии под названием « 31 день манго» .

Сегодня мы собираемся взять всю информацию, которую мы узнали за последние два дня, и упростить управление с помощью класса Motion. Класс Motion представляет собой комбинацию данных, которые мы получаем от акселерометра, компаса и гироскопа на Windows Phone.

Подача, рыскание и крен

ПОДАЧА YAW РУЛОН

Как вы можете видеть из приведенных выше анимированных изображений, высота, рыскание и крен являются тремя важными данными в авиации, но они также применимы и к нашим устройствам Windows Phone. Когда мы посмотрели на акселерометр и гироскоп, мы смогли собрать данные об устройстве по конкретным осям: X, Y и Z. Шаг, рыскание и крен фактически представляют вращение вокруг тех же осей. Это делается с помощью математики, которую класс Motion фактически выполняет для нас автоматически. (Для получения дополнительной информации об основных осях самолетов, посмотрите Википедию .)

Использование класса Motion

В наших предыдущих примерах Гироскопа и Компаса мы должны были обнаружить датчики на устройстве пользователя, прежде чем продолжить. Нам не нужно делать отдельные проверки при использовании класса Motion, но нам нужно убедиться, что само Motion поддерживается.

Прежде чем мы углубимся в конкретный код для класса Motion, мы должны придумать привлекательный интерфейс. Для нашего примера мы собираемся разместить звезду XAML на нашем экране, как показано на рисунке ниже:

образ

Используя значение Yaw из класса Motion, мы сможем управлять ориентацией звезды. Когда пользователь поворачивает свой телефон, звезда фактически остается неподвижной по отношению к пользователю. Вот краткая видео-иллюстрация этого эффекта на работе:

Вот XAML, который нам нужен для реализации этого пользовательского интерфейса:

<phone:PhoneApplicationPage
   x:Class="Day6_Motion.MainPage"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
   xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:es="clr-namespace:Microsoft.Expression.Shapes;assembly=Microsoft.Expression.Drawing"
   mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
   FontFamily="{StaticResource PhoneFontFamilyNormal}"
   FontSize="{StaticResource PhoneFontSizeNormal}"
   Foreground="{StaticResource PhoneForegroundBrush}"
   SupportedOrientations="Portrait" Orientation="Portrait"
   shell:SystemTray.IsVisible="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="31 DAYS OF MANGO" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="motion" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <es:RegularPolygon x:Name="Star" InnerRadius="0.47211" Margin="100,175,100,175" PointCount="5" Stretch="Fill" Stroke="White" UseLayoutRounding="False" StrokeThickness="6">
                <es:RegularPolygon.Fill>
                    <SolidColorBrush Color="{StaticResource PhoneAccentColor}"/>
                </es:RegularPolygon.Fill>
                <es:RegularPolygon.RenderTransform>
                    <RotateTransform CenterX="100" CenterY="128"></RotateTransform>
                </es:RegularPolygon.RenderTransform>
            </es:RegularPolygon>

            <TextBlock x:Name="yawValue" Text="YAW = 34.567" FontSize="40" Width="400" Height="100" TextAlignment="Center" Margin="28,503,28,4" />
        </Grid>
    </Grid>
</phone:PhoneApplicationPage> 

 

Вы должны заметить, что наша звезда создана с использованием новой сборки, специфичной для Expression Blend. Однако нам не нужно использовать Blend, чтобы использовать содержащиеся в нем элементы управления. Вам нужно будет добавить ссылку на сборку Microsoft.Expression.Drawing, а также сделать ссылку на пространство имен XML вверху страницы XAML. Если вы не играли с ним раньше, попробуйте изменить свойство PointCount элемента RegularPolygon. Вы можете создавать звезды с таким количеством точек, сколько захотите (хотя вы не заметите большой разницы после 60-го.)

Вы также можете увидеть два других изменения, которые я внес в звезду. Первый — это цвет заливки. Я на самом деле определил SolidColorBrush, который будет использовать выбранный цвет темы пользователя. Это было рассмотрено в День 5 из 31 Дня Windows Phone , поэтому обязательно прочитайте его, если хотите использовать это в своем приложении.

Чтобы начать заставлять звезду двигаться, мы будем использовать концепции, очень похожие на те, которые мы использовали на отдельных датчиках. Во-первых, мы делаем обнаружение движения:

using System;
using System.Windows.Media;
using Microsoft.Phone.Controls;
using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;

namespace Day6_Motion
{
    public partial class MainPage : PhoneApplicationPage
    {
        public MainPage()
        {
            InitializeComponent();

            if (Motion.IsSupported)
            {
                //DO SOMETHING
            }
        }
    }
} 

 

В нашем комментарии «Делать что-то» нам нужно инициализировать наш объект Motion и создать обработчик событий для прослушивания данных, которые будут созданы.

using System;
using System.Windows.Media;
using Microsoft.Phone.Controls;
using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;

namespace Day6_Motion
{
    public partial class MainPage : PhoneApplicationPage
    {
        Motion motion;
        
        public MainPage()
        {
            InitializeComponent();

            if (Motion.IsSupported)
            {
                motion = new Motion();
                motion.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
                motion.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<MotionReading>>(motion_CurrentValueChanged);
                motion.Start();
            }
        }

        void motion_CurrentValueChanged(object sender, SensorReadingEventArgs<MotionReading> e)
        {
            //MAKE THIS THREAD SAFE.
        }
    }
} 

 

Наконец, нам нужно убедиться, что мы практикуем некоторую безопасность потоков. Мы не можем прочитать данные датчика из потока пользовательского интерфейса, поэтому нам нужно передать эту обработку в отдельный поток, используя метод Dispatcher.BeginInvoke (). Вы увидите, что добавлено ниже, вместе с нашей математикой, чтобы манипулировать звездой. Приведенный ниже код должен быть единственной версией приложения, которую вам действительно нужно скопировать и вставить в свою. 

using System;
using System.Windows.Media;
using Microsoft.Phone.Controls;
using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;

namespace Day6_Motion
{
    public partial class MainPage : PhoneApplicationPage
    {
        Motion motion;
        
        public MainPage()
        {
            InitializeComponent();

            if (Motion.IsSupported)
            {
                motion = new Motion();
                motion.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
                motion.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<MotionReading>>(motion_CurrentValueChanged);
                motion.Start();
            }
        }

        void motion_CurrentValueChanged(object sender, SensorReadingEventArgs<MotionReading> e)
        {
            Dispatcher.BeginInvoke(() => UpdateUI(e.SensorReading));
        }

        private void UpdateUI(MotionReading e)
        {
            ((RotateTransform)Star.RenderTransform).Angle = MathHelper.ToDegrees(e.Attitude.Yaw);
            yawValue.Text = "YAW = " + e.Attitude.Yaw.ToString();
        }
    }
} 

 

Вы можете видеть, что мы применяем наше значение Yaw к углу RotateTransform нашей звезды, заставляя его вращаться, когда датчики обнаруживают движение телефона. Сделайте снимок на устройстве (при условии, что оно у вас есть), и вы, вероятно, заметите существенную разницу в поведении между телефоном с гироскопом и телефоном без него. Как я упоминал вчера, гироскоп обеспечивает гораздо более плавную и точную подачу данных, и, как таковая, звезда движется с грацией, когда присутствует гироскоп.

Что значит у тебя нет телефона?

Я не предлагаю, чтобы вы выбежали сегодня и купили его (хотя вы, конечно, можете это сделать). Если вы живете на Среднем Западе Соединенных Штатов, отправьте мне письмо . У меня есть телефоны, которые я могу одолжить на 10 дней. Если вы там не живете, напишите мне в любом случае, и я смогу связать вас с евангелистом разработчика в вашем регионе. У всех нас есть несколько телефонов, которые можно взять в долг.

Некоторые другие интересные данные …

В приведенном выше примере кода я действительно использовал только данные Yaw из класса Motion. Однако я хочу убедиться, что вы знаете все значения, доступные вам из класса Motion. В загружаемом решении для Windows Phone ниже я также включил переменные, чтобы получить все доступные данные из класса Motion. Вот как это выглядит:

float pitch = e.Attitude.Pitch;
float yaw = e.Attitude.Yaw;
float roll = e.Attitude.Roll;

float accelerometerX = e.DeviceAcceleration.X;
float accelerometerY = e.DeviceAcceleration.Y;
float accelerometerZ = e.DeviceAcceleration.Z;

float gyroscopeX = e.DeviceRotationRate.X;
float gyroscopeY = e.DeviceRotationRate.Y;
float gyroscopeZ = e.DeviceRotationRate.Z;

float gravityX = e.Gravity.X;
float gravityY = e.Gravity.Y;
float gravityZ = e.Gravity.Z;

DateTimeOffset timestamp = e.Timestamp; 

 

Вы можете видеть, что у нас все еще есть доступ к данным от отдельных датчиков, а также к значению TimeStamp, так что мы точно знаем, когда произошли данные.

Резюме

Так что это класс Motion. Это должен быть основной способ взаимодействия с гироскопом, компасом и акселерометром, и он должен значительно облегчить вам математику и обработку. Для тех из вас, кто пытается найти интересный способ использования этих данных, вот отличный пример:

Одно из замечательных применений акселерометра, которое я видел, было в велосипедном приложении. Основной задачей приложения было отслеживать, где пользователь катается на велосипеде. В качестве функции безопасности вы можете ввести номер телефона экстренной службы. Если приложение распознает неудобно быструю остановку с последующим небольшим движением, оно автоматически отправит экстренный номер телефона с GPS-координатами устройства. После этого телефон будет звонить по номеру 911. Это удивительное использование данных о местоположении и акселерометре, которые в конечном итоге помогут обеспечить безопасность велосипедистов. Ваше приложение может использовать это тоже.

Если вы хотите загрузить решение для кода, которое мы создали в этой статье, нажмите кнопку Загрузить код ниже:

скачать

Завтра мы перейдем к другому полезному API: камере. Теперь у нас есть возможность собирать необработанные данные, которые захватывает телефон, и мы поговорим о том, как мы их получаем и для чего мы можем их использовать. Увидимся позже!

toolsbutton

Источник: http://www.jeffblankenburg.com/2011/11/06/31-days-of-mango-day-6-motion