Опубликован: 24.03.2009 | Доступ: свободный | Студентов: 2286 / 115 | Оценка: 4.24 / 3.93 | Длительность: 17:47:00
Лекция 3:

Использование Visual Studio с Silverlight 2

< Лекция 2 || Лекция 3: 12345 || Лекция 4 >

Написание кода игры

Код игры в данном примере написан на C#. Его без труда можно было бы транслировать на VB.NET, IronPython или любой другой поддерживаемый язык программирования, но в большинстве случаев в данном курсе будет использоваться C#.

Инициализация структур данных

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

В Silverlight нельзя создать фрагмент существующего изображения, но можно вырезать его по определенному контуру. Не следует путать вырезание с обрезкой. В первом случае вы указываете, какие части рисунка должны быть отрисованы; во втором -удаляете все, кроме необходимой части изображения. Silverlight не поддерживает обрезку, поэтому приходится вырезать изображение.

Проблема использования вырезания состоит в том, что при его применении остальная часть рисунка остается доступной и может быть активизирована щелчком мыши. Например, если имеется изображение 400 х 400 и из него вырезается квадратный фрагмент 100 х 100 в позиции (100,100), мы видим квадрат 100 х 100 в позиции (100,100), но объект400 х 400 никуда не исчез: он стал пустым, но по-прежнему может быть активизирован щелчком мыши. Это не отвечает нашим требованиям для создания головоломки с перемещаемыми фрагментами. Но что можно сделать?

Решение состоит во введении в Canvas изображения, размеры которого соответствуют размерам вырезанного фрагмента, и последующем использовании трансформации транслирования на него, чтобы вырезанная часть изображения располагалась в верхнем левом углу данного Canvas, и, таким образом, Canvas формировал визуальное отображение только вырезанной области.

Итак, для головоломки 4x4, образованной 16 блоками необходимо создать 16 изображений и 16 объектов Canvas. Также потребуется как-то представлять поле, чтобы вы знали, какое изображение в каком квадрате находится. Вот код для описания этого:

Canvas[] cI = new Canvas[16]; 
Image[] i = new Image[16]; 
int[] board = new int[16];
Создание фрагментов головоломки

Чтобы создать фрагменты головоломки, понадобиться загрузить изображение sl.jpg в каждый элемент массива изображений. Для этого с помощью универсального идентификатора ресурса (uniform resource identifier, URI) мы указываем на необходимое изображение и определяем класс BitmapImage (из пространства имен System.Windows.Media.Imaging ), в который считываются данные по этому URI. И присваиваем этот класс элементу управления изображение:

i[nx].Source = new BitmapImage(uri);

Из конструктора можно вызвать функцию ( InitBoard ), которая будет использоваться для создания экземпляров фрагментов головоломки:

public Page() {
// Необходимо для инициализации переменных
InitializeComponent();
InitBoard(); }

Эту функцию можно увидеть здесь:

void InitBoard() { 
 Uri uri = new Uri("sl.jpg", UriKind.Relative); 
 int nx = 0;
 for (int ix = 0; ix < 4; ix++) 
  for (int iy = 0; iy < 4; iy++) { 
    nx = (ix * 4) + iy; 
    i[nx] = new Image(); 
    i[nx].Height = 400; 
    i[nx].Width = 400;
    i[nx].Stretch = Stretch.UniformToFill; 
    RectangleGeometry r = new RectangleGeometry(); 
    r.Rect = new Rect((ix * 100), (iy * 100), 100, 100); 
    i[nx].Clip = r;
    i[nx].Source = new BitmapImage(uri);
    i[nx].SetValue(Canvas.TopProperty, Convert.toDouble(iy * 100 * -1)); 
    i[nx].SetValue(Canvas.LeftProperty, Convert.toDouble(ix * 100 * -1));
    cI[nx] = new Canvas();
    cI[nx].Width = 100;
    cI[nx].Height = 100;
    cI[nx].Children.Add(i[nx]);
    cI[nx].SetValue(Canvas.NameProperty, "C" + nx.ToString());
    cI[nx].MouseLeftButtonDown += new 
            MouseButtonEventHandler(Page  MouseLeftButtonDown); 
    if (nx < 15) GameContainer.Children.Add(cI[nx]);
  }
 // Перемешиваем фрагменты shuffle();
 // Отрисовываем поле drawBoard();
}

Не забудьте добавить ссылку на System.Windows.Media.Imaging в начале кода:

using System.Windows.Media.Imaging;

На первый взгляд все это может показаться немного сложным, но при более близком рассмотрении все предельно просто. Задается вложенный цикл для прохождения по осям х и у с диапазоном значений от 0 до 3 . Это, как можно догадаться, используется для организации массива 4x4 для изображений.

Массивы Image и Canvas, используемые для хранения фрагментов, являются одномерными массивами по 16 элементов каждый (при такой структуре для их хранения требуется меньше памяти и кода). Чтобы спроецировать двумерные координаты ix, iy на одномерный массив, необходимо выполнить следующие вычисления:

nx = (ix * 4) + iy;

Для каждого элемента задаются размеры 400 х 400 с помощью значения UniformToFill (Равномерное заполнение) свойства Stretch (Растяжение). Более подробно об использовании изображений рассказывается в "Основы XAML" , "Основы XAML".

Далее вычисляется область вырезания. Для этого используется объект RectangleGeometry (Геометрический элемент прямоугольник):

RectangleGeometry r = new RectangleGeometry(); 
r.Rect=new Rect((ix*100), (iy*100) ,100,100); 
i[nx].Clip = r;

Таким образом, определяется прямоугольник с соответствующими координатами (полученными путем умножения ix и iy на 100) соответствующего размера (100 х 100), и он задается как область вырезания для текущего изображения ( i[nx] ).

Далее изображение загружается в BitmapImage, инициализация которого происходит путем задания URI этого изображения, и помещается в заданное положение. Чтобы изображение, вырезанное в позиции (100,100), появилось в верхнем левом углу, оно должно быть передвинуто на (-100,-100) относительно вырезанной области. Таким образом, свойствам Top (Сверху) и Left (Слева) должно быть задано значение -100 и умножено на значения iy и ix, соответственно.

i[nx].Source = new BitmapImage(uri);
i[nx].SetValue(Canvas.TopProperty, Convert.toDouble(iy * 100 * -1)); 
i[nx].SetValue(Canvas.LeftProperty, Convert.toDouble(ix * 100 * -1));

Изображения до сих пор не добавлены в родительский Canvas. Это следующий шаг. Canvas необходимо инициализировать, задать его размеры и добавить в него в качестве дочернего элемента соответствующее изображение. Вот код:

cI[nx] = new Canvas(); 
cI[nx] .Width = 100; 
cI[nx].Height = 100; 
cI[nx].Children.Add(i[nx]);

Теперь мы получили наш Canvas, и он содержит наше вырезанное изображение. Завершаем инициализацию, присваивая Canvas имя (чтобы его можно было отслеживать, когда мы щелкаем его), определяем обработчик событий для описания действий, которые будут выполняться по щелчку пользователя по нему, и, наконец, добавляем его в родительский Canvas. Пока нет необходимости задавать местоположение фрагмента. Это будет сделано после того, как фрагменты будут перемешаны на поле.

Обратите внимание, последнее изображение не добавляется на поле, потому что мы хотим, чтобы осталось свободное пространство.

cI[nx].SetValue(Canvas.NameProperty, "C" + nx.ToString()); 
cI[nx].MouseLeftButtonDown += new 
         MouseButtonEventHandler(Page  MouseLeftButtonDown); 
 if(nx<15)
   GameContainer.Children.Add(cI[nx]);

Наконец, необходимо перемешать фрагменты и отрисовать игровое поле. Код для реализации этого представлен в следующем разделе.

< Лекция 2 || Лекция 3: 12345 || Лекция 4 >