Evgenii Legotckoi
Sept. 18, 2015, 8:54 p.m.

How to make game using Qt - Lesson 1. Control of object

With this lesson begins a series of articles on how to write a play on Qt. In the previous article it was told about the system of positioning of graphical elements QGraphicsItem in the graphic scene QGraphicsScene . It was painted a triangle and placed in the center of the graphic scenes, the dimensions of which were 500 by 500 pixels. And now it is time to revive this triangle, but rather to begin to control it.

We make technical lesson assignment:

  • A graphic scene is located in the Window with dimensions of 500 by 500 pixels (this is already done in the previous lesson);
  • In the center of the graphic scene is a red triangle (which also has been done in the previous lesson);
  • The triangle should move when you press the Up arrow, Down, Left, Right;
  • Triangle should not go beyond a graphic scene, that is, should be limited by the size of the graphic scene.

Note. This project uses of WinAPI, so the project is suitable for use in the Windows operating system, but only algorithm that is used in this lesson is applicable to Linux and MacOS. So if you want to write a game for these operating systems, you will need to use the library of the OS for asynchronous processing keystrokes.


Project Structure

  • Triangle.pro - profile project, created by default, and in this project does not require korrektirovaki;
  • main.cpp - the file from which you start the application, the file is called a widget, which will be located in the graphic scene with a triangle, which we will manage;
  • widget.h - header file, called a widget with a graphic scene;
  • widget.cpp - File widget source code;
  • triangle.h - header file class Triangle, which is inherited from QGraphicsItem;
  • triangle.cpp - class source code file Triangle.

mainwindow.ui

The interface design simply throws QGraphicsView in the widget. Nothing more is required.

widget.h

This file is only to declare a graphical scene, the triangle object, which will manage, as well as a timer counts on which to test the state of the keyboard keys, we'll manage the triangle on the graphic scene.

  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3.  
  4. #include <QWidget>
  5. #include <QGraphicsScene>
  6. #include <QShortcut>
  7. #include <QTimer>
  8.  
  9. #include <triangle.h>
  10.  
  11. namespace Ui {
  12. class Widget;
  13. }
  14.  
  15. class Widget : public QWidget
  16. {
  17. Q_OBJECT
  18.  
  19. public:
  20. explicit Widget(QWidget *parent = 0);
  21. ~Widget();
  22.  
  23. private:
  24. Ui::Widget *ui;
  25. QGraphicsScene *scene; /// We declare a graphic scene
  26. Triangle *triangle; /// and triangle
  27. QTimer *timer; /* We declare the game a timer,
  28.   * by which will be changing the position of an object
  29.   * on the stage when exposed to the keyboard keys
  30. * */
  31. };
  32.  
  33. #endif // WIDGET_H

widget.cpp

This file initializes the graphic scene, and its size, in a graphical scene rendered the field border, where a triangle will move. But the key point is to initialize a timer signal processing of which will be made changes in the state of graphic scenes, and will change the coordinates of the triangle position, tracking the state of the keyboard keys.

  1. #include "widget.h"
  2. #include "ui_widget.h"
  3.  
  4. Widget::Widget(QWidget *parent) :
  5. QWidget(parent),
  6. ui(new Ui::Widget)
  7. {
  8. ui->setupUi(this);
  9. this->resize(600,600); /// Defining the size of the widget, ie the window
  10. this->setFixedSize(600,600); /// Fix a widget sizes
  11.  
  12. scene = new QGraphicsScene(); /// Initialize the graphics scene
  13. triangle = new Triangle(); /// Initialize triangle
  14.  
  15. ui->graphicsView->setScene(scene); /// Set the graphic scene in qgraphicsView
  16. ui->graphicsView->setRenderHint(QPainter::Antialiasing); /// Install anti-aliasing
  17. ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); /// Disable scroll vertically
  18. ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); /// Disable scroll horizontally
  19.  
  20. scene->setSceneRect(-250,-250,500,500); /// Set the graphic scenes
  21.  
  22. scene->addLine(-250,0,250,0,QPen(Qt::black)); /// Adding a horizontal line through the center
  23. scene->addLine(0,-250,0,250,QPen(Qt::black)); /// Add a vertical line through the center
  24.  
  25. /* In addition, we draw a limited area in the graphic scene */
  26. scene->addLine(-250,-250, 250,-250, QPen(Qt::black));
  27. scene->addLine(-250, 250, 250, 250, QPen(Qt::black));
  28. scene->addLine(-250,-250,-250, 250, QPen(Qt::black));
  29. scene->addLine( 250,-250, 250, 250, QPen(Qt::black));
  30.  
  31. scene->addItem(triangle); /// Adding to the scene triangle
  32. triangle->setPos(0,0); /// Set the triangle in the center of the stage
  33.  
  34. /* Initialize the timer and call processing slot timer signal from Triangle 20 times per second.
  35.   * By controlling the speed counts, respectively,
  36.   * control the speed of change in the state of graphic scenes
  37. * */
  38. timer = new QTimer();
  39. connect(timer, &QTimer::timeout, triangle, &Triangle::slotGameTimer);
  40. timer->start(1000 / 50);
  41. }
  42.  
  43. Widget::~Widget()
  44. {
  45. delete ui;
  46. }

triangle.h

And now we proceed to the program code that is responsible for the graphic object, which we will operate. The class inherits from QObject to work with signals and slots , as well as QGraphicsItem .

  1. #ifndef TRIANGLE_H
  2. #define TRIANGLE_H
  3.  
  4. #include <QObject>
  5. #include <QGraphicsItem>
  6. #include <QPainter>
  7. #include <QGraphicsScene>
  8.  
  9. /* Connect the library is responsible for the use WinAPI.
  10.  * This library is required to check the status of asynchronous keys
  11. * */
  12. #include <windows.h>
  13.  
  14. class Triangle : public QObject, public QGraphicsItem
  15. {
  16. Q_OBJECT
  17. public:
  18. explicit Triangle(QObject *parent = 0);
  19. ~Triangle();
  20.  
  21. signals:
  22.  
  23. public slots:
  24. void slotGameTimer();
  25.  
  26. protected:
  27. QRectF boundingRect() const;
  28. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
  29.  
  30. private:
  31. qreal angle; // The angle of rotation of the graphic object
  32.  
  33. };
  34.  
  35. #endif // TRIANGLE_H

triangle.cpp

Drawing a triangle is taken from the previous lesson on the positioning of graphical elements in the graphic scene, but redrawing in a slot that will handle the signal from the timer, and the initialization of the primary rotation of the object has a new piece of code.

Rotate an object is given in degrees of variable angle and set setRotation() function, which was inherited from QGraphicsItem . Also for monitoring the status of the keyboard keys used by the function of the WinAPI , namely GetAsyncKeyState() , which is the code button determines the state of the button itself. Each signal from QTimer class object is checked keystrokes and changing the position of the triangle depending on their condition.

  1. #include "triangle.h"
  2.  
  3. Triangle::Triangle(QObject *parent) :
  4. QObject(parent), QGraphicsItem()
  5. {
  6. angle = 0;
  7. setRotation(angle);
  8. }
  9.  
  10. Triangle::~Triangle()
  11. {
  12.  
  13. }
  14.  
  15. QRectF Triangle::boundingRect() const
  16. {
  17. return QRectF(-25,-40,50,80);
  18. }
  19.  
  20. void Triangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
  21. {
  22. QPolygon polygon; //
  23.  
  24. polygon << QPoint(0,-40) << QPoint(25,40) << QPoint(-25,40);
  25. painter->setBrush(Qt::red);
  26. painter->drawPolygon(polygon);
  27. Q_UNUSED(option);
  28. Q_UNUSED(widget);
  29. }
  30.  
  31. void Triangle::slotGameTimer()
  32. {
  33. /* Alternately checks for key presses
  34.      * using the asynchronous reception state of the keys
  35.      * is provided WinAPI
  36. * */
  37. if(GetAsyncKeyState(VK_LEFT)){
  38. angle -= 10; // Set turn 10 degrees to the left
  39. setRotation(angle); // Rotate object
  40. }
  41. if(GetAsyncKeyState(VK_RIGHT)){
  42. angle += 10; // Set turn 10 degrees to the right
  43. setRotation(angle); // Rotate object
  44. }
  45. if(GetAsyncKeyState(VK_UP)){
  46. setPos(mapToParent(0, -5)); /* Move the object 5 pixels forward to retranslate them
  47.   * in the coordinate system of the graphic scene
  48. * */
  49. }
  50. if(GetAsyncKeyState(VK_DOWN)){
  51. setPos(mapToParent(0, 5)); /* Move the object 5 pixels backward to retranslate them
  52.   * in the coordinate system of the graphic scene
  53. * */
  54. }
  55.  
  56. /* Check output of bounds. If the subject is beyond the set boundaries, then return it back
  57. * */
  58. if(this->x() - 10 < -250){
  59. this->setX(-240); // left
  60. }
  61. if(this->x() + 10 > 250){
  62. this->setX(240); // right
  63. }
  64.  
  65. if(this->y() - 10 < -250){
  66. this->setY(-240); // top
  67. }
  68. if(this->y() + 10 > 250){
  69. this->setY(240); // bottom
  70. }
  71. }

Примечание

To ensure that the project is compiled with MSVC build a set, add the following lines to pro project file:

  1. win32-msvc*{
  2. LIBS += -luser32
  3. }

Result

As a result of this work we have made first steps to ensure that the write off. Namely learned to control the object, that is, our hero-triangle, with whom we also work in future lessons on writing our first game.

A full list of articles in this series:

Video

Do you like it? Share on social networks!

M
  • Oct. 13, 2017, 4:19 p.m.

Добрый день,
Подскажите пожалуйста, чем может быть вызвана ошибка
"C:\Android\Qt\Mark\untitled4\triangle.cpp:5: ошибка: undefined reference to `vtable for Triangle'" ?
В конструкторе указывает на наследуемый класс QGraphicsItem и деструктор Triangle.
Я сначала пытался код сам исправить, но ничего не вышло и я просто скопировал Ваш.
Скопировал triangle.h и triangle.cpp.
Что это может быть?

Evgenii Legotckoi
  • Oct. 13, 2017, 4:50 p.m.

Отвратительная ошибка на самом деле.

В одном случае достаточно прописать Q_OBJECT.
В другом случае достаточно удалить build и пересобрать проект.
Один раз пришлось пересоздавать проект с нуля.
Проблема в том, что какие-то таблицы мок-файлов портятся. До сих пор порой до конца не понимаю, из-за чего такая проблема происходит. Иногда случается из-за добавления новых файлов в проект.
M
  • Oct. 13, 2017, 5:23 p.m.

Вы как всегда правы, удалить билд и перезапустить было решением проблемы

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

Добрый день. Переопределили boundingRect? и переопределили ли его правильно? выглядит так, что либо boundingRect неправильно расчитывается, либо не вызывается update сцены.

Спасибо, не поставил минус в boundingRect

СГ
  • Nov. 27, 2019, 9:21 p.m.

Евгений здравствуйте!Только начинаю разбираться в QT и работаю в Unreal Engine 4(делаю игры и приложения).Можно ли их сравнивать или они для разных задач.И что не сделать в Unreal,что можно сделать в QT.Оба на с++,у обоих есть дизайнеры для интерфейса.В Unreal правда blueprints,а в QT Qml(я так понимаю это его плюс перед Unreal).На Qml можно писать красивый интерфейс,но в Unreal это делать проще?

Evgenii Legotckoi
  • Nov. 27, 2019, 9:52 p.m.
  • (edited)

Добрый день

Они для разных задач.

  • Unreal Engine 4 - это всё-таки игры. Писать CAD систему или программу для клиентов по работе с базой данных я бы точно не стал, не для того это.
  • Qt - это различные приложения, от десктопных до мобильных, но точно не игры. Вернее игру написать можно на Qt, но я бы не стал писать что-то очень сложное. Для этого нужно брать игровой движок, тот же самый Unreal Engine 4.

В Qt вам для игры придётся написать собственный движок, который будет отвечать за физику и т.д. А в Unreal Engine 4 придётся писать очень много подготовительной логики для моделей данных (таблицы и т.д.). Ну либо использовать Felgo - фреймворк для написания приложений, который написан поверх Qt, они там сделали большую работу для мобильных приложений. В качестве движка используют cocos2d для игр.

Делать вёрстку приложения на QML определённо проще, якоря очень хорошая вещь. Когда я пробовал делать простую вёрстку в UE4 для меню, то мне якорей очень сильно не хватало, которые есть в QML.

blueprints - это конёчно жёсткое псевдопрограммирование )))) работать с ними можно, но я прекрасно понимал, когда пробовал себя в UE4, что логику, которую я писал в blueprints 8-10 блоками , на С++ я мог бы написать в две строки кода, которые были бы предельно понятны. Поэтому сразу начал искать варианты переноса логики в C++.

blueprints хороши для того, что требует 3D представления, но биты и байты ими перебирать - это самовредительство.

В общем сравнивать можно по ощущениям, но точно не по назначению. UE4 - игры, а Qt - это всё остальное.

СГ
  • Nov. 27, 2019, 10:22 p.m.

Евгений, спасибо за развёрнутый ответ!

kesh KD
  • May 14, 2020, 1:28 a.m.

"В дизайнере интерфейсов просто закидываем QGraphicsView в виджет. Больше ничего не требуется."

Для тупеньких, объясните пж (Qt Creator 4.10.2)

Evgenii Legotckoi
  • May 14, 2020, 2:06 a.m.

В Qt Creator двойным кликом открыть ui файл, и перетащить в виджет Graphics View. Потом выделить корневой виджет и нажать кнопку для создания GridLayoyt, чтобы Graphics View нормально позиционировался.

kesh KD
  • May 14, 2020, 1:35 p.m.
  • (edited)

Спасибо, и пока пользуясь случаем. PushButton в основном для чего?

Evgenii Legotckoi
  • May 14, 2020, 1:57 p.m.

Это обычная кнопка, клик по этой кнопке можно привязать к какому угодно функционалу, от применения настроек до открытия диалога. Зависит от логики, которую в неё вкладывают.

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

V
  • Dec. 8, 2020, 8:44 p.m.

Может вы мне подскажете, ибо я не могу понять и найти как эти строчки изменить под linux:

Evgenii Legotckoi
  • Jan. 28, 2021, 8:47 p.m.

Под Linux Не подскажу, там всё несколько сложнее

b
  • April 6, 2022, 12:12 p.m.

Привет, такой вопрос. Пишу игру, где отрисовываю абсолютно всё через QPainter. Спрайты анимации вывожу через DrawImage(). Какой из вариантов (QPainter и QGraphicsView) лучше в плане производительности? По поводу функционала понятно, но интересует именно скорость отрисовки, так как на средних смартфонах бывает падает FPS

Comments

Only authorized users can post comments.
Please, Log in or Sign up
  • Last comments
  • Evgenii Legotckoi
    March 9, 2025, 9:02 p.m.
    К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
  • VP
    March 9, 2025, 4:14 p.m.
    Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…
  • ИМ
    Nov. 22, 2024, 9:51 p.m.
    Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
  • Evgenii Legotckoi
    Oct. 31, 2024, 11:37 p.m.
    Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
  • A
    Oct. 19, 2024, 5:19 p.m.
    Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html