Once we have drawn sprite last lesson on working with Adobe Illustrator , it's time to apply the resulting image when working with Qt and add it to the program using QPixmap . Moreover, we do Animated sprite, and see how the small explosion Animated graphics on the stage of our application on Qt.
The project structure to work with QPixmap and sprite
sprite_example project structure will be as follows:
- sprite_example.pro - the profile of the project;
- widget.h - header file of the main application window;
- widget.cpp - file source code of the main application window;
- widget.ui - interface file;
- sprite.h - class header file that is used for our sprite, which will be applied QPixmap;
- sprite.cpp - file source code to work with QPixmap;
- sprite.qrc - resource file;
- sprite_sheet.png - our sprite, which we will use for the animation.
widget.ui
Nothing special in this file is not present. Just stretch a box around the object QGraphicsView , which put QGraphicsScene .
widget.h
In this file, we will declare the object of graphic scenes, which put an object with a QPixmap , which will Animated sprite. Just do not forget to include the header file 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
In this file, we initialize the graphical scene and put it in graphicsView , as well as create a sprite object and place it on the stage.
#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); scene = new QGraphicsScene(); // Init graphics scene ui->graphicsView->setScene(scene); // Set grapihcs scene into graphicsView scene->addItem(new Sprite()); // We put on the scene a new sprite object } Widget::~Widget() { delete ui; }
sprite.h
And now let's talk about how well implemented Animated sprite. For this we need a prepared sprite, or rather the sprite sheet, which consists of 15 frames, arranged in a single row.
Technically, this sprite sheet is set to QPixmap class object in which it scrolls from left to right with a certain periodicity. To this end, we are a new class inherit from QGraphicsItem and QObject , to use signals and slots . And in the method of drawing the paint Asking sprite_sheet image area, which is defined in the resource file. The timer controls the change of the frame using nextFrame() slot. At a signal from timer we change the coordinate of the drawing area of the sprite and redraw a graphic object with the new frame.
#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(); // Slot for turning images into QPixmap private: void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); QRectF boundingRect() const; private: QTimer *timer; // Timer for turning images into QPixmap QPixmap *spriteImage; // In this QPixmap object will be placed sprite int currentFrame; // Coordinates X, which starts the next frame of the sprite }; #endif // SPRITE_H
sprite.cpp
In the class constructor initializes the timer and the method of paint we draw the right frame of the sprite. Switching is performed using frames nextFrame() slot.
#include "sprite.h" Sprite::Sprite(QObject *parent) : QObject(parent), QGraphicsItem() { currentFrame = 0; // Sets the coordinates of the current frame of the sprite spriteImage = new QPixmap(":sprite_sheet.png"); // Load the sprite image QPixmap timer = new QTimer(); // Create a timer for sprite animation connect(timer, &QTimer::timeout, this, &Sprite::nextFrame); timer->start(25); // Run the sprite on the signal generation with a frequency of 25 ms } QRectF Sprite::boundingRect() const { return QRectF(-10,-10,20,20); } void Sprite::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { /* In the graphic renderer we draw the sprite * The first two arguments - is the X and Y coordinates of where to put QPixmap * The third argument - a pointer to QPixmap * 4 and 5 of the arguments - The coordinates in the image QPixmap, where the image is displayed * By setting the X coordinate with the variable currentFrame we would like to move the camera on the sprite * and the last two arguments - the width and height of the displayed area, that is, the frame * */ painter->drawPixmap(-10,-10, *spriteImage, currentFrame, 0, 20,20); Q_UNUSED(option); Q_UNUSED(widget); } void Sprite::nextFrame() { /* At a signal from the timer 20 to move the point of rendering pixels * If currentFrame = 300 then zero out it as sprite sheet size of 300 pixels by 20 * */ currentFrame += 20; if (currentFrame >= 300 ) currentFrame = 0; this->update(-10,-10,20,20); }
Result
As a result, you get the app in the middle of the window which will be blinking an explosion the size of 20 by 20 pixels.
Подскажите пожалуйста ( я новичок совсем)
Можно ли организовать спрайт без этого окошка (как в fl studio fruity dance)?
Не знаю, какой-там конкретно эффект и если честно не хочется fl studio ради того, чтобы посмотреть устанавливать, но из того, что увидел в интернете.
Предполагаю, что то, что вы хотите сделать, в данном случае нужно реализовывать точно также с окном, но с одним существенным отличием. Нужно полностью отключить обрамление окна, а в нём отрисовывать спрайт в виджете с прозрачным фоном.
Вот в этой статье было что-то похожее. Там я отключал обрамление окна и кастомизировал виджеты.
Обратите внимание вот на эти строчки
Спасибо большое!
Очень помогли!
А возможно всё кроме спрайта сделать прозрачным?
"всё" - это что?
по факту я вам уже ответил и на этот вопрос.
Извините, но дилемма в том что - Спрайт должен быть сам по себе без заднего окна и виджета. ( вот то что я хочу сделать-
Прошу прощения за надоедливые и банальные вопросы
Да не в этом дело.
По сути, там всё тоже самое, только отображайте спрайт в отдельном диалоговом окне, у которого будет полностью отключено обрамление и т.д. Просто используйте QDialog, чтобы спрайт отдельно крутился.
С Новым годом!
Всё оказалось проще:
MAIN.cpp
QML
У меня всего 2 вопроса:
\\
Как В файле QML менять значение с помощью переменной из Main frameX: 0 не через класс? ( желательно считывание из txt файла)
\\\
Как сделать так чтобы курсор мышки не реагировал на прозрачное диалоговое окно и я мог спокойно нажимать на ярлыки позади него
Ну вы здесь тоже самое сделали, что я вам и советовал... только ещё QML за уши притянули.
frameX - только через класс устанавливать. В QML все объекты наследованы от QObject и там работа с классами идёт. Максимум использовать JavaScript встроенный в QML, но опять же без C++ и классов ничего вы не сделаете.
Это было бы проще реализовать через классические виджеты, также нужно лезть в API операционной системы. Я такое не делал, небоходимости не было. Могу сказать только, что нужно искать информацию по эмулированию кликов, чтобы перекинуть клик за окно приложения. В общем в три строки эо не делается.
Планомерно изучайте Qt, с ростом опыта разберётесь, как это сделать, но я могу вам только общее направление по этой задаче подсказать и кое-какие примеры, но вопросы у вас должны быть более гранулированными, а не так, "как написать программу, которая сделает то, что вы хотите". Серьёзно, для того, что вам нужно, требуется изучить больше, чем вот эта одна строка из вашего кода
значительно больше
А как вы сделали папку ресурсы ?