📜 ⬆️ ⬇️

Windows Phone 8: Create an application. Matrix. Part 1

Windows Phone 8: Create an application. Matrix. Part 1
Windows Phone 8: Create an application. Matrix. Part 2
Windows Phone 8: Create an application. Matrix. Part 3. MVVM

Creating an application for a contest, there was also an idea to share the process of its creation, since I myself faced difficulties in finding information on creating applications for Windows Phone 8. Why is the “Matrix”? Because since the release of the movie she fascinated me. Then I found a screen saver on the screen. I could watch her for hours. And now I decided to transfer it to the phone, which would always be at hand. So, let's begin.


Print screen from Lumia 520 screen

About 2 years ago I already created something similar, but on jQuery. However, then everything turned out, except for usefulness: the maximum matrix size at which it did not “slow down” was approximately 15 X 20 cells, which is clearly not enough for modern FULL HD monitors. When figuring out the reasons for this behavior, I found out that it was only a load of 1 core and, as I understood then, it was only in 1 thread (I could be wrong, but I didn’t suit more about this topic of flight analysis). Yes, and created only in order to get comfortable in this JS framework. C # is devoid of these shortcomings, and the power of modern smartphones should be enough to handle a large number of elements and a lot of random numbers for each such element. Looking ahead, I will say that when testing on my weak Lumia 520, all my hopes were met.
')

First, let's define what we want to create.


  1. A grid of cells in which the coordinates of the snake start are randomly selected.
  2. Snakes will be of different random lengths.
  3. In each cell of the snake, the elements are randomly changed randomly.
  4. There is a color fading effect. The brightness of each component of the snake depends on its length.


What used to create the application



A few words about testing. On the emulator the results are not very plausible. When running a large number of snakes, he showed more FPS than on a real phone. When debugging on the phone - the phone slows down terribly. However, after stopping debugging and simply launching the application, performance was adequate.

Let's go to work in Visual Studio


Create a project: Templates - Visual C # - Windows Phone - Windows Phone Application.
Choose the .NET Framework 4.5.
My project name is SE_Matrix_2d_v_1. It will also be a namespace.
Choose Windows Phone OS 8.0.

MainPage.xaml

Now edit the XAML code. We will only need a Grid named LayoutRoot and a click event (Tap) Event_Grid_Tap_LayoutRoot, into which we dynamically, depending on the screen expansion, enter the necessary number of TextBlock cells. We look:

<phone:PhoneApplicationPage x:Class="SE_Matrix_2d_v_1.MainPage" x:Name="SE_Matrix_2d_v_1" 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" mc:Ignorable="d" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" shell:SystemTray.IsVisible="True"> <!--LayoutRoot   ,     --> <Grid x:Name="LayoutRoot" Background="Transparent" Tap="Event_Grid_Tap_LayoutRoot"> </Grid> </phone:PhoneApplicationPage> 

Run the emulator. Must be just a black screen.

MainPage.xaml.cs

Immediately connect the necessary libraries:
 using System.Windows.Media; //     using System.Threading.Tasks; //    using System.Diagnostics; //  . Debug.WriteLine( SomethingYouNeedToSee); 

In the constructor, we will call the CreateElement method, which will create a matrix of elements in which all further actions will take place:
  //  public MainPage() { InitializeComponent(); CreateElement(); } 

In order to create a matrix, you need to determine the expansion of the screen. Add the ScreenWidth and ScreenHeight properties to the MainPage class:
  public partial class MainPage : PhoneApplicationPage { //    double ScreenWidth = System.Windows.Application.Current.Host.Content.ActualWidth; double ScreenHeight = System.Windows.Application.Current.Host.Content.ActualHeight; ... 

Let's start creating the CreateElement method.
First of all, you need to determine the number of rows and columns in the matrix, which we will create:
  //     countWidth = (int)Math.Round(ScreenWidth / 50); countHeight = (int)Math.Round(ScreenHeight / 50); 

If you started learning C # after mastering other languages, it may be more understandable:
  //     countWidth = (int)Math.Round(this.ScreenWidth / 50); countHeight = (int)Math.Round(this.ScreenHeight / 50); 

So (using this) you unequivocally indicate that you need to refer specifically to the property of the class.
If this is not used, then a variable with the same name inside the method is first searched, and if it is not found, the search continues by the class properties.

Now, knowing the number of rows and columns, we create using the usual iteration (2 for loops) the necessary number of TextBlock elements with the necessary initial settings:
  //    for (i = 0; i < countWidth; i++) { for (j = 0; j < countHeight; j++) { //  TextBlock TextBlock element = new TextBlock(); //    TextBlock element.Name = "TB_" + i + "_" + j; //    //element.Text = char.ConvertFromUtf32(random.Next(0x4E00, 0x4FFF)); //      element.Text = ""; //  //      TextBlock int wx = i * 50; int wy = j * 50; element.Margin = new Thickness(wx, wy, 0, 0); //    element.Foreground = new SolidColorBrush(Colors.Green); //    element.FontSize = 36; //     Grid LayoutRoot.Children.Add(element); } } 

Margin is set so that they would not all be above each other.
The name of each TextBlock is formed with the participation of the X and Y coordinates to facilitate subsequent access to them and the ability to randomly set the coordinates of the beginning of the snake.

If you add the Border element to this method, you can visually assess the cell sizes and their location. We look:
 //   ,      public void CreateElement() { int i, j, countWidth, countHeight; //     countWidth = (int)Math.Round(this.ScreenWidth / 50); countHeight = (int)Math.Round(this.ScreenHeight / 50); //    for (i = 0; i < countWidth; i++) { for (j = 0; j < countHeight; j++) { //  TextBlock TextBlock element = new TextBlock(); //  Border Border elementBorder = new Border(); //    TextBlock elementBorder.Name = "B_" + i + "_" + j; //    TextBlock element.Name = "TB_" + i + "_" + j; //    //element.Text = char.ConvertFromUtf32(random.Next(0x4E00, 0x4FFF)); //      element.Text = ""; //  //      TextBlock int wx = i * 50; int wy = j * 50; element.Margin = new Thickness(wx, wy, 0, 0); //    element.Foreground = new SolidColorBrush(Colors.Green); //    element.FontSize = 36; //      Border elementBorder.Margin = new Thickness(wx, wy, 0, 0); //     elementBorder.BorderThickness = new Thickness(1); //    elementBorder.BorderBrush = new SolidColorBrush(Colors.Green); //  TextBlock  Border elementBorder.Child = element; //     Grid LayoutRoot.Children.Add(elementBorder); } } } 

In this case, we add the Border element (LayoutRoot.Children.Add (elementBorder);) to the Grid, since it would be necessary to wrap it in the Border tag to get the visible bounds of the desired element:
 <Border BorderThickness="1" BorderBrush="Black" Background="Green" CornerRadius="5"> <TextBlock Text="Description"/> </Border> 

Further we will continue work with the first option, without borders.

Now that there is a matrix, you can start creating snakes that will crumble. First, create a click event handler on the Grid element, which will simply call the Start method:
  //      Grid ( ) private void Event_Grid_Tap_LayoutRoot(object sender, System.Windows.Input.GestureEventArgs e) { Start(); } 

If in this handler call the Start method in a loop, then we get several simultaneous snakes. But this is a bit later.

The Start method determines the snake's initial settings, such as the X and Y coordinates of the snake start, the snake length, the speed of changing characters in each TextBlock cell. In a random way, the number of snakes after clicking on the screen in the queue:
  //    public async void Start() { int count, iteration; //         iteration = 1; count = 0; //         while (count < iteration) { //       int ranX = random.Next(0, 10); //       int ranY = random.Next(0, 20); //     int length = random.Next(3, 7); //          int time = random.Next(30, 70); await Task.Delay(1); //   await RandomElementQ_Async(ranX, ranY, length, time); count++; } } 

So we got to the “heart” of our application, the RandomElementQ_Async method. He is responsible for capturing the desired element, determining its color, creating the effect of falling and protecting it from creeping out of the snake beyond the boundaries of the matrix. And now in more detail:
 //  ,      public async Task RandomElementQ_Async(int x, int y, int length, int timeOut) { //     ,     . Dictionary<int, TextBlock> dicElem = new Dictionary<int, TextBlock>(); // ,    ,     if ((y + i) < countHeight && (y + i) >= 0).   4  . int count = 0; //      length for (int i = 0; i < length; i++) { //    ,        //     int countHeight = (int)Math.Round(ScreenHeight / 50); // ,       ,      if ((y + i) < countHeight) { //   ,      string elementName = "TB_" + x + "_" + (y + i); //      object wantedNode = LayoutRoot.FindName(elementName); TextBlock element = (TextBlock)wantedNode; //    ,        ""  ""  dicElem[count] = (element); //     .  ( ) -   ,  -  . //  1, ,        255   . int rf = (int)Math.Round(255 / (double)(i + 1)) - 1; //    ,    . . await Change(element, timeOut, 255); //   ,     .     ,     . for (int k = 0; k <= i; k++) { //    ""   (,  y = -5) if (dicElem.ContainsKey(k)) { // ,      .   ""  TextBlock previousElement = dicElem[k]; //    // (rf * (k + 1)) - 20   ,             //       ( ) Task dsvv = Change(previousElement, timeOut, (rf * (k + 1)) - 20); } } count++; } } } 

And the last simple method that changes the characters and their color in the desired cell the necessary number of times:
  //       public async Task Change(TextBlock txt, int timeOut, int Opacity) { //       SolidColorBrush NewColor = new SolidColorBrush(new Color() { A = (byte)(255) /*Opacity*/, R = (byte)(0) /*Red*/, G = (byte)(Opacity) /*Green*/, B = (byte)(0) /*Blue*/ }); //   ""  1   "" txt.Foreground = NewColor; //       for (int i = 0; i < 5; i++) { //     txt.Text = char.ConvertFromUtf32(random.Next(0x4E00, 0x4FFF)); //      await Task.Delay(timeOut); } } 


The working code of the file MainPage.xaml.cs
 using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Navigation; using Microsoft.Phone.Controls; using Microsoft.Phone.Shell; using System.Threading.Tasks; using System.Diagnostics; namespace SE_Matrix_2d_v_1 { public partial class MainPage : PhoneApplicationPage { //   Random random = new Random(); //    double ScreenWidth = System.Windows.Application.Current.Host.Content.ActualWidth; double ScreenHeight = System.Windows.Application.Current.Host.Content.ActualHeight; //  public MainPage() { InitializeComponent(); CreateElement(); } //   ,      public void CreateElement() { int i, j, countWidth, countHeight; //     countWidth = (int)Math.Round(this.ScreenWidth / 50); countHeight = (int)Math.Round(this.ScreenHeight / 50); //    for (i = 0; i < countWidth; i++) { for (j = 0; j < countHeight; j++) { //  TextBlock TextBlock element = new TextBlock(); //    TextBlock element.Name = "TB_" + i + "_" + j; //    //element.Text = char.ConvertFromUtf32(random.Next(0x4E00, 0x4FFF)); //      element.Text = ""; //  //      TextBlock int wx = i * 50; int wy = j * 50; element.Margin = new Thickness(wx, wy, 0, 0); //    element.Foreground = new SolidColorBrush(Colors.Green); //    element.FontSize = 36; //     Grid LayoutRoot.Children.Add(element); } } } //      Grid ( ) private void Event_Grid_Tap_LayoutRoot(object sender, System.Windows.Input.GestureEventArgs e) { Start(); } //    public async void Start() { int count, iteration; //         iteration = 1; count = 0; //         while (count < iteration) { //       int ranX = random.Next(0, 10); //       int ranY = random.Next(0, 20); //     int length = random.Next(3, 7); //          int time = random.Next(30, 70); await Task.Delay(1); //   await RandomElementQ_Async(ranX, ranY, length, time); count++; } } //  ,      public async Task RandomElementQ_Async(int x, int y, int length, int timeOut) { //     ,     . Dictionary<int, TextBlock> dicElem = new Dictionary<int, TextBlock>(); // ,    ,     if ((y + i) < countHeight && (y + i) >= 0).   4  . int count = 0; //      length for (int i = 0; i < length; i++) { //    ,        //     int countHeight = (int)Math.Round(ScreenHeight / 50); // ,       ,      if ((y + i) < countHeight) { //   ,      string elementName = "TB_" + x + "_" + (y + i); //      object wantedNode = LayoutRoot.FindName(elementName); TextBlock element = (TextBlock)wantedNode; //    ,        ""  ""  dicElem[count] = (element); //     .  ( ) -   ,  -  . //  1, ,        255   . int rf = (int)Math.Round(255 / (double)(i + 1)) - 1; //    ,    . . await Change(element, timeOut, 255); //   ,     .     ,     . for (int k = 0; k <= i; k++) { //    ""   (,  y = -5) if (dicElem.ContainsKey(k)) { // ,      .   ""  TextBlock previousElement = dicElem[k]; //    // (rf * (k + 1)) - 20   ,             //       ( ) Task dsvv = Change(previousElement, timeOut, (rf * (k + 1)) - 20); } } count++; } } } //       public async Task Change(TextBlock element, int timeOut, int Opacity) { //       SolidColorBrush NewColor = new SolidColorBrush(new Color() { A = (byte)(255) /*Opacity*/, R = (byte)(0) /*Red*/, G = (byte)(Opacity) /*Green*/, B = (byte)(0) /*Blue*/ }); //   ""  1   "" element.Foreground = NewColor; //       for (int i = 0; i < 5; i++) { //     element.Text = char.ConvertFromUtf32(random.Next(0x4E00, 0x4FFF)); //      await Task.Delay(timeOut); } } //       ApplicationBar //private void BuildLocalizedApplicationBar() //{ // //    ApplicationBar    ApplicationBar. // ApplicationBar = new ApplicationBar(); // //            AppResources. // ApplicationBarIconButton appBarButton = new ApplicationBarIconButton(new Uri("/Assets/AppBar/appbar.add.rest.png", UriKind.Relative)); // appBarButton.Text = AppResources.AppBarButtonText; // ApplicationBar.Buttons.Add(appBarButton); // //         AppResources. // ApplicationBarMenuItem appBarMenuItem = new ApplicationBarMenuItem(AppResources.AppBarMenuItemText); // ApplicationBar.MenuItems.Add(appBarMenuItem); //} } } 


Well, the first part of the application is ready. Backbone.
In the next part, we will transfer the application to the “Windows Phone Application with Panorama” template, expand the application's functionality by adding various matrix settings, the changes of which will immediately be displayed on the screen of your smartphone.

P.S. I tried to convey the sequence of my thoughts as much as possible, which would not seem like a black box for people who started studying WP8. As well as to simplify the code and gradually increase its complexity in the following parts. If there are strange moments - ask.

Source: https://habr.com/ru/post/195422/


All Articles