Evgenii Legotckoi
Evgenii LegotckoiҚыр. 18, 2015, 10:54 Т.Ж.

Qt тілінде ойынды қалай жазу керек - 1-сабақ. Объектіні басқару

Бұл сабақ 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
}

Барлығы

Атқарылған жұмыстардың нәтижесінде ойын жазуға алғашқы қадамдар жасадық. Атап айтқанда, біз нысанды басқаруды үйрендік, яғни үшбұрышты кейіпкеріміз, біз онымен алғашқы ойынымызды жазу бойынша алдағы сабақтарда да жұмыс істейтін боламыз.

Бейне оқулық жобаға қосымша түсініктемелер мен түсіндірмелер береді, сонымен қатар қолданбаның жұмысын көрсетеді.

Осы сериядағы мақалалардың толық тізімі:

Бейне оқулық

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

M
  • Қаз. 13, 2017, 6:19 Т.Ж.

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

Evgenii Legotckoi
  • Қаз. 13, 2017, 6:50 Т.Ж.

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

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

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

ПД
  • Там. 6, 2019, 9:58 Т.Ж.

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

Evgenii Legotckoi
  • Там. 6, 2019, 2:17 Т.Қ.

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

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

СГ
  • Қар. 27, 2019, 10:21 Т.Ж.

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

Evgenii Legotckoi
  • Қар. 27, 2019, 10:52 Т.Ж.
  • (өңделген)

Добрый день

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

  • 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 - это всё остальное.

СГ
  • Қар. 27, 2019, 11:22 Т.Ж.

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

kesh KD
  • Мамыр 13, 2020, 3:28 Т.Қ.

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

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

Evgenii Legotckoi
  • Мамыр 13, 2020, 4:06 Т.Қ.

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

kesh KD
  • Мамыр 14, 2020, 3:35 Т.Ж.
  • (өңделген)

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

Evgenii Legotckoi
  • Мамыр 14, 2020, 3:57 Т.Ж.

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

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

V
  • Жел. 8, 2020, 9:44 Т.Ж.

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

Evgenii Legotckoi
  • Қаң. 28, 2021, 9:47 Т.Ж.

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

b
  • Сәуір 6, 2022, 2:12 Т.Ж.

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

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
Г

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:66ұпай,
  • Бағалау ұпайлары-1
t

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:33ұпай,
  • Бағалау ұпайлары-10
t

Qt - Тест 001. Сигналы и слоты

  • Нәтиже:52ұпай,
  • Бағалау ұпайлары-4
Соңғы пікірлер
G
GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssrАқп. 8, 2024, 6:43 Т.Қ.
Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
F
FynjyШілде 22, 2024, 4:15 Т.Ж.
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
BlinCT
BlinCTМаусым 25, 2024, 1 Т.Ж.
Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
BlinCT
BlinCTМамыр 5, 2024, 5:46 Т.Ж.
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
Evgenii Legotckoi
Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

Бізді әлеуметтік желілерде бақылаңыз