Evgenii Legotckoi
Evgenii Legotckoi23 сентября 2015 г. 11:00

Как написать игру на Qt - Урок 5. Добавляем звук с QMediaPlayer

Приступаем к пятому и заключительному уроку по написанию игры на Qt, в котором добавим звук с помощью класса QMediaPlayer . Предлагаю добавить три вида звуков: Поедание яблок, жужжание Мухи , которая будет жужжать при передвижении и душераздирающий вопль, когда Муху съедят.

Звук в структуре проекта

Звук в структуре проекта помещается в файл ресурсов, как показано на скриншоте структуры проекта.

Для этого создаём папку resource и в ней папку game. Далее в папке resources создаём файл ресурсов, в котором прописываем префикс "/" и добавляем аудио файлы, которые предварительно поместили в папку game.

А далее звуки необходимо подключить к проекту с использованием класса QMediaPlayer.

В данном случае звуки подключаются в трёх местах программного кода.


triangle.h

В заголовочном файле необходимо подключить библиотеки классов QMediaPlayer и QMediaPlaylist. А также объявить по объекту этих классов.

#ifndef TRIANGLE_H
#define TRIANGLE_H

#include <QObject>
#include <QGraphicsItem>
#include <QPainter>
#include <QGraphicsScene>
#include <QMediaPlayer>
#include <QMediaPlaylist>

/** Подключаем библиотеку, отвечающую за использование WinAPI
 * Данная библиотека необходима для асинхронной проверки состояния клавиш
 * */
#include <windows.h>

class Triangle : public QObject, public QGraphicsItem
{
    Q_OBJECT
public:
    explicit Triangle(QObject *parent = 0);
    ~Triangle();

    // Программный код из прошлых уроков

    QMediaPlayer * m_player;        // Аудио плеер
    QMediaPlaylist * m_playlist;    // Плейлист

};

#endif // TRIANGLE_H

triangle.cpp

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

#include "triangle.h"

Triangle::Triangle(QObject *parent) :
    QObject(parent), QGraphicsItem()
{
    angle = 0;      /// Задаём угол поворота графического объекта
    steps = 1;      /// Задаём стартовое положение ножек мухи
    countForSteps = 0;      /// Счётчик для отсчета тиков таймера, при которых мы нажимали на кнопки
    setRotation(angle);     /// Устанавливаем угол поворота графического объекта

    m_player = new QMediaPlayer(this);          // Инициализация плеера
    m_playlist = new QMediaPlaylist(m_player);  // Инициализация плейлиста

    m_player->setPlaylist(m_playlist);          // Установка плейлиста в аудио плеер
    m_playlist->addMedia(QUrl("qrc:/game/bzzz.wav"));       // Добавление трека в плейлист
    m_playlist->setPlaybackMode(QMediaPlaylist::CurrentItemInLoop); // Зацикливание трека
}

Triangle::~Triangle()
{

}

QRectF Triangle::boundingRect() const
{
    return QRectF(-40,-50,80,100);   /// Ограничиваем область, в которой лежит треугольник
}

void Triangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
   // Программный код из прошлых уроков
}

void Triangle::slotGameTimer()
{
    /* Проверяем, нажата ли была какая-либо из кнопок управления объектом.
     * Прежде чем считать шажки
     * */
    if(GetAsyncKeyState(VK_LEFT) ||
       GetAsyncKeyState(VK_RIGHT) ||
       GetAsyncKeyState(VK_UP) ||
       GetAsyncKeyState(VK_DOWN))
    {
       // Программный код из прошлых уроков

        m_player->play();   // Плеер играет только тогда, когда муха движется
    } else {
        m_player->stop();   // Если Муха не движется, то отключаем плее
    }

    // Программный код из прошлых уроков
}

widget.h

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

widget.cpp

В данном классе нет глобального объявления объекта QMediaPlayer, поскольку объекты создаются динамически, например для каждого съеденного яблока. Из-за того, что яблоки могут съедаться очень быстро и практически одновременно, то и звуки поедания яблок будут звучать вместе, а один плеер не справится с такой задачей, поэтому придётся запускать по плееру на каждый звук. Также отдельным плеером будет проигрываться гибель Мухи .

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    // программный код из прошлых уроков
}

Widget::~Widget()
{
    delete ui;
}

void Widget::slotDeleteApple(QGraphicsItem *item)
{
    /* Получив сигнал от Мухи
     * Перебираем весь список яблок и удаляем найденное яблоко
     * */
    foreach (QGraphicsItem *apple, apples) {
        if(apple == item){
            scene->removeItem(apple);   // Удаляем со сцены
            apples.removeOne(apple);    // Удаляем из списка
            delete apple;               // Вообще удаляем
            ui->lcdNumber->display(count++);    /* Увеличиваем счёт на единицу
                                                 * и отображаем на дисплее
                                                 * */
            // Звук поедания яблока
            QMediaPlayer * m_player = new QMediaPlayer(this);   // Инициализируем плеер
            QMediaPlaylist * m_playlist = new QMediaPlaylist(m_player); // Создаём плейлист

            m_player->setPlaylist(m_playlist);  // Устанавливаем плейлист в плеер
            m_playlist->addMedia(QUrl("qrc:/game/hrum.wav")); // Добавляем аудио в плеер
            m_playlist->setPlaybackMode(QMediaPlaylist::CurrentItemOnce); // Проигрываем один раз
            m_player->play();   // Запускаем плеер
        }
    }
}

void Widget::slotCreateApple()
{
   // программный код из прошлых уроков
}

void Widget::on_pushButton_clicked()
{
   // программный код из прошлых уроков);

    ui->pushButton->setEnabled(false);

    gameState = GAME_STARTED;
}

void Widget::slotGameOver()
{
    /* Если игра окончена
     * Отключаем все таймеры
     * */
    timer->stop();
    timerCreateApple->stop();

    // Если Муха Погибла, то запускаем предсмертный крик
    QMediaPlayer * m_player = new QMediaPlayer(this);       // Создаём плеер
    QMediaPlaylist * m_playlist = new QMediaPlaylist(m_player); // Создаём плейлист

    m_player->setPlaylist(m_playlist);      // Устанавливаем плейлист в плеер
    m_playlist->addMedia(QUrl("qrc:/game/scream.wav")); // Добавляем аудио в плейлист
    m_playlist->setPlaybackMode(QMediaPlaylist::CurrentItemOnce);   // Проигрываем трек один раз
    m_player->play();   // Запускаем трек

    // программный код из прошлых уроков
}

void Widget::slotPause()
{
    // программный код из прошлых уроков
}

Итог

Вот и закончена работа над нашей первой игрой. Теперь у Вас имеется представление о том, как создать простенькую игру на Qt C++.

Все, кто интересуется исходниками игры, могут скачать их по этой ссылке: Source

Все, кто интересуется самой игрой и просто хочет в неё сыграть, могут скачать её по этой ссылке: Muha_Setup

Полный список статей данного цикла:

Видеоурок

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

ВН
  • 22 марта 2019 г. 7:08
  • (ред.)

Из кьюта приложение не хочет запускаться, аварийно завершается, но каких-либо ошибок не выдаёт. Оно открывается, после нажатия "старт" зависает и завершается. Если не из кьюта запускать дебаг - та же ерунда. Релиз вообще отказывается работать, ошибки на картинках. Все dll и libs доложила и в дебаг, и в релиз. В чём может быть проблема?
А windeployqt вообще динамит, открывает консоль на секунду - и всё. Удаление qmakes и pro.user тоже не помогает


Ну может бибилотеки не те положили? У вас сборка для MinGW, а либы для MSVC.

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
e
  • ehot
  • 31 марта 2024 г. 14:29

C++ - Тест 003. Условия и циклы

  • Результат:78баллов,
  • Очки рейтинга2
B

C++ - Тест 002. Константы

  • Результат:16баллов,
  • Очки рейтинга-10
B

C++ - Тест 001. Первая программа и типы данных

  • Результат:46баллов,
  • Очки рейтинга-6
Последние комментарии
k
kmssr8 февраля 2024 г. 18:43
Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко5 февраля 2024 г. 1:50
Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 декабря 2023 г. 10:30
Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 декабря 2023 г. 8:38
Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik18 декабря 2023 г. 21:01
Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Сейчас обсуждают на форуме
a
a_vlasov14 апреля 2024 г. 6:41
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
Павел Дорофеев
Павел Дорофеев14 апреля 2024 г. 2:35
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrex4 апреля 2024 г. 4:47
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…
P
Pisych27 февраля 2023 г. 4:04
Как получить в массив значения из связанной модели? Спасибо, разобрался:))
AC
Alexandru Codreanu19 января 2024 г. 11:57
QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…

Следите за нами в социальных сетях