Модель данных / Разработка игр на Silverlight для начинающих

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


Назовем его GameBoard.cs. Это будет главный файл игровой модели.

Опишем нужные данные игры:

namespace MemoryCards.Models
{
public class GameBoard
{
public int nSizeWidth;//кол-во карточек по ширине
public int nSizeHeight;//кол-во карточек по высоте
public int nCountCell;//всего карточек
public Models.Card[] arrBoard;//игровая доска - массив карточек
public int nCountOpenCard;//кол-во текущих открытых карточек
public int nCountImages = 26;//кол-во уникальных изображений
public bool bEndGame = false;//конец игры
public int nCountTryOpen = 0;//попыток открывания карточек

Первые три свойства определяют размерность игровой доски. Свойство arrBoard — это одномерный массив карточек (для простоты оперирования), описывающий все карточки на поле размером M*N. При помощи специальных простых функций, мы сможем обращаться к элементам этого массива по координатам (x,y) (см. раздел «Вспомогательные функции»). Сами карточки опишем в отдельном файле класса C#, с названием Card.cs. Этот файл-класс добавил на случай, если для карточек потребуется дополнительный функционал. Вообще лучше всегда отдельные классы описывать в отдельных файлах.
Содержимое Card.cs содержит только структуру данных: индекс картинки, признак открыта, признак решена.

public struct Card
{
public int nImageIndex;
public bool bOpen;
public bool bComplit;
}

nCountOpenCard, nCountTryOpen — это счетчики действий пользователя, bEndGame - конец игры, с этими параметрами все понятно. nCountImages - количество отдельных картинок в файле изображений. Для начала, я взял просто набор букв из английского алфавита и сделал из них одно изображение 1300*50 точек:

Файл должен быть в формате PNG (Silverlight, насколько мне известно, поддерживает на данный момент только два типа файлов PNG и JPEG, из них только первый поддерживает прозрачный цвет). Файл назвал a_z.png и поместил в каталог Images. В разделе визуализации игры, мы будем загружать этот файл, выделять отдельные буквы-картинки и выводить на экран.
После объявления свойств игровой доски, нужно произвести ее инициализацию. Задача заключается в том, чтобы заполнить поле случайными парными изображениями, то есть в массив arrImages заполнить поле nImageIndex значениями от 0 до 25. Вот код инициализации:

public GameBoard(int nW, int nH)
{
nSizeWidth = nW;
nSizeHeight = nH;
nCountCell = nSizeWidth * nSizeHeight;
nCountOpenCard = 0;
arrBoard = new Models.Card[nCountCell];

//генерация случайных неповторяющихся карточек

//создаем массив индексов изображений и перемешиваем его
int[] arrImages = new int[nCountImages];
for (int n = 0; n < nCountImages; n++) arrImages[n] = n;
arrImages=shuffleArrInt(arrImages);
//инициализация карточек доски
for (int n = 0; n < nCountCell; n++)
{
arrBoard[n].nImageIndex = -1;
//arrBoard[n].bOpen = false;
//arrBoard[n].bComplit = false;
}
//прерывание выполнения, если недостаточно количества изображений для полноценного заполнения доски
if (nCountCell/2 > nCountImages) throw (new ArgumentOutOfRangeException("count cells > images"));
//заполняем доску парными изображениями из перемешанного массива индексов изображений
for (int n = 0; n < nCountCell; n += 2)
arrBoard[n].nImageIndex = arrBoard[n + 1].nImageIndex = arrImages[n/2];
//перемешиваем карточки на доске
shuffle();
}

На вход конструктора подаем ширину и высоту поля, определяем нужные свойства. Затем создаем массив индексов отдельных картинок от 0 до 25 и перемешиваем его, чтобы затем последовательно заполнить массив карточек парными значениями arrBoard[n].nImageIndex = arrBoard[n + 1].nImageIndex = arrImages[n/2] — который затем также перемешиваем. Функции shuffleArrInt(arrImages) и shuffle() работают аналогично. Простой алгоритм, переставляет достаточное (кол-во элементов*2) количество раз, 2 случайных элемента массива:

int[] shuffleArrInt(int[] arrInt)
{
Random rand = new Random();
for (int n = 0; n < arrInt.GetLength(0)*2; n++)
{
int n1 = rand.Next(arrInt.GetLength(0));
int n2 = rand.Next(arrInt.GetLength(0));
if (n1 != n2)
{
int nTemp = arrInt[n1];
arrInt[n1] = arrInt[n2];
arrInt[n2] = nTemp;
}
}
return arrInt;
}


Осталось рассмотреть игровую логику модели. Требуется определить ее реакцию при открывании карточки, а также проверку состояния игры на правильность решения.
Для наглядности сразу приведу код открытия карточки:

public void openCard(int nIndex)
{
if (arrBoard[nIndex].bOpen == false)
{
if (nCountOpenCard < 2)
{
arrBoard[nIndex].bOpen = true;
nCountTryOpen++;
nCountOpenCard++;
}else
{
for (int n = 0; n < nCountCell; n++)
arrBoard[n].bOpen = false;
arrBoard[nIndex].bOpen = true;
nCountTryOpen++;
nCountOpenCard = 1;
}
}else
arrBoard[nIndex].bOpen = false;

solve();

}

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


void solve()
{
int[] arrOpenCard = new int[2];
arrOpenCard[0] = arrOpenCard[1] = -1;
int ni = 0;
for (int n = 0; n < nCountCell; n++)
if (arrBoard[n].bOpen == true) arrOpenCard[ni++] = n;
if (arrOpenCard[0] != -1 && arrOpenCard[1] != -1)
if (arrBoard[arrOpenCard[0]].nImageIndex == arrBoard[arrOpenCard[1]].nImageIndex)
{
arrBoard[arrOpenCard[0]].bOpen = false;
arrBoard[arrOpenCard[1]].bOpen = false;
arrBoard[arrOpenCard[0]].bComplit = true;
arrBoard[arrOpenCard[1]].bComplit = true;
}
int nCountComplit = 0;
for (int n = 0; n < nCountCell; n++)
if (arrBoard[n].bComplit == true) nCountComplit++;
if (nCountComplit == nCountCell) bEndGame = true;
}

Комментариев нет:

Отправить комментарий

Да, я внимательно слушаю