Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Windows Phone 8: Создаем приложение. Матрица. Часть 1

Anna | 17.06.2014 | нет комментариев
Создавая приложение на конкурс возникла так же идея поделиться процессом его создания, так как сам столкнулся с сложностями нахождения информации по созданию приложений для Windows Phone 8. Отчего «Матрица»? Потому, что еще с выхода фильма она меня завораживала. Потом обнаружил заставку на экран. Мог часами глядеть на нее. А сейчас решил теснее перенести ее на телефон, что б неизменно была под рукой. И так начнем.

Принт скрин с экрана Lumia 520

Года 2 назад я теснее создавал что-то схожее, но на JQuery. Впрочем тогда все получилось, помимо полноценности: наивысший размер матрицы, при котором она не «тормозила» составлял примерно 15 Х 20 клеточек, что очевидно немного для современных FULL HD мониторов. При выяснении причин такого поведения узнал, что оно все грузило только 1 ядро и как я тогда осознал, только в 1 потоке (могу заблуждаться, но огромнее на эту тему разбора полетов не устраивал). Да и создавал только с целью освоиться в этом JS фреймворке. C# лишен этих недостатков, да и мощности современных телефонов должно хватить для обработки большого число элементов и множества случайных чисел на всякий такой элемент. Забегая наперед, скажу что при тестировании на моей слабенькой Lumia 520 все мои веры оправдались.

Для начала определим, что именно хотим сделать

  1. Сетка ячеек, в которой случайным образом выбираются координаты начала змейки
  2. Змейки будут различной случайной длины
  3. В всякой ячейке змейки элементы меняются случайным образом случайное число раз
  4. Присутствует результат затухания цвета. Яркость всякой составляющей змейки зависит от ее длины

Что применял для создания приложения

  • Windows 8 Pro x64 (RU)
  • VS 2012 SP1 (RU)
  • Windows Phone SDK 8.0 (RU)
  • Только типовые элементы, входящие в VS
  • Тестировал на эмуляторе с настройками WVGA 512 MB (RU)

Пару слов про тестирование. На эмуляторе итоги не крепко правдоподобны. При запуске большого числа змеек он показывал огромнее FPS чем на настоящем телефоне. При отладке на телефоне — телефон тормозит страшно. Впрочем позже остановки отладки и простого запуска приложения продуктивность была адекватная.

Перейдем к работе в Visual Studio

Создаем план: Образцы — Visual C# — Windows Phone — Приложение Windows Phone.
Выбираем .NET Framework 4.5.
Имя плана у меня SE_Matrix_2d_v_1. Оно же будет и namespace.
Выбираем Windows Phone OS 8.0.

MainPage.xaml

Сейчас отредактируем XAML код. Нам необходим будет только Grid с именем LayoutRoot и событие нажатия(Tap) Event_Grid_Tap_LayoutRoot, в тот, что динамически, в зависимости от растяжения экрана будем вписывать надобное число ячеек TextBlock. Глядим:

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

Запускаем эмулятор. Должен быть легко черный экран.

MainPage.xaml.cs

Сразу подключаем нужные библиотеки:

using System.Windows.Media; // Для работы с цветами
using System.Threading.Tasks; // Для асинхронных вызовов
using System.Diagnostics; // Для отладки. Debug.WriteLine( SomethingYouNeedToSee);

В конструкторе вызовем способ CreateElement, тот, что с сделает матрицу элементов, в которой и будут прохоk! // Перебираем все элементы, составляющие змейку на данном этапе. С всяким циклом она возрастает, пока не достигнет своей длины. 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 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);
            }            
        }
Работающий код файла 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-й элемент(тот, что падает) -  всега самый блестящий, конечный - самый темный.
                    // Отнимаем 1, потому, что конечный элемент в выводе получается огромнее 255 и становится блестящим.
                    int rf = (int)Math.Round(255 / (double)(i   1)) - 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);
        //}
    }
}

Ну вот и готова перваячасть приложения. Костяк.
В дальнейшей части мы переведем приложение на образец «Приложение Windows Phone с панорамой», расширим функционал приложения добавлением разных настроек матрицы, метаморфоза которых будут сразу же отображаться на экране вашего телефона.

П.С. Усердствовал максимально передать последовательность своих мыслей, что б для людей начавших постижение WP8 приложение не казалось черным ящиком. А так же максимально упростить код и понемногу наращивать его трудность в следующих частях. Если есть непонятные моменты — спрашивайте.

Источник: programmingmaster.ru
Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB