Реклама

Qt/C++ - Урок 028. Как использовать sprite картинки с помощью QPixmap

РуководствоQtQPixmap, Qt sprite, Qt, sprite, sprite QPixmap1625

После того, как мы нарисовали sprite в прошлом уроке по работе с Adobe Illustrator, настало время применить полученную картинку при работе с Qt и добавить её в программу с помощью QPixmap. Причем, мы сделаем анимированый sprite, и посмотрим, как происходит маленький анимированый взрыв на графической сцене нашего приложения на Qt.

Структура проекта для работы с QPixmap и sprite

Структура проекта sprite_example будет следующая:

  • sprite_example.pro - профайл проект;
  • widget.h - заголовочный файл основного окна приложения;
  • widget.cpp - файл исходных кодов основного окна приложения;
  • widget.ui - файл интерфейса;
  • sprite.h - заголовочный файл класса, предназначенного для нашего спрайта, в котором будет применяться QPixmap;
  • sprite.cpp - файл исходных кодов для работы с QPixmap;
  • sprite.qrc - ресурсный файл;
  • sprite_sheet.png - наш спрайт, который мы применим для анимации.

widget.ui

Ничего особенного в этом файле нет. Просто растягиваем по всему окно объект QGraphicsView, в который поместим QGraphicsScene .

widget.h

В этом файле мы объявим объект графической сцены, в который поместим объект с QPixmap, в котором будет анимированый sprite. Только не забудьте подключить заголовочный файл sprite.h.

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QGraphicsScene>
#include <QTimer>
#include <QList>
#include <QPixmap>

#include "sprite.h"

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;
    QGraphicsScene *scene;  // Объявляем графическую сцену
};

#endif // WIDGET_H

widget.cpp

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

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

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    scene = new QGraphicsScene();       // Инициализируем графическую сцену

    ui->graphicsView->setScene(scene);  // Устанавливаем графическую сцену в graphicsView

    scene->addItem(new Sprite());       // Помещаем на сцену новый объект спрайта

}

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

sprite.h

А вот теперь поговорим о том, как же реализован анимированый sprite. Для этого нам понадобится заранее подготовленный спрайт, а вернее sprite sheet, который состоит из 15 кадров, расположенных в одну строку.

Технически, данный sprite sheet устанавливается в объект класса QPixmap, в котором он пролистывается слева направо с определенной периодичность. Для этого мы новый класс наследуем от QGraphicsItem и QObject, чтобы использовать сигналы и слоты . И в методе paint задаём отрисовку участка изображения sprite_sheet , который задан в ресурсном файле. Таймер управляет сменой кадров с помощью слота nextFrame(). По сигналу от таймера мы изменяем координату отрисовки участка спрайта и перерисовываем графический объект с новым кадром.

#ifndef SPRITE_H
#define SPRITE_H

#include <QObject>
#include <QGraphicsItem>
#include <QTimer>
#include <QPixmap>
#include <QPainter>

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

signals:

public slots:

private slots:
    void nextFrame();   // Слот для пролистывания изображения в QPixmap

private:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    QRectF boundingRect() const;

private:
    QTimer *timer;      // Таймер для пролистывания изображения в QPixmap
    QPixmap *spriteImage;   // В данный объект QPixamp будет помещён спрайт
    int currentFrame;   // Координата X, с которой начинает очередной кадр спрайта

};

#endif // SPRITE_H

sprite.cpp

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

#include "sprite.h"

Sprite::Sprite(QObject *parent) :
    QObject(parent), QGraphicsItem()
{
    currentFrame = 0;   // Устанавливаем координату текущего кадра спрайта
    spriteImage = new QPixmap(":sprite_sheet.png"); // Загружаем изображение спрайта в QPixmap

    timer = new QTimer();   // Создаём таймер для анимации спрайта
    // Подключаем сигнал от таймера к слоту перелистывания кадров спрайта
    connect(timer, &QTimer::timeout, this, &Sprite::nextFrame);
    timer->start(25);   // Запускаем спрайт на генерацию сигнала с периодичность 25 мс
}

QRectF Sprite::boundingRect() const
{
    return QRectF(-10,-10,20,20);
}

void Sprite::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    /* В отрисовщике графического объекта отрисовываем спрайт
     * Разберём все параметры данной функции
     * Первых два аргумента - это координат X и Y куда помещается QPixmap
     * Третий аргумент - это указатель на QPixmap
     * 4 и 5 аргументы - Координаты в В изображении QPixmap, откуда будет отображаться изображение
     * Задавая координату X с помощью перемнной currentFrame мы будем как бы передвигать камеру
     * по спрайту
     * и последние два аргумента - это ширина и высота отображаем части изображение, то есть кадра
     * */
    painter->drawPixmap(-10,-10, *spriteImage, currentFrame, 0, 20,20);
    Q_UNUSED(option);
    Q_UNUSED(widget);
}

void Sprite::nextFrame()
{
    /* По сигналу от таймера передвигаем на 20 пикселей точку отрисовки
     * Если currentFrame = 300 то обнуляем его, поскольку размер sprite sheet 300 пикселей на 20
     * */
    currentFrame += 20;
    if (currentFrame >= 300 ) currentFrame = 0;
    this->update(-10,-10,20,20); // и перерисовываем графический объект с новым кадром спрайта
}

Итог

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

Видеоурок

Реклама

Комментарии

Комментарии

Только авторизованные пользователи могут оставлять комментарии.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь
Последние комментарии
  • EVILEG
  • 24 мая 2017 г. 15:12

Как написать игру на Qt - Урок 3. Взаимодействие с другими объектами

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

Как написать игру на Qt - Урок 3. Взаимодействие с другими объектами

А если применить приведение типов? Enemy01 *itemEnemy01 = dynamic_cast (item); void Widget::slotDeleteApple(QGraphicsItem *item) { Apple *check = dynamic_cast<Apple *>...

  • EVILEG
  • 24 мая 2017 г. 14:35

Как написать игру на Qt - Урок 3. Взаимодействие с другими объектами

void Widget::slotDeleteApple(QGraphicsItem *item) { if(apple == item) { scene->removeItem(apple); delete apple; ui->lcdNumber->display(count+...

Как написать игру на Qt - Урок 3. Взаимодействие с другими объектами

При столкновении объектов отсылается сигнал signalCheckItem, который содержит указатель на объект. В ядре игры проводится проверка. Если объект == apple, то выполняется удаление объекта. vo...

  • EVILEG
  • 24 мая 2017 г. 13:28

Qt/C++ - Урок 052. Кастомизация Qt Аудио плеера в стиле AIMP

В методах mousePressEvent, mouseMoveEvent и т.д. в этом же самом уроке показано, как определять области, в которых находится курсор мыши. Это реализовано для изменения размеров, в методе checkResiz...

Сейчас обсуждают на форуме

WinApi CBTProc

Сделать бул как у тебя?

  • Kostya
  • 26 мая 2017 г. 14:10

Всплывающие подсказки в QT

Как реализована данная штука?

Отличия в рефлектограммах соседних портов

Спасибо, за информацию.

  • Arrow
  • 24 мая 2017 г. 14:09

qmake

Похоже на то! Спасибо.