Технология разработки визуальных кроссплатформенных приложений с использованием фреймворка Qt на примере программы “Snake”

В современном мире, очень важно поддерживать работу приложения на разнообразных платформах. Типичным примером является программное обеспечение, предназначенное для работы в операционных системах Linux и Windows одновременно. Qt — является отличным фреймворком, который позволяет создавать визуальные, кроссплатформенные приложения.

Актуальность кроссплатформенности в игровой индустрии успешно доказывает опыт американской компании Valve, получившая тотальную известность, выпустив крайне успешную и хорошо принятую критиками игру Half-Life.В настоящее время для разработчика крайне важно поддерживать множество операционных систем для работы приложения. Кроссплатформенность распространяется практически на каждую it-структуру, начиная от кроссплатформенных языков программирования, таких как c, c++, Pascal, заканчивая кроссплатформенными средами исполнения и пользовательскими интерфейсами. Всем известная OpenGL – открытая графическая библиотека, определяющая платформо-независимый программный интерфейс для написания приложений, использующих двумерную и трёхмерную компьютерную графику, которая также используется в данном проекте, наглядный пример успеха платформонезависимого продукта. Qt – кроссплатформенный инструментарий разработки ПО на языке программирования C++, именно он станет нашим главным «другом» на момент написания проекта, так и в дальнейшей перспективе разработки приложений. Из всего вышесказанного становится ясной актуальность кроссплатформенных приложений. Получение опыта разработки таких приложений и наглядное демонстрация всей «мощи» кроссплатформенного инструментария и составляет тему данной работы.

Объект исследования: одно из направлений программирования – кроссплатформенная разработка приложений.

Предмет исследования: практическое применение принципов разработки кроссплатформенных, визуальных приложений.

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

Задачи:

  1. Изучить актуальность кроссплатформенных приложений.
  2. Разобраться с принципами работы фреймоврка Qt .
  3. Ознакомиться с графическим api OpenGL.
  4. Погрузиться в проектирование пользовательского интерфейса для приложения.
  5. Освоить основные принципы работы с языком запросов SQL,на примере работы с MySQL.
  6. Получить опыт работы с современным средством контроля версий Git, на примере работы с GitHub.
  7. «Поднять» и настроить сервер на FreeBSD.
  8. Разработать программный и пользовательский интерфейс программы.
  9. Создать дистрибутив данной программы и распространить его.

Используемое ПО

Фреймворк Qt

D:\work\Projects\Qt-logo.pngВ процессе подготовки программы для демонстрации возможностей кроссплатформенного программирования и получения опыта программирования визуальных приложений, мы решили использовать фреймворк Qt .

Почему стоит использовать Qt?

Qt предоставляет программисту не только удобный набор библиотек классов, но и определённую модель разработки приложений, определённый каркас их структуры. Следование принципам и правилам «хорошего стиля программирования на C++/ Qt » существенно снижает частоту таких трудно отлавливаемых ошибок в приложениях как утечки памяти (memoryleaks), необработанные исключения, незакрытые файлы или неосвобождённые дескрипторы ресурсных объектов, чем нередко страдают программы, написанные «на голом C++» без использования библиотеки Qt .

У данного фреймворка имеется ряд преимуществ, из-за которых он и был выбран в качестве главного «наставника» в написании проекта.

Следует отменить несколько из них:

  1. Кроссплатформенный инструментарий разработки программного (далее – ПО) обеспечения на языке программирования C++.
  2. Несколько видов лицензии распространения ПО, в том числе и бесплатной.
  3. Использование MetaObjectCompiler (MOC) — предварительной системы обработки исходного кода (в общем-то, Qt — это библиотека не для чистого C++, а для его особого наречия, с которого и «переводит» MOC для последующей компиляции любым стандартным C++ компилятором).
  4. Поддержка множества языков программирования, таких как:
    1. C++
    2. PySide
    3. Python– Py Qt
    4. Ruby – Qt Ruby
    5. Java – Qt Jambi
    6. PHP –PHP- Qt
  5. Хорошо продуманный, логичный и стройный набор классов, предоставляющий программисту очень высокий уровень абстракции. Благодаря этому программистам, использующим Qt , приходится писать значительно меньше кода, чем это имеет место при использовании, например, библиотеки классов MFC. Сам же код выглядит стройнее и проще, логичнее и понятнее, чем аналогичный по функциональности код MFC или код, написанный с использованием «родного» для X11 тулкита Xt. Его легче поддерживать и развивать.

Знакомство с OpenGL

D:\work\Projects\opengl_0.jpgТак как мы будем разрабатывать платформо-независимую программу, наш выбор пал именно на OpenGL.

Данная графическая библиотека включает в себя более 250 функций для рисования сложных трёхмерных сцен из простых примитивов.

В основном используется при создании компьютерных игр, САПР (Система автоматизированного проектирования), виртуальной реальности, визуализации в научных исследованиях.

Стандарт OpenGL, с появлением новых технологий, позволяет отдельным производителям добавлять в библиотеку функциональность через механизм расширений. Расширения распространяются с помощью двух составляющих: заголовочный файл, в котором находятся прототипы новых функций и констант, а также драйвер устройства, поставляемого разработчиком. Каждый производитель имеет аббревиатуру, которая используется при именовании его новых функций и констант. Например, компания NVIDIA имеет аббревиатуру NV, которая используется при именовании её новых функций, как, например,glCombinerParameterfvNV(), а также констант, GL_NORMAL_MAP_NV. Может случиться так, что определённое расширение могут реализовать несколько производителей. В этом случае используется аббревиатура EXT. В случае же, когда расширение одобряется консорциумом ARB, оно приобретает аббревиатуру ARB и становится стандартным расширением. Обычно расширения, одобренные консорциумом, включаются в одну из следующих спецификаций OpenGL.

«Змейка»: создание и особенности реализации

D:\work\Projects\build\icon - копия.jpgВ рамках проекта была разработана программа «Змейка» для демонстрации преимуществ кроссплатформенного фреймворка Qt и графической библиотеки OpenGL; я не ставил перед собой задачу написать программу, которая «взорвёт» рынок, главным было получить практический опыт разработки кроссплатформенных приложений и усовершенствовать свои навыки реального программирования.

Пользовательский интерфейс программы предполагал таблицу рейтингов, настройки приложения и саму игру.

Программный интерфейс включал в себя элегантный и переносимый код возможность поддержки, которого реализована с помощью GitHub’a.

В конечном итоге получился достаточно неплохой готовый продукт. Далее рассмотрим его более подробно.

Пользовательский интерфейс

При проектировании пользовательского интерфейса мы выделили несколько пунктов, которые должна содержать наша программа:

  • Настройки
  • Таблица рейтингов
  • Авторизация
  • Игра

Опираясь на данные пункты, мы сделали первичный интерфейс с помощью Qt Designer.

Программный интерфейс

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

  • Главное окно
  • Окно настроек
  • Окно регистрации/авторизации
  • Виджет игры
  • Логирование
  • Настройки (управление файлом, структурой)
  • База данных
  • Логика игры

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

Git или система контроля версий

Так как количество строк кода нашего проекта зашкаливает за 1.000, было принято решение систематизировать поддержку кода, для этого мы используем GitHub.

GitHub — самый крупный веб-сервис для хостинга IT-проектов и их совместной разработки.

Сервис абсолютно бесплатен для проектов с открытым исходным кодом (каким мы и являемся) и предоставляет им все возможности, а для частных проектов предлагаются различные платные тарифные планы.

Данный сервис очень упростил поддержку объёмного кода, в некоторых ситуация даже спасал, когда неожиданно накрылся один из винчестеров на котором разрабатывался проект.

Адрес нашего проекта на githubURL: https://github.com/KostyaKulakov/Snake-Game

Для более наглядной демонстрации возможностей github, прилагаю несколько иллюстраций.

Подготовка и настройка сервера на FreeBSD

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

Для начала мы выкупили виртуальный сервер у хостера firstvds, процесс оказался довольно не сложный, в связи с тем, что я имел опыт работы с данным хостером и «возведением» серверов/баз данных.

Для начала к «новоиспечённому» серверу нужно было как-то подключаться, для данной цели мы выбрали, PuTTY — свободно распространяемый клиент для различных протоколов удалённого доступа, включая SSH, который нам и был нужен.

Далее нам нужно установить MySQL сервер, для этого мы использовали документацию из доверенных источников (ссылка прилагается в списке литературы), предварительно обновив порты (список пакетов).

После возведения MySQL сервера, нужно было настроить права доступа.

Как и любой толковый сисадмин, я решил ограничить подключения для всех пользователей кроме того, что был создан для подключения программно по ip.

Над именем пользователя для программы мы особо не задумывались, по этому, было решено назвать его «programm».

Из соображений безопасности данный пользователь имел доступ только к базе данных рекордов, о который мы ниже поговорим.

После долгой настройки мы перешли к процессу созданию самой базы, о которой в следующей главе и пойдёт речь.

Для администрирования базы данных был выбран MySQL клиент – Navicat.

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

Для данной цели было решено создать 2 таблицы:

  • Account – Таблица содержащая информацию о пользователях
  • Record – Таблица содержащая информацию о достижениях пользователей

В таблице аккаунтов было решено хранить:

  • Id – Уникальный номер записи в таблице
  • Name – Уникальное имя аккаунта
  • Password – Пароль аккаунта (пароль из соображений безопасности хранятся в md5)

Прилагаю иллюстрацию структур таблиц:

Account:

Record:

Из данных иллюстраций ясно видна связь таблицы рекордов и таблицы аккаунтов.

Под «капотом» (интересные моменты кода программы)

1. Главное окно

Разберём самые интересные моменты кода основного окна.

Как было сказано раньше – Qt очень упрощает жизнь программисту, сейчас мы поймём почему.

Для того чтобы связать элементы между собой, в нашем случае кнопки, в Qt используется механизм сигналов и слотов.

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

В данном случае, мы используем «говорящие» названия объектов кнопок, это упрощает восприятие кода.

Разберём пример с кнопкой выхода.

В функции connect, мы передаём первый аргумент – объект, от которого ждём сигнал, далее объект, у которого вызывается слот.

Передаём объект – кнопку выхода, сигнал – нажатие на неё, объект у которого вызывается слот – текущее окно и наконец, сам слот – это закрытие приложения.

Как было сказано ранее, мы можем добавлять свои слоты.

Во втором случае так и сделано, мы ожиданием клик, от кнопки настроек, и вызываем слот (функцию) из текущего класса.

При этом мы должны объявить данный слот:

После объявления следует описать его.

Мы разобрались с сигналами и слотами.

Рассмотрим структуру класса главного окна:

В арсенале класса имеются:

  • Конструктор, принимающий в виде аргумента родительский виджет.
  • Деструктор.
  • Функция изменения размера окна, которая вызывается при любом изменении главного окна
  • Функция-слот opensettings, функция создания/вызова окна настроек.
  • Функция-слот openrecords, функция создания/вызова окна рекордов.
  • Функция-слот openregistration, функция создания/вызова окна регистрации/авторизации.
  • Функция-слот installsizepolice, функцияфиксации размеров окна на момент начала игры.

Разберём каждый элемент:

  1. Конструктор

В данной функции, мы инициализируем систему взаимодействия с базой данных и устанавливаем подключения с сервером.

Далее, как мы и планировали, передаём информацию об объекте управления базой данных в виджет игры, для взаимодействия с очками.

Последующие действия устанавливают действия для кнопок, несколько из них мы уже разобрали.

  1. Деструктор

Здесь всё проще, мы освобождаем память из-под объектов управления базой данных и графического оформления приложения.

  1. Функция изменения размера окна

Первая и успешно решённая проблема, с которой мы столкнулись: мы используем для движения змейки шаг в 10 пикселей, нам нужно ровное кол-во клеток в сетке:

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

Числа 103 и 22, это сдвиг от области главного окна к виджету игры.

  1. Функция создания/вызова окна настроек

Для начала мы инициализируем само окно (объект окна), заодно передадим ему настройки приложения.

Далее функция exec поставит фокус на данное окно и отобразит его.

После закрытие окна, управление опять передаётся в основное окно, и мы успешно устанавливаем фокус на виджет с игрой.

  1. Функция создания/вызова окна рекордов

Всё аналогично предыдущему случаю, мы создаём объект окна и передаём в качестве аргумента указатель на наш объект управления базой данных.

  1. Функция создания/вызова окна регистрации/авторизации

Инициализации объекта окна, передача настроек приложения и базы данных.

2. Настройки. Один из методов работы с конфигурационными файлами

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

Для начала обратимся к структуре нашего класса:

Перейдём непосредственно к описанию каждой функции

  1. Конструктор

Для начала мы инициализируем объект класса QSettingsfsettings, передав ему имя файла с настройками и его формат.

QVariant  QSettings::value ( const QString & key, const QVariant & defaultValue = QVariant() ) const

Возвращает значение для настройки key. Если настройка не существует, то возвращает значение по умолчанию defaultValue.

Если файл настроек содержит значения параметров, то они будут записаны в переменные, в противном случае, будут записанные те, которые мы указали как defaultValue.

  1. Установка режима отображения количества кадров в секунду

void Settings::setValue ( const QString & key, const QVariant & value )

Устанавливает значение настройки key в значение value. Если key уже существует, то предыдущее значение перезаписывается.

void QSettings::sync ()

Записывает любые несохранённые данные в постоянное хранилище и перезагружает любые настройки, которые были к тому времени изменены другим приложением.

  1. Установка режима проигрывания звуков

Выполняются аналогичные действия пункту 2.

  1. Установка режима отображения матрицы

Матрицу, про которую идёт речь, мы уже видели в предыдущем разделе в пункте «Функция изменения размера окна».

  1. Установка имени аккаунта

В данной функции происходит сохранение имени пользователя.

  1. Установка пароля

Следует заметить, что пароль сохраняется в зашифрованном виде (md5).

  1. Установка статуса авторизации

Данный параметр помогает нам понять, прошёл ли пользователь авторизацию.

  1. Получения статуса отображения количества кадров в секунду

Функция возвращает статус отображения fpsво время работы приложения.

  1. Получения статуса проигрывания звуков

На основе возвращённого ответа функции, мы можем сделать вывод, проигрывать ли звук.

  1. Получения статуса режима отображения матрицы

На основе возвращённого ответа функции, мы можем сделать вывод, нужно ли отображать матрицу/сетку во время работы приложения.

  1. Получения имени пользователя

Функция возвращает имя пользователя, которые мы можем использовать в дальнейших целях.

  1. Получения md5 пароля

Функция возвращает зашифрованный пароль пользователя.

  1. Получения статуса авторизации пользователя

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

Именно так выглядит работа простого механизма изнутри.

Иллюстрация конфигурационного файла:

[db]

login=Graf

[email protected](c18bd005a3e26db22dccf373e32bff86)

auth=true

[snake_interface]

is_showfps=false

is_playsound=false

is_showmatrix=true

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

3. Окно настроек

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

Со стороны пользователя все, кажется «лёгко», именно так оно и будет, если мы используем Qt .

Рассмотрим класс окна:

Именно правильный программный интерфейс и каноническая реализация даёт простой и понятный код.

  1. Конструктор

Для начала нам нужно проинициализировать объект класса настроек. Далее мы установим на чекбоксы значения аргументов из настроек. После нажатие на кнопку «ОК» мы сохраняем настройки.

  1. Сохранение настроек

Всё просто. Мы сохраняем значения изчекбоксов в настройки.

Именно на данном примере явно видны преимущества использования Qt .

4. База Данных

Система управления базами данных (СУБД) — совокупность программных и лингвистических средств общего или специального назначения, обеспечивающих управление созданием и использованием баз данных.

Qt дает возможность создания платформо-независимых приложений для работы с базами данных, используя стандартные СУБД. Qt включает «родные» драйвера для Oracle, Microsoft SQL Server, Sybase Adaptive Server, IBM DB2, PostgreSQL, MySQL и ODBC-совместимых баз данных. Qt включает специфичные для баз данных виджеты, а также поддерживает расширение для работы с базами данных любых встроенных или отдельно написанных виджетов.

Работа с базами данных в Qt происходит на различных уровнях:

1.Слой драйверов — Включает классы QSqlDriver, QSqlDriverCreator, QSqlDriverCreatorBase, QSqlDriverPlugin и QSqlResult. Этот слой предоставляет низкоуровневый мост между определенными базами данных и слоем SQL API.

2.Слой SQL API — Этот слой предоставляет доступ к базам данных. Соединения устанавливаются с помощью класса QSqlDatabase. Взаимодействие с базой данных осуществляется с помощью класса QSqlQuery. В дополнение к классам QSqlDatabase и QSqlQuery слой SQL API опирается на классы QSqlError, QSqlField, QSqlIndex и QsqlRecord.

3.Слой пользовательского интерфейса — Этот слой связывает данные из базы данных с дата-ориентированнымивиджетами. Сюда входят такие классы, как QSqlQueryModel, QSqlTableModelи QSqlRelationalTableModel.

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

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

Этого достаточно.

Рассмотрим структуру СУБД:

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

Пояснение: Во время написание конкурсной работы было решено, не скрывать части данных для соблюдения безопасности работы сервера.

Заглянем под «капот» субд.

  1. Конструктор

На данном этапе мы указываем, какой из драйверов использовать, в нашем случае QMYSQL.

Далее указываем данные для подключения к базе данных.

  1. Функция подключения к базе данных

Изначально мы вызываем функцию open, которая возвращает статус, успешно ли произведено подключение.

В случае неуспешного подключения, будет выведена причина неудачного подключения.

  1. Функция отключения от базы данных

В функции удаляется глобальное подключение объекта к базе данных. Далее закрывается подключение к базе данных.

  1. Функция создания аккаунта для пользователя (API)

Для начала нам нужно проверить, имеется ли уже такой аккаунт, если имеется, то прекратить регистрацию.

QsqlQuery — набор средств управления выражениями SQL и их выполнения.

Укажем базу данных, которую мы будем использовать, в нашем случае db.

Далее нам нужно создать запрос.

Данный запрос выполнит вставку в таблицу account запись с указанным именем и зашифрованным паролем.

Скорее всего, вы заметили, что в запросе мы не указали имя и пароль, а поставили:name и password. Данные выражения будут заменены на переменные, которые мы указываем ниже. Имя остаётся без изменения. Пароль преобразуется из нормального вида в md5.

Далее мы выполняем данный запрос, если запрос выполнен успешно, мы добавляем игрока в таблицу рекордов, в противном случае выдаём ошибку.

  1. Авторизация пользователя (API)

Данная функция возвращает true – в случае успешной авторизации, false–в противном случае.

Данная функция предоставляется в двух экземплярах, 1 для работы с зашифрованным паролем и 2 для работы с не зашифрованным паролем.

В функции мы создаём запрос и ищем пользователя, так, как мы указали явно вывести нам либо одну запись, либо ничего. Мы получим либо 1 запись, либо 0. Только в случае полного совпадения логина и пароля мы получим запись. Поэтому количество записей можно использовать, как возвращающееся значение.

  1. Установка кол-во набранных очков (API)

Данная функция, по имени пользователя, обновляет его количество набранных очков.

Также мы используем значение bool (newacc), при создание нового аккаунта, мы не обновляем, а добавляем запись в таблицу.

  1. Проверка на занятость аккаунта (API)

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

  1. Получение уникального идентификатора пользователя по имени аккаунта (API)

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

  1. Получение имени аккаунта по уникальному идентификатору

В данной функции мы получаем имя аккаунта, по уникальному идентификатору.

  1. Получения записи из таблицы рекордов по уникальному идентификатору

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

  1. Получения списка рекордов всех участников игры «Змейка» в порядке убывания (API)

Данная функция возвращает вектор структур записей о рекордах.

В запросе присутствует ключевое слово DESC, которое устанавливает порядок вывода (убывание/возрастание).

В данном разделе мы полностью рассмотрели СУБД программы. Ознакомились с основами языкаSQL, поняли принцип работы с бд в Qt . В следующих разделах мы будем активно использовать рассмотренную СУБД.

5. Таблица рекордов

Неотъемлемая часть спортивного интереса – это таблица рекордов. Практически ни одна игра не обходится без данной функции.

На настоящий момент программа была уже опробована несколькими людьми.

Описание класса:

  1. Конструктор

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

В цикле мы создаём новую запись в таблице и заполняем её данными из вектора.

6. Виджет игры «Змейка»

Данный виджет выполняет основную роль – рисования.

Виджет содержит в себе настройки приложения, змейку, базу и пару таймеров (для чего, скоро поймём).

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

Наш виджет унаследован от QGLWidget.

Укажем несколько особенностей используемого виджета:

QGLWidget так устроен, что при первой инициализации класса он автоматически вызывает методы в следующем порядке:

При запуске: initializeGL()->resizeGL()->paintGL()

При изменении размера окна: resizeGL()->paintGL()

updateGL() вызывает paintGL()

initializeGL — необходимо использовать для глобальных настрое построения изображения, которые нет необходимости указывать при построении кадра.

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

paintGL — этот метод будет выстраивать каждый наш кадр для отображения.

Для хранения размеров виджета нам понадобятся пару переменных, также нам нужны будут переменные для хранения текущего количества кадров(fps) и количества набранных очков, также нужно хранить шаг для сетки и системные состояния, к примеру, о начале игре или о нажатии клавиш.

Рассмотрим класс виджета:

Сейчас более подробно рассмотрим каждый из методов класса.

  1. Конструктор

В первую очередь мы принимаем СУБД, далее создаём объект настроек приложения, устанавливаем интервал для случайных значений и двойную буферизацию (двойная буферизация позволяет более корректно заменять изображение, чтобы не происходили скачки на экране: PaintGL сразу картинку не рисует на экран, а заносит в буфер, а по запросу swapBuffers() заменяет текущее изображение на то, что появилось в буфере).

На следующем этапе мы устанавливаем таймера, первый таймер, для обновления виджета, а второй — для змейки.

  1. Запуск игры (Slots)

В данной функции мы

Обнуляем кол-во набранных очков,

Создаём новый экземпляр змейки.

Устанавливаем границы поля.

Устанавливаем состояние игры.

И убираем логотип игры.

Устанавливаем фокус на нашу змейку

Создаём еду

И запускаем таймер.

  1. Окончание игры (Slots)

Так как змейка погибает, мы проигрываем звук поражения.

Устанавливаем состояние игры на false, при этом состояние о поражении переводим в true.

Только после данных действий, мы останавливаем таймер змейки и удаляем её экземпляр.

Дальше мы проверяем, авторизирован ли игрок, если да, то проверяем рекорд, если он превзошёл свой рекорд, то обновляем его и показываем поздравление.

  1. Изменение размера виджета (Event)

Данная функция вызывается при изменении размера окна, из-за которого меняется размер виджета.

На время изменения размера, мы устанавливаем режим матрицы проекции.

Далее загружаем матрицу.

Изменяем область вывода изображения.

Запоминаем новые размеры виджета.

Посылаем змейке запрос на изменение размера поля.

  1. Функция обработки нажатий клавиш (Event)

В данной функции мы перехватываем нажатие и выполняем нужное действие, в нашей программе мы изменяем направления движения главной змейки.

Также по нажатию клавиши Escape, игры завершается.

  1. Функция, возвращающая настройки программы

Функция возвращает указатель на настройки приложения.

  1. Функция инициализации настроек OpenGL

В данном методе мы устанавливаем чёрный цвет очистки экрана.

  1. Функция состояния игры

Функция возвращает состояние игры.

  1. Функция подсчёта кол-во кадров в секунду (FPS)

В данной функции мы высчитываем кол-во кадров. Мы смотрим если время в секундах сейчас больше, чем было в прошлый раз, что сохраняем значение кадров.

Если оно не изменялось, то увеличиваем кол-во кадров (секунда не прошла)

  1. Функция рисования интерфейса

Первым делом, выбираем цвет рисования, т.к. линия у нас должна быть белой, мы устанавливаем белый цвет.

Далее нам нужно нарисовать линию от одного края к другому, для этого мы вычисляем нужные значения и рисуем их.

Также нужно вывести кол-во набранных очков, для этого воспользуемся методом Qt , и выведем его.

Получим из настроек состояние отображения fps, если нужно выведем кол-во fps.

  1. Функция рисования сетки

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

При этом по горизонтали от низа мы делаем отступ интерфейса.

  1. Основная функция рисования paintGL (Event)

Для начала мы установим буфер глубины и буфер цвета.

Далее установим матрицу проекции и включим её.

Определим координатную систему с помощью glOrtho, в нашем случае начало координат будет в правом верхнем углу.

Проверяем, если состояние игры положительное, то рисуем змею и еду, в противном случае проверяем, нужно ли показывать логотип, если нет, то смотрим, погибла ли наша змейка, если да, то выведем, сколько очков мы набрали. Далее смотрим по настройкам, если есть указание рисовать матрицу, рисуем её, также поступаем и с подсчётом fps. В любом случае рисуем интерфейс.

  1. Функция действий змейки

В данной функции, происходит взаимодействие с самой змейкой, основное действие — это её движение.

Далее мы проверяем, не столкнулась ли змейка, ни с кем из своих звеньев.

Потом идёт проверка на, то, находится ли голова на клетке с едой, если да, то проигрываем музыку поедания фрукта и добавляем одно звено, если это был «Мега» фрукт, то вычисляем очки по специальной формуле.

На этом можно закончить разбор рисования, дальше мы обсудим логику самой змейки.

7. Логика «Змейки»

В этой главе было решено объединить 2 класса, это класс, самой змейки и класс её звеньев.

Приступим к заключительной части категории «Под капотом».

Рассмотрим 2 класса:

  1. Рисование змейки

В функции рисования, мы пробегаемся по массиву звеньев и рисуем каждое из них

  1. Рисование еды

В данном методе, мы смотрим, является ли данная еда «мега», если да, то устанавливаем зелёный цвет, для рисования.

Далее мы рисуем квадрат в пределах заданных координат.

  1. Установка размеров поля

В данной функции, мы устанавливаем данное значение для каждого звена и запоминаем его для себя.

  1. Добавление звена

Данная функция используется для прикрепления нового звена к змейке. Она использует алгоритм расчёта последней клетки, последнего звена и на её место ставит текущее (новое) звено. Также для него оно устанавливает идентичное направление.

  1. Изменение направления движения змейки

Для начала нам нужно узнать, можно ли изменить направление и готово ли звено его принять. Только после этого мы можем установить значение.

Далее используем очень хитрый алгоритм. Когда звено доходит до определённых координат оно меняет направление. Данная процедура повторяется для каждого звена.

  1. Конструктор змейки

Первым делом мы инициализируем музыку. Далее мы создаём «голову» звено и ставим ему направление движения.

  1. Автоматическое движение змейки

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

  1. Проверка столкновений

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

  1. Генерация еды

Метод генерирует в случайной точке еду, по достижении пяти «простых» поеданий еды, генератор генерирует специальную «мега» еду, которая даёт больше очков.

Также мы используем алгоритм, который не даёт вылезти еде за края поля.

Имеет место и проверка, не оказалась ли еда в звене или в том же самом месте.

  1. Проверка на столкновение с едой

Метод проверяет, не столкнулась ли голова с едой.

  1. Воспроизведение звуков

В данных методов вызывается метод play, который проигрывает музыку.

  1. Конструктор звена

В конструкторе происходит присваивание локальным переменным значения аргументов. Координаты и направление движения.

  1. Рисование звена

Похожий пример, мы уже разбирали, когда говорили о рисовании еды. В данном случае всё идентично.

  1. Передвижение звена

Данные функции отвечают за передвижение звена, в них происходит изменение значения координат и проверка на выход за пределы поля.

  1. Изменение направления движения с учётом координат

Выполняется проверка, нужно ли изменить направление движения на текущих координатах.

  1. Проверка выхода за поля

Дистрибутив игры

В качестве ПО для создания дистрибутива был выбран SmartInstallMarker.

С помощью данной программы мы с лёгкость смогли создать полноценный дистрибутив игры.

Заключение

Задачи, поставленные в начале работы над проектом, выполнены, цель доcтигнута. Исходный код представлен в git репозитории.

Литература

  1. Standard C++ Library reference URL: http://cplusplus.com/reference/ Время доступа: 19.01.14
  2. Qt Documentation URL: http://doc.qt.digia.com/ Время доступа: 20.01.14
  3. OpenGL 4 Reference URL: http://opengl.org/sdk/docs/man/ Время доступа: 20.01.14
  4. Koenig A. Accelerated C++.-2002
  5. Lafore R/ Object-Oriented Programming in C++.-2011

4 Комментарии “Технология разработки визуальных кроссплатформенных приложений с использованием фреймворка Qt на примере программы “Snake”

  1. На раскрыта тема «кроссплатформенных приложений» указанная в заголовке. Все остальное (почти) туфта. Зачем упоминание про термины типа СУБД? Или это академическая статья включая тексты из википедии? 🙂
    При чем тут FreeBSD вообще? Частный субъективный случай реализации задачи взаимосвязи игроков и только.

    1. СУБД использовалось для примера работы с базой данных, статья писалась как научная работа в 10 классе

  2. Код не линкуется, хотя компилится.
    F:\PROJECTS8\build-snake-Desktop_Qt_5_7_0_MinGW_32bit-Debug\debug\glwidget.o:-1: In function ZN8GLWidgetC2EP7QWidgetP8DataBase':
    F:\PROJECTS8\Snake-Game\src\glwidget.cpp:12: error: undefined reference to
    [email protected]

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

Ваш e-mail не будет опубликован.