- 1. Жоба құрылымы
- 2. mainwindow.ui
- 3. виджет.h
- 4. widget.cpp
- 5. үшбұрыш.сағ
- 6. triangle.cpp
- 7. Ескерту
- 8. Барлығы
- 9. Бейне оқулық
Бұл сабақ Qt ойынды қалай жазу керектігі туралы мақалалар сериясын бастайды. Алдыңғы мақала сызбадағы QGraphicsItem графикалық элементтердің орналасу жүйесін сипаттады. көрініс QGraphicsScene. Үшбұрыш сызылып, графикалық көріністің ортасына орналастырылды, оның өлшемдері 500 x 500 пиксель болды. Енді осы үшбұрышты жандандыратын, дәлірек айтқанда, оны басқаруға кірісетін кез келді.
Сабақтың техникалық тапсырмасын орындайық:
- Терезе өлшемдері 500-ден 500 пиксельге дейінгі графикалық көріністі қамтиды (бұл алдыңғы сабақта жасалған);
- Графикалық көріністің ортасында қызыл үшбұрыш бар (ол да өткен сабақта жасалған);
- Жоғары, Төмен, Сол, Оң жақ көрсеткі пернелерін басқанда үшбұрыш қозғалуы керек;
- Үшбұрыш графикалық көріністің шеңберінен шықпауы керек, яғни графикалық көріністің өлшемімен шектелуі керек.
Ескертпе. Бұл жоба WinAPI пайдаланады, сондықтан жоба Windows операциялық жүйесінде, ал Linux және MacOS үшін осы сабақта қолданылған алгоритм ғана қолданылады. Сондықтан, егер сіз осы операциялық жүйелер үшін ойын жазғыңыз келсе, онда пернелерді басуларды асинхронды өңдеу үшін осы операциялық жүйелердің кітапханаларын пайдалану қажет болады.
Жоба құрылымы
- Triangle.pro - жоба профилі, әдепкі бойынша жасалған және осы жобада түзетуді қажет етпейді;
- main.cpp - қолданба басталатын файл, бұл файлда виджет шақырылады, онда біз басқаратын үшбұрышты графикалық көрініс орналасады;
- widget.h – графикалық көрініспен шақырылатын виджеттің тақырыптық файлы;
- widget.cpp - виджет бастапқы код файлы;
- triangle.h - QGraphicsItem-дан мұраланған Triangle класының тақырып файлы;
- triangle.cpp - Triangle. сыныбына арналған бастапқы код файлы
mainwindow.ui
Интерфейс дизайнерінде біз жай ғана QGraphicsView виджетіне түсіреміз. Басқа ештеңе талап етілмейді.
виджет.h
Бұл файлда біз жай ғана графикалық көріністі, біз басқаратын үшбұрыш объектісін, сондай-ақ таймерді жариялаймыз, оған сәйкес пернетақта пернелерінің күйі тексеріледі, біз графикалық көріністегі үшбұрышты басқарамыз.
#ifndef WIDGET\_H #define WIDGET\_H #include <QWidget> #include <QGraphicsScene> #include <QShortcut> #include <QTimer> #include <triangle.h> namespace Ui { class Widget; } class Widget : public QWidget { Q\_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private: Ui::Widget *ui; QGraphicsScene *scene; /// Объявляем графическую сцену Triangle *triangle; /// и треугольник QTimer *timer; /* Объявляем игровой таймер, благодаря которому * будет производиться изменения положения объекта на сцене * При воздействии на него клавишами клавиатуры * */ }; #endif // WIDGET\_H
widget.cpp
Бұл файлда графикалық көріністі және оның өлшемдерін инициализациялау орындалады және графикалық көріністе үшбұрыш қозғалатын өрістің шекаралары да сызылады. Бірақ негізгі сәт - графикалық көріністің күйі өзгеретін сигналды өңдеу арқылы таймерді инициализациялау және пернетақта пернелерінің күйін бақылай отырып, үшбұрыштың координаталары да өзгереді.
#include "widget.h" #include "ui\_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); this->resize(600,600); /// Задаем размеры виджета, то есть окна this->setFixedSize(600,600); /// Фиксируем размеры виджета scene = new QGraphicsScene(); /// Инициализируем графическую сцену triangle = new Triangle(); /// Инициализируем треугольник ui->graphicsView->setScene(scene); /// Устанавливаем графическую сцену в graphicsView ui->graphicsView->setRenderHint(QPainter::Antialiasing); /// Устанавливаем сглаживание ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); /// Отключаем скроллбар по вертикали ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); /// Отключаем скроллбар по горизонтали scene->setSceneRect(-250,-250,500,500); /// Устанавливаем область графической сцены scene->addLine(-250,0,250,0,QPen(Qt::black)); /// Добавляем горизонтальную линию через центр scene->addLine(0,-250,0,250,QPen(Qt::black)); /// Добавляем вертикальную линию через центр /* Дополнительно нарисуем органичение территории в графической сцене */ scene->addLine(-250,-250, 250,-250, QPen(Qt::black)); scene->addLine(-250, 250, 250, 250, QPen(Qt::black)); scene->addLine(-250,-250,-250, 250, QPen(Qt::black)); scene->addLine( 250,-250, 250, 250, QPen(Qt::black)); scene->addItem(triangle); /// Добавляем на сцену треугольник triangle->setPos(0,0); /// Устанавливаем треугольник в центр сцены /* Инициализируем таймер и вызываем слот обработки сигнала таймера * у Треугольника 20 раз в секунду. * Управляя скоростью отсчётов, соответственно управляем скоростью * изменения состояния графической сцены * */ timer = new QTimer(); connect(timer, &QTimer::timeout, triangle, &Triangle::slotGameTimer); timer->start(1000 / 50); } Widget::~Widget() { delete ui; }
үшбұрыш.сағ
Ал енді біз басқаратын графикалық объектіге жауап беретін бағдарлама кодына көшеміз. Класс сигналдармен және слоттармен жұмыс істеуге арналған QObject жүйесінен, сондай-ақ QGraphicsItem. -дан мұраға алады.
Дәл осы файлда windows.h тақырып файлы функциямен жұмыс істеу үшін қосылған
#ifndef TRIANGLE\_H #define TRIANGLE\_H #include <QObject> #include <QGraphicsItem> #include <QPainter> #include <QGraphicsScene> /* Подключаем библиотеку, отвечающую за использование WinAPI * Данная библиотека необходима для асинхронной проверки состояния клавиш * */ #include <windows.h> class Triangle : public QObject, public QGraphicsItem { Q\_OBJECT public: explicit Triangle(QObject *parent = 0); ~Triangle(); signals: public slots: void slotGameTimer(); // Слот, который отвечает за обработку перемещения треугольника protected: QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); private: qreal angle; // Угол поворота графического объекта }; #endif // TRIANGLE\_H
triangle.cpp
Үшбұрыш салу графикалық көріністегі графикалық элементтерді орналастыру бойынша алдыңғы сабақтан алынған, бірақ таймерден сигналды өңдейтін ұяшықта қайта салу, сонымен қатар нысанның бастапқы айналуын инициализациялау қазірдің өзінде жаңа код бөлігі болып табылады. .
Нысанның айналуы бұрыш айнымалысы арқылы градуспен берілген және QGraphicsItem ішінен мұраланған setRotation() функциясы арқылы орнатылады. Сондай-ақ, пернетақта түймелерінің күйін бақылау үшін WinAPI, функциясы пайдаланылады, атап айтқанда GetAsyncKeyState(), түймешік коды арқылы осы түйменің күйін анықтайды. QTimer класындағы объектінің әрбір сигналында басылған пернелер тексеріледі және олардың күйіне байланысты үшбұрыштың орны өзгереді.
#include "triangle.h" Triangle::Triangle(QObject *parent) : QObject(parent), QGraphicsItem() { angle = 0; // Задаём угол поворота графического объекта setRotation(angle); // Устанавилваем угол поворота графического объекта } Triangle::~Triangle() { } QRectF Triangle::boundingRect() const { return QRectF(-25,-40,50,80); /// Ограничиваем область, в которой лежит треугольник } void Triangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { QPolygon polygon; /// Используем класс полигона, чтобы отрисовать треугольник /// Помещаем координаты точек в полигональную модель polygon << QPoint(0,-40) << QPoint(25,40) << QPoint(-25,40); painter->setBrush(Qt::red); /// Устанавливаем кисть, которой будем отрисовывать объект painter->drawPolygon(polygon); /// Рисуем треугольник по полигональной модели Q\_UNUSED(option); Q\_UNUSED(widget); } void Triangle::slotGameTimer() { /* Поочерёдно выполняем проверку на нажатие клавиш * с помощью функции асинхронного получения состояния клавиш, * которая предоставляется WinAPI * */ if(GetAsyncKeyState(VK\_LEFT)){ angle -= 10; // Задаём поворот на 10 градусов влево setRotation(angle); // Поворачиваем объект } if(GetAsyncKeyState(VK\_RIGHT)){ angle += 10; // Задаём поворот на 10 градусов вправо setRotation(angle); // Поворачиваем объект } if(GetAsyncKeyState(VK\_UP)){ setPos(mapToParent(0, -5)); /* Продвигаем объект на 5 пискселей вперёд * перетранслировав их в координатную систему * графической сцены * */ } if(GetAsyncKeyState(VK\_DOWN)){ setPos(mapToParent(0, 5)); /* Продвигаем объект на 5 пискселей назад * перетранслировав их в координатную систему * графической сцены * */ } /* Проверка выхода за границы поля * Если объект выходит за заданные границы, то возвращаем его назад * */ if(this->x() - 10 < -250){ this->setX(-240); // слева } if(this->x() + 10 > 250){ this->setX(240); // справа } if(this->y() - 10 < -250){ this->setY(-240); // сверху } if(this->y() + 10 > 250){ this->setY(240); // снизу } }
Ескерту
Жобаны MSVC құрастыру жинағымен құрастыру үшін pro жоба файлына келесі жолдарды қосыңыз:
win32-msvc*{ LIBS += -luser32 }
Барлығы
Атқарылған жұмыстардың нәтижесінде ойын жазуға алғашқы қадамдар жасадық. Атап айтқанда, біз нысанды басқаруды үйрендік, яғни үшбұрышты кейіпкеріміз, біз онымен алғашқы ойынымызды жазу бойынша алдағы сабақтарда да жұмыс істейтін боламыз.
Бейне оқулық жобаға қосымша түсініктемелер мен түсіндірмелер береді, сонымен қатар қолданбаның жұмысын көрсетеді.
Осы сериядағы мақалалардың толық тізімі:
- 1-сабақ. Qt тілінде ойынды қалай жазуға болады. Объектіні басқару
- 2-сабақ. Qt ойынды қалай жазуға болады. Ойын кейіпкерінің анимациясы (2D)
- 3-сабақ. Qt ойынды қалай жазуға болады. Басқа нысандармен әрекеттесу
- 4-сабақ. Qt ойынды қалай жазуға болады. Жау – аман қалудың мәні
- 5-сабақ. Qt ойынды қалай жазуға болады. QMediaPlayer көмегімен дыбыс қосу
Добрый день,
Подскажите пожалуйста, чем может быть вызвана ошибка
"C:\Android\Qt\Mark\untitled4\triangle.cpp:5: ошибка: undefined reference to `vtable for Triangle'" ?
В конструкторе указывает на наследуемый класс QGraphicsItem и деструктор Triangle.
Я сначала пытался код сам исправить, но ничего не вышло и я просто скопировал Ваш.
Скопировал triangle.h и triangle.cpp.
Что это может быть?
Отвратительная ошибка на самом деле.
Вы как всегда правы, удалить билд и перезапустить было решением проблемы
Добрый день.
Проблема следующая:
треугольник при перемещении не отрисовывается полностью, кроме того, на графической сцене остаются его следы, но если, например, свернуть приложение и заново его открыть, то треугольник отрисовывется как положено.
Добрый день. Переопределили boundingRect? и переопределили ли его правильно? выглядит так, что либо boundingRect неправильно расчитывается, либо не вызывается update сцены.
Спасибо, не поставил минус в boundingRect
Евгений здравствуйте!Только начинаю разбираться в QT и работаю в Unreal Engine 4(делаю игры и приложения).Можно ли их сравнивать или они для разных задач.И что не сделать в Unreal,что можно сделать в QT.Оба на с++,у обоих есть дизайнеры для интерфейса.В Unreal правда blueprints,а в QT Qml(я так понимаю это его плюс перед Unreal).На Qml можно писать красивый интерфейс,но в Unreal это делать проще?
Добрый день
Они для разных задач.
В Qt вам для игры придётся написать собственный движок, который будет отвечать за физику и т.д. А в Unreal Engine 4 придётся писать очень много подготовительной логики для моделей данных (таблицы и т.д.). Ну либо использовать Felgo - фреймворк для написания приложений, который написан поверх Qt, они там сделали большую работу для мобильных приложений. В качестве движка используют cocos2d для игр.
Делать вёрстку приложения на QML определённо проще, якоря очень хорошая вещь. Когда я пробовал делать простую вёрстку в UE4 для меню, то мне якорей очень сильно не хватало, которые есть в QML.
blueprints - это конёчно жёсткое псевдопрограммирование )))) работать с ними можно, но я прекрасно понимал, когда пробовал себя в UE4, что логику, которую я писал в blueprints 8-10 блоками , на С++ я мог бы написать в две строки кода, которые были бы предельно понятны. Поэтому сразу начал искать варианты переноса логики в C++.
blueprints хороши для того, что требует 3D представления, но биты и байты ими перебирать - это самовредительство.
В общем сравнивать можно по ощущениям, но точно не по назначению. UE4 - игры, а Qt - это всё остальное.
Евгений, спасибо за развёрнутый ответ!
"В дизайнере интерфейсов просто закидываем QGraphicsView в виджет. Больше ничего не требуется."
Для тупеньких, объясните пж (Qt Creator 4.10.2)
В Qt Creator двойным кликом открыть ui файл, и перетащить в виджет Graphics View. Потом выделить корневой виджет и нажать кнопку для создания GridLayoyt, чтобы Graphics View нормально позиционировался.
Спасибо, и пока пользуясь случаем. PushButton в основном для чего?
Это обычная кнопка, клик по этой кнопке можно привязать к какому угодно функционалу, от применения настроек до открытия диалога. Зависит от логики, которую в неё вкладывают.
Если у вас и дальше будут вопросы, то задавайте их на форуме, каждый в отдельной теме, чтобы они уже были логически структурированы и не было оффтопов.
Я просматриваю все вопросы, которые появляются на форуме и по возможности отвечаю на них. Форум
Может вы мне подскажете, ибо я не могу понять и найти как эти строчки изменить под linux:
Под Linux Не подскажу, там всё несколько сложнее
Привет, такой вопрос. Пишу игру, где отрисовываю абсолютно всё через QPainter. Спрайты анимации вывожу через DrawImage(). Какой из вариантов (QPainter и QGraphicsView) лучше в плане производительности? По поводу функционала понятно, но интересует именно скорость отрисовки, так как на средних смартфонах бывает падает FPS