Пошаговое создание игры «Same Game». Урок №8

  Дмитрий Бушуев  | 

    | 

  Обновл. 20 Авг 2019  | 

 539

Уже можно видеть, как наша версия игры «SameGame» обретает форму готового приложения. Ведь наш проект является уже не просто полурабочим прототипом, а полноценной игрой с пятью уровнями сложности. И в данном уроке мы продолжим кастомизировать приложение, добавляя пользователю возможность изменить размеры игрового поля, а также количество блоков, расположенных на нём. В этом нам поможет «Диалоговое окно», которое и будет запрашивать эти данные.

Изменяем размеры и количество блоков

Первым шагом в данном направлении является внесение изменений в классы, соответствующие игровому полю и Document. Начнём с класса игрового поля и немного отредактируем его заголовочный файл. Т. к. у нас в классе CSameGameBoard уже есть геттеры, через которые можно получить данные о ширине/высоте блоков и количестве строк/столбцов на доске, то теперь нужно добавить и сеттеры для установки этих значений.

Файл SameGameBoard.h:

Для облегчения чтения и восприятия класса мы поместили сеттеры сразу после геттеров. В них нет ничего сложного, лишь обычные условия проверки для каждого из набора значений ширины/высоты блока (заданных в пикселях) и количества строк/столбцов. Почему мы выбрали именно эти значения параметров: 3 и 5? Дело в том, что эти числа выбраны из-за того, что значения меньше 3 и больше 5 сильно портят «эстетический» вид игрового поля.

Далее мы отредактируем аналогичным образом Document, добавляя сеттеры к уже присутствующим геттерам.

Файл SameGameDoc.h:

Всё, что нам осталось сделать — это создать окно, в котором пользователь будет вводить новые параметры, затем нам нужно будет изменить размеры игрового поля, изменить размеры окна и заново перерисовать главное окно приложения. Реализуем это с помощью обработчика событий для параметров меню. Ничего сложного в этом нет, за исключением обработки запроса пользователя на изменение размеров. Для этого нам потребуется создать «Диалоговое окно». Создание нового «Диалогового окна» в Visual Studio начинается с окна редактора ресурсов.

Откройте «Окно ресурсов» через Вид > Другие Окна > Ресурсы или с помощью нажатия комбинации клавиш CTRL+SHIFT+E. Мы уже использовали это окно в прошлый раз для редактирования пунктов меню. Правда в этот раз, вместо редактора меню, нам нужен будет редактор диалоговых окон. Можно заметить, что в нём уже есть одно диалоговое окно IDD_ABOUTBOX, автоматически сгенерированное средствами MFC в тот момент, когда создавался проект. Данное окно появляется каждый раз, когда в нашей программе пользователь нажимает Справка > Сведения о SameGame…. Добавить новое окно очень просто, для этого нужно нажать правой кнопкой мыши по пункту «Dialog» в «Окне Ресурсов SameGame» и выбрать «Вставить Dialog»:

Перед вами откроется форма с пустой заготовкой, имеющая идентификатор IDD_DIALOG1:

Дважды щёлкните по IDD_DIALOG1, чтобы попасть в «Редактор диалоговых окон». Средства MFC сгенерировали форму с уже заранее установленными кнопками «ОК» и «Отмена»:

Через эту форму мы будем запрашивать у пользователя не только параметры размера игровой доски, но также и количество строк/столбцов, число блоков, их ширину и высоту, поэтому нам нужно сделать его максимально универсальным. При этом на форму нужно будет поместить несколько меток (labels), полей редактирования (edit boxes) и кнопок (buttons), чтобы сделать наше диалоговое окно более функциональным. Сначала нам нужно открыть «Панель элементов» редактора диалогов через меню Вид > Панель Инструментов или использовать сочетание клавиш CTRL+ALT+X:

Это список так называемых «Основных элементов управления». Аналогичные элементы вы можете встретить практически в любом Windows-приложении. Итак, нам потребуется элемент «Static Text» («Статический Текст»), чтобы указать, какие входные данные пользователь должен вводить в каждый из элементов управления («Edit Control»). Помимо этого, нужно будет добавить кнопку (button), которая будет восстанавливать значения по умолчанию. Для того чтобы добавить элемент, просто щёлкните по нему и перетащите из панели инструментов прямо на форму в «Редакторе диалоговых окон». Предлагаю начать с кнопки, нажмите и перетащите её чуть ниже кнопок «OK» и «Отмена»:

Чтобы изменить текст кнопки, просто нажмите на неё, чтобы она была выбрана как на скриншоте выше, и начните вводить с клавиатуры «По умолчанию».

Далее нам нужно добавить 2 элемента типа «Edit Control» («Элементы управления редактированием»). Щёлкните по ним в диалоговом окне и перетащите на форму. Чтобы их выровнять, вы можете кликнуть по линейкам выше и слева в «Редакторе окон», чтобы создать направляющие, которые привязываются к элементам формы:

Теперь давайте добавим несколько элементов «Static Text» («Статический текст») для того, чтобы пользователю было понятно, где и какие данные нужно вводить. Я добавил несколько дополнительных направляющих, которые помогут выровнять новые элементы, привязываясь к уже существующим. Эти элементы будут иметь свой текст. Благодаря этому мы сможем изменять текст в зависимости от типа данных, которые мы хотим получить от пользователя:

Именно так наше диалоговое окно будет выглядеть для обоих вариантов меню, с которыми мы будем работать в этом уроке, а именно «Размер блока…» и «Количество блоков…». Для этого нам нужно будет изменить заголовок окна, описания внутри элементов «Static Text» и значения в «Edit control» в зависимости от того, какую информацию мы хотим получить от пользователя. Кроме этого, нам нужно будет ещё внести несколько изменений в идентификаторы элементов управления, которые мы добавили. Это облегчит работу с ними. Для этого вызываем уже знакомое нам «Окно свойств», нажав ALT+ENTER или через меню Вид > Окно свойств. При этом в «Окне свойств» будут отображаться свойства для конкретно выбранного элемента. На скриншоте ниже показан пункт, который нужно изменить:

IDC_STATIC — это зарезервированный идентификатор для всех элементов «Static Text». Давайте изменим его на что-то вроде IDC_STATIC_TEXT_1. Похожим образом предлагаю изменить идентификаторы для всех элементов управления на нашей форме. Для этого на форме выделите другой элемент и, как в прошлый раз, измените его идентификатор в «Окне свойств». Верхний «Static Text» будет IDC_STATIC_TEXT_1, а нижний — IDC_STATIC_TEXT_2. Затем подобным образом переименуйте элементы «Edit Control», задавая соответствующие ID: IDC_EDIT_VALUE_1 и IDC_EDIT_VALUE_2. Благодаря этому мы в дальнейшем сможем динамически изменять текст внутри этих элементов в зависимости от того, какие данные мы хотим получить от пользователя. Кнопке с текстом «По умолчанию» задайте IDC_BUTTON_DEFAULTS. В конце нам нужно будет поменять ID самой формы с IDD_DIALOG1 на IDD_DIALOG_OPTIONS (это нам пригодится в дальнейшем, когда мы будет показывать пользователю данное окно).

После того, как мы закончили редактировать наше диалоговое окно, пришло время написать для него код.

Для этого просто нажмите правой кнопкой мыши по заголовку вашей формы и выберите «Добавить класс…»:

Запустится «Мастер классов MFC». Заполните соответствующие поля так, как показано на скриншоте ниже:

Прежде чем взяться за код, который был автоматически создан «Мастером добавления класса MFC», давайте добавим несколько переменных в этот класс. Они будут связаны с элементами управления, которые мы ранее добавили на форму. Для этого вернитесь в «Редактор форм» и нажмите правой кнопкой мыши по элементу с ID_STATIC_TEXT_1 и выберите «Добавить переменную…»:

После чего вашему взору предстанет «Мастер добавления переменных». Он добавит переменную в класс и ассоциирует её с тем элементом управления, на который мы перед этим кликнули правой кнопкой мыши. Далее впишите в поле «Имя» m_ctrlStaticText1 и нажмите кнопку «Готово». Благодаря этому в класс нашего «Диалогового окна» добавится весь необходимый код:

Нас устроят начальные значения, которые нам предлагает «Мастер…». С помощью control-переменной типа CStatic мы сможем в любой момент изменять текст элемента «Static Text». Забегая наперёд, скажу, что для элементов «Edit control» выбор параметров будет немного отличаться. Ну а пока, выберем следующий элемент «Static Text» и повторим для него всё то же самое, только в поле «Имя» впишем m_ctrlStaticText2.

Теперь нажмите правой кнопкой мыши по первому элементу «Edit control» и снова выберите пункт «Добавить переменную…». Но в этот раз в поле «Категория» установите Значение, в поле «Тип переменной» — int, а в «Имя» — m_nValue1 и нажмите «Готово». Таким образом, значение элемента «Edit control» будет храниться во внутренней переменной целочисленного типа, которую создал «Мастер…»:

Проделайте тоже самое и для второго элемента «Edit control», задав ему имя m_nValue2.

Теперь нам нужно добавить обработчик событий в класс кнопки «По умолчанию». Нужно кликнуть правой кнопкой мыши по этому элементу и выбрать «Добавить обработчик событий…»:

Тем самым откроется «Мастер обработчика событий», позволяющий создавать обработчик любого типа для всех ваших классов. У выбранной вами кнопки событием по умолчанию будет сообщение BN_CLICKED (т.е. «Нажата кнопка»). Затем просто нажмите «Добавить/Править» и вы тут же перенесётесь в файл OptionDialog.cpp к только что созданному обработчику:

Далее нам нужно будет переопределить функцию OnInitDialog(). В предыдущих уроках мы уже это проходили, поэтому я не буду повторяться:

Далее идёт приличное количество кода, автоматически сгенерированного средствами MFC, рассмотрение которого выходит за рамки этого туториала. Мы коснёмся лишь некоторых моментов. Для начала отредактируем файл OptionDialog.h:

Мы добавили ещё одну переменную в список аргументов конструктора, чтобы диалоговое окно можно было использовать с информацией, задаваемой как для строки/столбца, так и для ширины/высоты. Когда мы передаём true, то диалоговое окно запрашивает у пользователя информацию о количестве строк и столбцов на игровом поле. Если же мы передаём false, то запрашиваем ширину и высоту блоков на игровом поле.

Файл OptionDialog.cpp:

Первое, что мы делаем, это изменяем конструктор, чтобы он мог принимать ещё один аргумент типа bool, который будет указывать на то, какую форму диалогового окна нужно создать. Здесь ничего сложного нет. Следующее изменение, которое мы сделали — это сброс значений по умолчанию. Для строк/столбцов значения равны 15, а для ширины/высоты — 35. Затем, чтобы обновить элементы управления на новые значения, мы должны вызвать функцию UpdateData(), передав ей false в качестве аргумента. Данный аргумент является логическим флагом, указывающим направление обмена (из переменных в элементы управления или наоборот). Т.к. наша цель — это обновить элементы управления значениями, взятыми из переменных, то нужно передать false в качестве параметра.

Последнее, что нам остаётся сделать — это написать код для функции OnInitDialog(). Эта функция вызывается непосредственно перед отображением диалогового окна пользователю. В ней мы можем настроить нужные нам параметры. Для диалогового окна «Строки/Столбцы» мы устанавливаем заголовок «Обновить количество блоков» с помощью функции SetWindowText() и макроса _T(), который мы уже ранее рассматривали. Затем мы обновляем текст на «Строки» и «Столбцы» в элементах управления «Static text» с помощью функции с соответствующим данному элементу управления именем. Если же у нас диалоговое окно «Ширина/Высота», то мы изменяем заголовок окна и метки подобным образом, но уже применительно к данному варианту. Это все изменения, которые требовалось сделать в коде диалоговых окон. Теперь всё должно работать как нужно.

И наконец, наш последний шаг — настроить несколько обработчиков событий в представлении View для двух параметров меню с которыми мы работаем. Как обычно, сделаем это через «Окно свойств» класса SameGameView. Нажмите на кнопку «События», которая выглядит как молния, разверните параметр ID_SETUP_BLOCKCOUNT и добавьте обработчик событий COMMAND. Сделайте то же самое и с параметром ID_SETUP_BLOCKSIZE:

Нам не нужно будет вносить какие-либо изменения в заголовочный файл нашего представления View, кроме изменений, которые автоматически добавили два обработчика. Они приведены ниже:

Все основные изменения находятся в исходном файле представления View в SameGameView.cpp. Для того чтобы использовать наше созданное диалоговое окно, мы должны подключить соответствующий заголовочный файл в файл исходного кода представления View.

Файл SameGameView.cpp:

Далее идёт код двух обработчиков событий, которые мы добавили в прошлый раз. Обе эти функции, по сути, являются одинаковыми, за исключением нескольких моментов:

Как и до этого, сначала мы получаем указатель на Document. Затем мы создаём диалоговое окно путём создания экземпляра данного класса. В первую функцию OnSetupBlockcount() мы передаём параметр true, а во вторую — false. Мы уже обсуждали этот момент.

Затем мы задаём целочисленные значения для m_nValue1 и m_nValue2 строк/столбцов (для первой функции) и ширины/высоты (для второй функции). Устанавливая эти значения перед вызовом функции DoModal(), мы гарантируем, что они с самого начала будут находиться в соответствующих элементах управления.

Следующая строка — это то место, где фактически отображается диалоговое окно при помощи функции DoModal(). При этом окно блокирует управление, пока пользователь не нажмёт одну из кнопок: «OK», «Отмена» или «X», чтобы закрыть окно. Затем функция возвращает значение, зависящее от того, каким образом пользователь закрыл окно: если через нажатие на кнопку «OK», то мы сравниваем возвращаемое значение с IDOK. Но перед этим, мы должны удалить старую игровую доску и освободить память. Как только это будет сделано, можно использовать наши сеттеры для сохранения тех значений, которые указал пользователь.

Как только они будут установлены в классах Document и игрового поля, нам нужно будет создать новую игровую доску, вызвав SetupBoard(). В заключении, мы изменяем размер окна, чтобы соответствовать новому количеству строк/столбцов или новому размеру блока.

Ваша игра теперь должна выглядеть примерно следующим образом:

Заключение


Разработка нашей игры близится к завершению. Мы прошли очень долгий путь и уже почти пришли к финишу. В этом уроке мы создали «Диалоговое окно» для того, чтобы иметь возможность запрашивать у пользователя дополнительную информацию о настройках игры. Эта кастомизация позволяет пользователю получить новые впечатления от процесса игры. На каком уровне вы можете полностью очистить игровое поле из пяти строк и пяти столбцов? Есть много комбинаций параметров, которые могут изменить сложность игры и заставить вас поменять свою стратегию. Вот что делает игру по-настоящему увлекательной, мотивируя перепроходить её раз за разом, придумывая и руководствуясь новыми стратегиями.

Урок №8. Исходный код игры «SameGame» на С++

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (3 оценок, среднее: 4,67 из 5)
Загрузка...

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *