Реклама

GameDev на Qt - Урок 4. Обнаружение коллизий в Qt (2D)

РуководствоQtGameDev, Qt, Collision, Коллизия976

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

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

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

Если вы пишите платформер на Qt, то для объектов QGraphicsItem имеется возможность использовать функцию графической сцены, в которой они находятся, а именно QGraphicsScene ::collidingItems() . В данную функцию передаётся в качестве аргумента тот объект, для которого Мы хотим произвести обнаружение коллизий. Функция возвращает список графических объектов, если смогла их обнаружить в области шара для хомяка нашего героя. И если Мы обнаруживаем, что герой наткнулся при очередном шаге на какой-то объект, то Мы заставляем героя тут же сделать шаг назад.

Реализуем обнаружение коллизий

А теперь приступим к реализации разрешения коллизий на основе программного кода из предыдущих уроков по GameDev в Qt:

widget.cpp

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

    scene->addRect(0,0,520,20,QPen(Qt::NoPen),QBrush(Qt::darkGray));
    scene->addRect(0,0,20,520,QPen(Qt::NoPen),QBrush(Qt::darkGray));
    scene->addRect(0,500,520,20,QPen(Qt::NoPen),QBrush(Qt::darkGray));
    scene->addRect(500,0,20,520,QPen(Qt::NoPen),QBrush(Qt::darkGray));
    scene->addRect(170,250,180,20,QPen(Qt::NoPen),QBrush(Qt::darkGray));
    scene->addRect(250,170,20,180,QPen(Qt::NoPen),QBrush(Qt::darkGray));

triangle.h

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

private:
    QRectF boundingRect() const;

triangle.cpp

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

// Изменены размеры героя
QRectF Triangle::boundingRect() const
{
    return QRectF(-12,-15,24,30);
}

/* Возвращаем форму героя
 * В данном случае лучше использовать эллипс
 * */
QPainterPath Triangle::shape() const
{
    QPainterPath path;
    path.addEllipse(boundingRect());
    return path;
}

void Triangle::slotBulletTimer()
{
    /// Если стрельба разрешена, то вызываем сигнал на создание пули
    if(shot) emit signalBullet(mapToScene(0,-25), target);

}

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

void Triangle::slotGameTimer()
{
    /** Перемещаем треугольник в зависимости от нажатых кнопок
     * */
    if(GetAsyncKeyState('A')){
        this->setX(this->x() - 1);
        /* Проверяем на столкновение,
         * если столкновение произошло,
         * то возвращаем героя обратно в исходную точку
         * */
        if(!scene()->collidingItems(this).isEmpty()){
            this->setX(this->x() + 1);
        }
    }
    if(GetAsyncKeyState('D')){
        this->setX(this->x() + 1);
        /* Проверяем на столкновение,
         * если столкновение произошло,
         * то возвращаем героя обратно в исходную точку
         * */
        if(!scene()->collidingItems(this).isEmpty()){
            this->setX(this->x() - 1);
        }
    }
    if(GetAsyncKeyState('W')){
        this->setY(this->y() - 1);
        /* Проверяем на столкновение,
         * если столкновение произошло,
         * то возвращаем героя обратно в исходную точку
         * */
        if(!scene()->collidingItems(this).isEmpty()){
            this->setY(this->y() + 1);
        }
    }
    if(GetAsyncKeyState('S')){
        this->setY(this->y() + 1);
        /* Проверяем на столкновение,
         * если столкновение произошло,
         * то возвращаем героя обратно в исходную точку
         * */
        if(!scene()->collidingItems(this).isEmpty()){
            this->setY(this->y() - 1);
        }
    }

    // Код из предыдущих уроков
}

Итог

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

Видеоурок

Реклама
Реклама

Комментарии

Комментарии

Только авторизованные пользователи могут оставлять комментарии.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь
Реклама
Последние комментарии
  • EVILEG
  • 24 апреля 2017 г. 20:44
Подключение вашего Qt приложения к сервисам Google, используя OAuth 2.0

У меня пока мыслей на этот счёт нет ((

Подключение вашего Qt приложения к сервисам Google, используя OAuth 2.0

Пробовал играться с шарком, либо я криво смотрел, либо почему-то POST запросы на oauth.yandex.ru не летят, хотя должны постом лететь, я и исходники QOAuth2AuthorizationCodeFlow ковырял на пред

  • EVILEG
  • 24 апреля 2017 г. 13:39
Подключение вашего Qt приложения к сервисам Google, используя OAuth 2.0

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

Сейчас обсуждают на форуме
  • EVILEG
  • 28 апреля 2017 г. 20:02
Qt Installer Framework. Вызов программы при деинсталляции.

А. Вон оно как. Ну хорошо, что оказалось так просто.

  • EVILEG
  • 28 апреля 2017 г. 17:01
QTWebEngineView

На самом деле всё гораздо проще. у QWebEngineView есть сигнал urlChanged() . Вот его и нужно использовать, чтобы получить новый url страницы. Заголовочный файл #...

  • EVILEG
  • 28 апреля 2017 г. 9:30
Другой ToolBar

Если ToolBar все должны находиться внутри окна mainwindow, то создайте необходимое количество ToolBar`ов и часть из них сделайте скрытыми. А когда открываете диалог, то показывайте скрытые Too...

  • EVILEG
  • 28 апреля 2017 г. 9:13
Ошибка

Заголовочный файл класса StyleHelper не подключили в файл реализации mainwindow.cpp

Реклама