Interactive Help screen

The sensors can be used not only in the native part of the game, but also in the managed one. As an example, you will modify the Help screen to present a movement of the device, by drawing an interactive picture representing the device and arrows indicating a direction in which the rocket should be moved, as shown in the following screenshot:

Interactive Help screen

HelpPage.xaml

The interactive picture will be placed inside the StackPanel layout control in the Steering group, in HelpPage.xaml file. It is represented by the following XAML code:

<Grid Margin="0 10 0 0">
  <Grid.RowDefinitions> (...) </Grid.RowDefinitions>
  <Grid.ColumnDefinitions> (...) </Grid.ColumnDefinitions>
  <Polygon Grid.Row="0" Grid.Column="1"
    Points="10,40 10,20 0,20 15,0 30,20 20,20 20,40"
    Fill="{Binding BrushUp}" />
  <Polygon Grid.Row="2" Grid.Column="1"
    Points="10,0 20,0 20,20 30,20 15,40 0,20 10,20"
    Fill="{Binding BrushDown}" /> (...)
  <Rectangle Grid.Row="1" Grid.Column="1" Height="80"
    Stroke="{StaticResource SA3DDarkBrush}"
    Fill="{StaticResource SA3DLightBrush}"
    StrokeThickness="2" />
  <Rectangle Grid.Row="1" Grid.Column="1" Height="60"
    Fill="White" Stroke="{StaticResource SA3DDarkBrush}"
    StrokeThickness="2" Margin="10 10 20 10" />
</Grid>

The Grid control contains three rows and three columns. The first and last row have height equal to 50 pixels, and the middle row fills the remaining space. Similar scenario is used in case of columns. The first and last column have width equal to 50 pixels, and the middle column fills the remaining space between other columns.

The most interesting part of this code is related to the Polygon elements. The Polygon is a control that draws an object by specifying a set of point coordinates. Each coordinate is separated by a comma, and each pair by a space. The first Polygon control makes it possible to draw an arrow representing the upward direction. It uses seven points, including (10,40) and (20,40). Their graphical representation is shown in the following figure. It is worth mentioning that the Polygon forms a closed line, that is, the last point is automatically connected with the first one. Each Polygon control has the Fill attribute that is bound to some property (for example, BrushDown). You will define it later in the view model class.

HelpPage.xaml

Apart from the Polygon controls (representing up, down, left, and right directions), two Rectangle elements are added into the Grid. The first one presents a mobile phone, while the other provides a screen of the device. They are placed in the middle row and in the middle column. Their arrangement is specified by suitable margins.

To present arrows in a proper way, you should create a style that is automatically applied to all Polygon controls. It sets a vertical and horizontal alignment (to center), as well as a stroke color (to the SA3DDarkBrush resource) and thickness (to 2).

HelpPage.xaml.cs

Additional modifications are necessary in the code-behind file. Here, you need to override the OnNavigatedTo and OnNavigatedFrom methods.

At the end of the OnNavigatedTo method, you should call the method with the same name, but from the HelpViewModel class. It will be used to perform some additional operations when the user navigates to the page. The code is as follows:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
  base.OnNavigatedTo(e);
  this.m_viewModel.NavigationService = this.NavigationService;
  this.m_viewModel.OnNavigatedTo(e);
}

In a similar way, you handle a situation when the user navigates from the page. Thus, in the OnNavigatedFrom method you call the suitable method from the view model class, as shown as follows:

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
  base.OnNavigatedFrom(e);
  this.m_viewModel.OnNavigatedFrom(e);
}

HelpViewModel.cs

The remaining modifications are required in the HelpViewModel class.

First of all, you define four properties representing brushes used by the data binding mechanism. They are named BrushUp, BrushDown, BrushLeft, and BrushRight. All of them are instances of SolidColorBrush (from System.Windows.Media namespace). In the following code, only the first property is shown, however, others can be added in a very similar way:

public SolidColorBrush m_brushUp =
  new SolidColorBrush(Colors.Transparent);
public SolidColorBrush BrushUp
{
  get { return this.m_brushUp; }
  set
  {
    this.m_brushUp = value;
    this.OnPropertyChanged("BrushUp");
  }
}

Now, you create the private field representing the accelerometer, which is an instance of the Accelerometer class from the Microsoft.Devices.Sensors namespace:

private Accelerometer m_accelerometer;

Inside the OnNavigatedTo method, you perform operations required before obtaining data from the sensor, as shown in the following block:

public void OnNavigatedTo(NavigationEventArgs e)
{
  if (Accelerometer.IsSupported)
  {
    try
    {
      this.m_accelerometer = new Accelerometer();
      this.m_accelerometer.CurrentValueChanged +=
        this.Accelerometer_CurrentValueChanged;
      this.m_accelerometer.Start();
    }
    catch (Exception) { this.m_accelerometer = null; }
  }
}

At the beginning, you check whether the accelerometer is supported in your device, by reading a value of the IsSupported property. Then, a new instance of the Accelerometer class is created. The next step is related to the CurrentValueChanged event, which you subscribe to obtain up-to-date information from the sensor. You use the additional method (Accelerometer_CurrentValueChanged) that is called every time when data read from accelerometer have been changed. At the end, you start using the accelerometer, by calling the Start method. In case of any exception during accelerometer initialization, you disable its further use by assigning a null value to the m_accelerometer field.

As soon as the accelerometer is no longer required, you should stop it. It can be done in the OnNavigatedFrom method, which is called when the user changes the page, for example, returns to the main menu. The suitable part of code is as follows:

public void OnNavigatedFrom(NavigationEventArgs e)
{
  if (this.m_accelerometer != null)
  {
    this.m_accelerometer.Stop();
    this.m_accelerometer = null;
  }
}

The Accelerometer_CurrentValueChanged is a method that should update values of properties (for example, BrushUp) that are taking part in the data binding:

private void Accelerometer_CurrentValueChanged(object sender,
  SensorReadingEventArgs<AccelerometerReading> e)
{
  float x = e.SensorReading.Acceleration.X;
  float y = e.SensorReading.Acceleration.Y;
  float z = e.SensorReading.Acceleration.Z;
  Color mainColor = new Color() { R = 175, G = 40, B = 0 };
  Color upColor = mainColor;   
  Color downColor = mainColor;
  Color leftColor = mainColor; 
  Color rightColor = mainColor;
  upColor.A = (byte)(255 * Math.Max(x, 0));
  downColor.A = (byte)(255 * Math.Abs(Math.Min(x, 0)));
  leftColor.A = (byte)(255 * Math.Max(y, 0));
  rightColor.A = (byte)(255 * Math.Abs(Math.Min(y, 0)));
  Deployment.Current.Dispatcher.BeginInvoke(() =>
  {
    this.BrushUp = new SolidColorBrush(upColor);
    this.BrushDown = new SolidColorBrush(downColor);
    this.BrushLeft = new SolidColorBrush(leftColor);
    this.BrushRight = new SolidColorBrush(rightColor);
  });
}

At the beginning, you use the second parameter of this method (named e) to get suitable values and store them as x, y, and z local variables. Next, you choose a color (mainColor) that is used as a fill color for an arrow when the accelerometer data have the maximum available value in particular direction. Then, you copy data of this color into four separate variables representing colors of all arrows (upColor, downColor, leftColor, and rightColor).

Note

The Color is a structure. Therefore, assignment of its instance to other variable causes copying field values, instead of copying only a reference to the instance.

In the following part, some simple calculations are made to set a suitable alpha values for colors. They should be in range <0;255>. The lowest value indicates that the color is not shown. To calculate alpha values for all arrows, the following formulas are applied:

up = 255 * max(x,0)
down = 255 * |min(x,0)|
left = 255 * max(y,0)
right = 255 * |min(y,0)|

All calculated values are in range <0;255>, because the second part of each formula returns a value not smaller than 0 and not higher than 1.

The remaining part of the Accelerometer_CurrentValueChanged method just updates values of properties. What is more, due to performing operation from a different thread, it is required to use the BeginInvoke method on the Dispatcher property (using the Deployment class from the System.Windows namespace). It specifies operations, which should be performed, by taking a lambda expression as a parameter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.82.21