УДК 004.6
Поварницын Е.Н. студент 2 курса
факультет «Информационные системы и технологии» Северный Арктический Федеральный Университет
Россия, г. Архангельск СОЗДАНИЕ ИГРЫ «ПЯТНАШКИ» НА ЯЗЫКЕ C#
Аннотация: Статья посвящается созданию игры «Пятнашки». В данной статье описан сам процесс игры, а так же её суть. Так же наглядное использование языков C# и XAML.
Ключевые слова: Пятнашки, XMAL, C#, игра, компьютерная игра, Microsoft Visual Studio.
Povarnitsyn E.N.
student
2year, faculty "Information Systems and Technologies"
Northern Arctic Federal University Russia, Arkhangelsk CREATING THE GAME "FIFTEEN" IN C #
Annotation: The article is dedicated to the creation of the game "Fifteen." This article describes the game process itself, as well as its essence. Also, the visual use of the C # and XAML languages.
Keywords: Fifteen, XAMLL, C #, game, computer game, Microsoft Visual Studio.
ОПИСАНИЕ ИДЕИ
Сперва, сделаем один уровень игры размером пятнашек 4x4, но в процессе работы осложним игру. Сложность заключается в размерах самой игры: Лёгкий уровень размером 3x3, средний 4x4 и сложный 5x5. После всей работы сама игра выглядела не очень красиво с обычными цветовыми палитрами и поэтому закрасим кнопки с цифрами в текстуру, а сам фон сменим с градиента на более живой. Таким образом, получится, вроде как, красивая и интересная игра «Пятнашки».
РЕАЛИЗАЦИЯ
Для начала нужно создать саму модель игры «Пятнашки». Для этого создадим «класс», в котором будет реализован основной процесс игры. Для облегчения процесса создания также потребовались «методы» в самом классе.
Первый метод «Model» , данный метод позволял создать матрицу для самой игры, так же он намного упрощал создания таких игр как 24,8, в соответствии с рисунком 1. Переменная map служила самой матрицей, а size размер, к примеру 4.
class Model {
int size;
int[,] map;
int space_x, space_y;
static Random rand = new Random();
public Model (int size) {
if (size < 2) size = 2; if (size > 5) size = 5; this.size = size; map = new int[size, size]
}
Рисунок 1 - Model Следующий метод «Start». Данный метод заполняет массив цифрами по координатам, в соответствии с рисунком 2. Так же здесь используется метод «coords_to_position», но о нём позже.
public void start() {
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
map[x, y] = coords_to_position(x, y) + 1;
space_x = size - 1;
space_y = size - 1;
map[space_x,space_y] = 0;
}
Рисунок 2 - Start
Далее расположены методы «coords_to_position» и «position_to_coords».
Первый метод с помощью координат x и y ищет номер матрицы, к примеру, если будет координата x=3, а y=0, то матрица примет значения 3. Так же он не даёт матрице переполниться, что впоследствии могло взывать ошибку. Второй метод же возвращает координаты x и y обратно, то есть даёт возможность с помощью элемента массива найти, какие координаты он имеет, в соответствии с рисунком 3. Так же он проверяется, что бы массив не переполнился.
private int coords_to_position(int x,int y) {
if (x < 0) x = 0;
if (x > size -1 ) x = size-1;
if (y < 0) y = 0;
if (y > size - 1) y = size - 1; return y * size + x;
}
private void position_to_coords (int position, out int x, out int y) {
if (position < 0) position = 0; if (position > size * size - 1) y=size*size-1 ; x = position % size; y = position / size;
}
Рисунок 3 - coords_to_position и position_to_coords Следующий метод «Shift» позволяет нам передвигать нулевой элемент в массиве, в соответствии с рисунком 4. Другими словами обмениваться числами. Это позволит нам в будущем передвигать наши пятнашки.
public void shift(int position) {
int x, y;
position_to_coords(position, out x, out y); if ((Math.Abs(space_x - x) + Math.Abs(space_y - y)) == 1) { map[space_x, space_y] = map[x, y]; map[x, y] = 0; space_x = x; space_y = y;}
}
Рисунок 4 - Shift
Метод «Get_number» нам понадобится для того, чтобы в будущем получить координату, на котором будет расположено число, в соответствии с рисунком 5.
public int get_number(int position) {
int x, y;
position_to_coords(position, out x, out y); if (x < 0 || x >= size) return 0;
if (y < 0 || y >= size) return 0; return map[x, y];
}
Рисунок 5 - Get_number Для того чтобы в начале игры числа располагались случайно составим
метод «SЫft_гandom». В нём нулевое число будет передвигаться на 4 стороны наугад, в соответствии с рисунком 6.
public void shift_random() {
int a = rand.Next(0, 4);
int x = space_x;
int y = space_y;
switch (a) {
case 0: x--; break; case 1: x++; break; case 2: y--; break; case 3: y++; break;
}
shift(coords_to_position(x, y)); _}_
Рисунок 6 - Shift_random И самый последний метод в данном классе является «Chek_game». Данный метод проверяет не окончена ли ещё игра. Он сверяет, не совпадают ли начальные координаты с текущими, и если они совпадают, то он выдаёт значение «true», в соответствии с рисунком 7. Игра будет продолжаться до тех пор, пока этот метод не будет действительным.
public bool chek_game() {
if (!(space_x == size - 1 && space_y == size - 1))
return false; for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++) if (!(x == size - 1 && y == size - 1))
if (map[x, y] != coords_to_position(x, y) + 1) return false; return true;
}
Рисунок 7 - Chek_game На этом класс игры заканчивается и начинается работа с файлами .xaml и xaml.cs.
WINDOWS PRESENTATION FOUNDATION На данном этапе будет показано, как делается средний уровень 4x4 сложности в игре «Пятнашки». Лёгкий уровень 3x3 и сложный 5x5 делается аналогично, с добавлением или удалением кнопок, в зависимости от параметра матрицы.
Сначала, следует разделить окно на равную клетчатую таблицу, где будут расположены 4 строки и 4 столбца. В них следует сделать кнопки («Button») и установить обработчик событий «По клику». Таким образом, у нас в .xaml.cs добавятся методы при взаимодействии с данной кнопкой. Для
взаимодействия с кнопками добавим «Tag» к каждой кнопки начиная с 0 и заканчивая 15.
Далее добавим метод Button, который позволит с помощью кейсов взаимодействовать с кнопками, в соответствии с рисунком 8.
private Button button (int position) {
switch (position) {
case 0: return button0; case 1: return button1; case 2: return button2; case 3: return button3; case 4: return button4; case 5: return button5; case 6: return button6; case 7: return button7; case 8: return button8; case 9: return button9; case 10: return button10; case 11: return button11; case 12: return button12; case 13: return button13; case 14: return button14; case 15: return button15; default: return null;
} }
Рисунок 8 - Button Далее создадим метод «refresh», который будет отвечать за расстановку чисел на кнопки, он будет брать номера из массива и преобразовывать их в текст (контент), в соответствии с рисунком 9. Также для красивой картинки сделаем кнопку, на которой будет расположено число 0 невидимой.
private void refresh() {
for (int position = 0; position < 16; position++) {
button(position).Content = game.get_number(position); button(position).Visibility = (game.get_number(position)==0)?
Visibility.Collapsed:Visibility ; }
}
Рисунок 9 - Refresh Остаётся только начать игру. И для этого нужно создать метод «Start_game». В котором будут располагаться сначала элементы в массиве, потом перемешиваться с определённой точностью n шагов и
преобразовываться в текст (контент), в соответствии с рисунком 10.
private void start_game (){ game.start();
for (int i = 0; i < 100; i++) game.shift_random();
}
Рисунок 10 - Start_game Далее возвратимся к нашим кнопкам. В них следует отметить позицию, конвертировав наш тэг, для определения кнопки, далее следует добавить наше передвижение по матрицы и конвертировать ее в текст. Следует это сделать ко всем кнопкам. Теперь цифры передвигаются с кнопки на кнопку. Теперь чтобы понять что игра закончена следует её проверить через метод «chek_game», и если оно true, то вывести на экран победное сообщение с предложением либо повторить игру, либо закрыть приложение. Это следует сделать в соответствии с рисунком 11 и применить ко всем кнопкам соответственно.
private void Button_Click(object sender, RoutedEventArgs e) {
int position = Convert.Tolntl6(((Button)sender).Tag);
game.shift(position);
refresh();
if (game.chek_game()) {
var res = MessageBox.Show("Победа!!!\nЕще разок?", "Ура!!!", MessageBoxButton.YesNo);
if (res == MessageBoxResult.Yes)
start_game(); else Close();
}
}
Рисунок 11 - Button_Ckick_N Всё, наша игра готова, теперь остаётся сделать ее визуально красивой. Для этого в файле .xaml отредактируем фон игры и собственно сами кнопки. Наложим на фон красящую картинку, в соответствии с рисунком 12.
<Window.Background>
<lmageBrush lmageSource="/lmg/Normal.jpg" Stretch="UniformToFill"/> </Window.Background>
Рисунок 12 - Background Далее будет работать с кнопками приложения. Добавим на кнопки фон,
сделаем так, чтобы кнопки имели формы фона, у меня они квадратные. Так же я сделал рамку под цвет фона, для того что бы лучше выглядело. Следует всё это выполнить в соответствии с рисунком 13, и применить ко всем кнопкам, дабы они не различались друг от друга
<Button.OpacityMask>
<ImageBrush ImageSource="Img/Lava1.jpg" Stretch="Uniform"/> </Button.OpacityMask> <Button.Background>
<ImageBrush Stretch="Uniform" ImageSource="Img/Lava1.jpg"/> </Button.Background> <Button.BorderBrush>
<ImageBrush Stretch="Uniform" ImageSource="Img/Lava1.jpg"/> </Button.BorderBrush>
Рисунок 13 - Button.Img Для будущего взаимодействия с главным экранам я сделал кнопки «В главное меню». Так же я добавил «Рестарт» и «Выход». Для того чтобы выйти в главное меню, нужно прежде всего создать ещё одно окно и сделать переход на него при нажатии определённой кнопки, в соответствии с рисунком 14.
private void Button_Click_17(object sender, RoutedEventArgs e) {
Window1 taskWindow = new Window1();
taskWindow.Show();
Close();
}
Рисунок 14 - Переход в главное меню Так же стоит добавить чтобы игра стартовала при загрузки окна, для этого нужно сделать в обработчики событий «Loaded» и в файле .xaml.cs запустить игру, в соответствии с рисунком 15.
private void Window_Loaded(object sender, RoutedEventArgs e) {
start_game();
}
Рисунок 15 - Загрузка игры В итоге мы получаем игру «Пятнашки», показанную на рисунке 16.
т Пятнашки — □ X
Рисунок 16 - Пятнашки
Теперь можно создать лёгкий и сложный уровень, сделав некоторые махинации с кнопками. Для увеличения или уменьшения массива стоит всего лишь поменять одну переменную game = new Model(поле NxN), в соответствии с рисунком 17.
public partial class MainWindow : Window {
Model game;
public MainWindow() {
lnitializeComponent();
game = new Model(4);
}
Рисунок 17 - Размер поля
Так же следует изменить кол-во кейсов в методе «Button» на необходимое количество, в соответствии с рисунком 18.1 и 18.2.
private Button button(int position) {
switch (position) {
case 0: return button0; case 1: return buttonl; case 2: return button2; case 3: return button3; case 4: return button4; case 5: return buttons; case 6: return button6; case 7: return button7; case 8: return buttons; default: return null;
}
}
private Button button(int position) {
switch (position) {
case 0: return button0;
case 1: return button1;
case 2: return button2;
case 3: return button3;
case 4: return button4;
case 5: return button5;
case 6: return button6;
case 7: return button7;
case 8: return button8;
case 9: return button9;
case 10 return button10;
case 11 return button11;
case 12 return button12;
case 13 return button13;
case 14 return button14;
case 15 return button15;
case 16 return button16;
case 17 return button17;
case 18 return button18;
case 19 return button19;
case 20 return button20;
case 21 return button21;
case 22 return button22;
case 23 return button23;
case 24 return button24;
default: return null;
}
}
Рисунок 18.2 - Изменение Button для 5x5
После чего следует поменять расстановку чисел на кнопках в методе «Refresh», если поле 4x4, то будет 16, если 3x3, то 9, если 5x5, то 25 и т.д., в соответствии с рисунком 19.1 и рисунком 19.2.
private void refresh() {
for (int position = 0; position < 9; position++) {
button(position).Content = game.get_number(position); button(position).Visibility = (game.get_number(position) == 0)
? Visibility.Collapsed: Visibility; }
_Рисунок 19.1 - Изменение Refresh для 3x3_
private void refresh() {
for (int position = 0; position < 25; position++) {
button(position).Content = game.get_number(position); button(position).Visibility = (game.get_number(position) == 0) ? Visibility.Collapsed: Visibility;
}
}
Рисунок 19.2 - Изменение Refresh для 5x5 После этих операций и некоторых работы в XAML мы получаем игры, в соответствии с рисунками 20.1 и 20.2
ДЗ Пятнашки — □ X
Рисунок 20.1 - Лёгкий уровень
• П«4*-п D *
Рисунок 20.2 - Сложный уровень Далее в уже созданном меню, разместим ссылки на открытие самих уровней и закрытие самой игры, в соответствии с рисунком 21.
private void Button_Click(object sender, RoutedEventArgs e) {
Easy taskWindow = new Easy();
taskWindow.Show();
Close();
}
private void Button_Click_1(object sender, RoutedEventArgs e) {
MainWindow taskWindow = new MainWindow();
taskWindow.Show();
Close();
}
private void Button_Click_2(object sender, RoutedEventArgs e) {
Hard taskWindow = new Hard();
taskWindow.Show();
Close();
}
private void Button_Click_3(object sender, RoutedEventArgs e) {
Close();
}
Рисунок 21 - Ссылка на уровни и выход
В итоге после редактирования фона и кнопок, мы получим меню через которое можно проходить на уровни, в соответствии с рисунком 22.
Рисунок 22 - Меню игры И в самом конце можно добавить иконку для игры, в соответствии с рисунком 23_
^^^Пятнашки" Height="500" Width="750" Icon="Img/Games.ico">
Рисунок 23 - Иконка для игры Всё, мы получили игру с красивым оформлением. Это можно увидеть на рисунке 24.
Рестарт
17 19
in
9 Î 4 6 11 5 12
1) 10 14 1$
Выход
Рисунок 24 - Готовая игра Использованные источники:
1. Подбельский, В.В. Язык декларативного программирования XAML / В.В. Подбельский. — Москва : ДМК Пресс;
2. Александров, Э.Э. Программирование на языке C в Microsoft Visual Studio 2010 : учебное пособие / Э.Э. Александров, В.В. Афонин. — 2-е изд. — Москва