Урок №3: Отрисовка игры «SameGame» на C++/MFC

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

  Обновл. 27 Окт 2020  | 

 8425

 ǀ   7 

На предыдущем уроке мы занимались частью Document архитектуры «Document/View», на этом же уроке мы займемся частью View, начиная отрисовку нашей игры.

The View: Отрисовка игры SameGame

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

Первым шагом является добавление кода для изменения параметров окна до нужного размера. Сейчас окно имеет размер, заданный по умолчанию, что не является тем, что нам нужно. Мы исправим это в переопределяемом методе OnInitialUpdate(). Класс View наследует базовый метод OnInitialUpdate(), который задает представление нашего документа, и мы должны переопределить этот метод, чтобы получить возможность изменять размеры окна. Для того чтобы это реализовать, нам нужно открыть окно свойств заголовочного файла CSameGameView (который фактически будет называться SameGameView.h): для этого нажмите Alt+Enter или в меню "Вид" > "Окно свойств" (в других версиях Visual Studio может быть следующее: "Вид" > "Другие окна" > "Окно свойств"). Найдите опцию OnInitialUpdate и выберите <Add> OnInitialUpdate как показано на скриншоте ниже:

Тем самым мы добавим переопределенный метод OnInitialUpdate() к нашему View с небольшим содержанием по умолчанию для вызова функции ResizeWindow(). Таким образом, заголовочный файл SameGameView.h будет иметь следующий вид:

Помимо этого, нам также нужно будет добавить код отрисовки в класс CSameGameView. Заголовочные и исходные файлы для View уже содержат переопределение функции OnDraw(). Здесь мы и поместим наш код. Ниже приведен полный исходный код для SameGameView.cpp:

Нарисовать игровую доску очень просто, мы будем перебирать каждую строку, столбец за столбцом и рисовать цветной прямоугольник. У функции OnDraw() есть один аргумент — указатель на CDC. Класс CDC является базовым классом для всех контекстов устройства. Контекст устройства — это обобщённый интерфейс устройства вывода, такого как экран или принтер.

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

Затем нам нужно покрасить фон клиентской области в черный цвет. Для этого нам нужно получить размеры клиентской области — вызываем GetClientRect(). Вызов GetBoardSpace(-1,-1) в Document возвратит цвет фона, а FillSolidRect() заполнит клиентскую область фоновым цветом.

Теперь пришло время нарисовать отдельные прямоугольники. Для этого нам нужно сначала нарисовать цветной прямоугольник, а затем обвести его черным контуром. Нам нужно создать объект кисти, чтобы сделать контур. Кисть HOLLOW_BRUSH, которую мы создаем, называется hollow (в переводе «пустой»), потому что, когда мы рисуем прямоугольник, MFC захочет заполнить его внутренность каким-нибудь цветом. Мы не хотим этого, поэтому будем использовать HOLLOW_BRUSH. Создание кисти приводит к выделению GDI-памяти, которую позднее нам нужно будет очистить.

Вложенные циклы for очень просты, они перебирают строку за строкой, столбец за столбцом, получая цвет соответствующего пространства доски из Document с помощью функции GetBoardSpace(), вычисляя размер прямоугольника, который нужно закрасить, а затем выполняется сам процесс закрашивания блока. При отрисовке используются два метода:

   метод FillSolidRect() — для заполнения цветной части блока;

   метод Rectangle() — для рисования контура блока.

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

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

Наконец, функция GetParentFrame() возвращает указатель на класс CMainFrame, который является фактическим окном нашей игры, и мы изменяем размер окна, вызывая MoveWindow().

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

Заключение


На этом уроке мы рассмотрели некоторые основы MFC и архитектуру «Document/View». Мы собрали объект игрового поля, который содержит наши данные, и создали представление, которое отображает эти данные пользователю. На следующих уроках мы рассмотрим обработку событий.

  GitHub / Исходный код — Урок №3: Отрисовка игры «SameGame» на C++/MFC

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

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

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

  1. Аватар Юрий(не автор):

    У меня не выводится окно "Переопределения" в свойствах представления класса. С чем это может быть связано?

      1. Аватар Юрий(не автор):

        Добавил в ручную в определение класса. Теперь работает.

  2. Аватар Дмитрий:

    При выборе SameGameView.h в окне свойств не отображаются события для выбора.

    Не могу понять в чем проблема и почему не отображаются свойства.
    Можете помочь?

    https://i.imgur.com/8RgTUIa.png

    1. Дмитрий Бушуев Дмитрий Бушуев:

      У вас на скриншоте слева (где куча разных заголовочных файлов) — окно "Обозреватель решений". Это не то окно.
      Нужно открыть окно "Представление Классов" (можно сделать через меню Вид->Классы). Откроется окно "Представление Классов" (как на самой первой картинке в статье). Далее щелкаете правой кнопкой мыши на CSameGameView и выбираете "Свойства".

      Вот картинка для наглядности:
      https://imgur.com/a/tUfRZLg

      1. Аватар Дмитрий:

        Премного благодарен, Дмитрий!

        1. Дмитрий Бушуев Дмитрий Бушуев:

          Всегда пожалуйста 🙂

Добавить комментарий для Дмитрий Отменить ответ

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