Evgenii Legotckoi
Evgenii LegotckoiЖел. 6, 2015, 9:47 Т.Ж.

Qt/C++ - 033-сабақ. QGraphicsItem орнына QGraphicsObject-пен жұмыс істеу

Менің назарымды [QGraphicsItem және QObject] мұраға алынған сыныптың орнына сигналдармен және ұяшықтармен жұмыс істеу үшін аударды (https:// evileg.com/ ru/post/81/) сіз QGraphicsObject ішінен мұраланған классты пайдалана аласыз. Шынында да, егер сіз QGraphicsObject көздеріне аздап үңілсеңіз, бұл QGraphicsItem және QObject ішінен мұраланған класс екенін көресіз. Яғни, бірнеше мұра да қолданылады, тек осы жағдайда барлық велосипедтер бізге дейін жазылған. Сондықтан осы сыныппен ойын механикасы мысалында жұмыс істеуге тырысайық.

Атап айтқанда, мен Diablo. сияқты кез келген RPG сияқты графикалық көріністе кейіпкерді тінтуірдің көмегімен жылжытатын бағдарлама жазуды ұсынамын.

QGraphicsObject-пен жұмыс істеуге арналған жоба құрылымы

  • QGraphicsObjectExample.pro - профильдік жоба;
  • main.cpp - негізгі бастапқы код файлы;
  • widget.h - қолданба терезесінің тақырып файлы;
  • widget.cpp - қолданба терезесінің бастапқы код файлы;
  • customscene.h - теңшелетін [графикалық көрініс] тақырып файлы(https://evileg.com/en/post/82/) ;
  • customscene.cpp - реттелетін графикалық көріністің бастапқы код файлы;
  • triangle.h - жылжитын үшбұрыш батыр класының тақырып файлы;
  • triangle.cpp - үшбұрышты кейіпкер сыныбының бастапқы код файлы.

mainwindow.ui - QGraphicsObjectExample.pro - main.cpp

Негізгі терезенің пішіні ерекше. Ол тек QGraphicsView нысанын қамтиды. QGraphicsObjectExample және main.cpp файлдары әдепкі бойынша жасалады және өзгертілмейді.

виджет.h

Жоспарларымызды жүзеге асыру үшін бізге тек теңшелген графикалық көрініс қажет, басқа ештеңе жоқ. Ол Виджет класының конструкторында жергілікті түрде жариялануы мүмкін болса да.

#ifndef WIDGET\_H
#define WIDGET\_H

#include <QWidget>

#include "customscene.h"
#include "triangle.h"

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q\_OBJECT

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

private:
    Ui::Widget *ui;
    CustomScene *scene;
};

#endif // WIDGET\_H

widget.cpp

Виджет класының конструкторында графикалық көрініс пен үшбұрыш нысанын инициализациялаймыз. Сондай-ақ signalTargetCoordinate сигналын графикалық көріністен үшбұрыш ұясына қосамыз. signalTargetCoordinate үшбұрыш қозғалатын тінтуірдің координаталарын береді.

#include "widget.h"
#include "ui\_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    // Устанавливаем параметры окна приложения
    this->resize(600,600);
    this->setFixedSize(600,600);

    ui->setupUi(this);
    scene = new CustomScene();

    ui->graphicsView->setScene(scene);
    ui->graphicsView->setRenderHint(QPainter::Antialiasing);    // Устанавливаем сглаживание
    ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Отключаем скроллбар по вертикали
    ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Отключаем скроллбар по горизонтали

    scene->setSceneRect(0,0,520,520);   // Устанавливаем размеры графической сцены

    Triangle *triangle = new Triangle();
    triangle->setPos(260,260);
    scene->addItem(triangle);

    // Соединяем сигнал о положении курсора со слотом для передвижения героя
    connect(scene, &CustomScene::signalTargetCoordinate, triangle, &Triangle::slotTarget);
}

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

customscene.h

Графикалық көріністе тінтуірдің координаттарын жіберу үшін сигнал пайдаланылады және ол mousePressEvent және mouseMoveEvent. оқиғаларынан жіберіледі.Бұл жағдайда деректері бар сигнал сол жақ тінтуірдің түймесі басылды.

#ifndef CUSTOMSCENE\_H
#define CUSTOMSCENE\_H

#include <QObject>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>

class CustomScene : public QGraphicsScene
{
    Q\_OBJECT
public:
    explicit CustomScene(QObject *parent = 0);
    ~CustomScene();

signals:
    // Сигнал для передачи координат положения курсора мыши
    void signalTargetCoordinate(QPointF point);

public slots:

private:
    // Функция, в которой производится отслеживание положения мыши
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
};

#endif // CUSTOMSCENE\_H

customscene.cpp

#include "customscene.h"
#include <QApplication>

CustomScene::CustomScene(QObject *parent) :
    QGraphicsScene(parent)
{

}

CustomScene::~CustomScene()
{

}

void CustomScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    if(QApplication::mouseButtons() == Qt::LeftButton){
        emit signalTargetCoordinate(event->scenePos()); // Передаём данный о местоположении клика
    }
}

void CustomScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    if(QApplication::mouseButtons() == Qt::LeftButton){
        emit signalTargetCoordinate(event->scenePos()); // Передаём данный о местоположении клика
    }
}

үшбұрыш.сағ

Бұл класс QGraphicsObject сыныбынан мұра алады және QObject сыныбынан мұраны пайдаланбайды, өйткені QGraphicsObject одан, сондай-ақ QGrapihcsItem ішінен мұраланған. Әрі қарай жұмыс істеу. бұл нысан да орындалады, біз QGrapgicsItem. ішінен мұраланған сыныппен жұмыс істегендей орындалады.

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

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

Бірақ мақсатты нүктенің координаттарын алуға арналған ұя кейіпкердің нысанаға қарай айналуын өңдейді.

#ifndef TRIANGLE\_H
#define TRIANGLE\_H

#include <QObject>
#include <QTimer>
#include <QGraphicsObject>

#define GO true
#define STOP false

class Triangle : public QGraphicsObject
{
    Q\_OBJECT
public:
    explicit Triangle();

signals:

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

public slots:
    void slotTarget(QPointF point); // Слот для установки координаты, куда нужно идти

private:
    QTimer *gameTimer;      // Игровой таймер
    QPointF target;         // Положение курсора
    bool state;             // Статус идти/стоять

private slots:
    void slotGameTimer();   // Игровой слот
};

#endif // TRIANGLE\_H

triangle.cpp

#include "triangle.h"
#include <math.h>

#include <QPainter>

static const double Pi = 3.14159265358979323846264338327950288419717;
static double TwoPi = 2.0 * Pi;

static qreal normalizeAngle(qreal angle)
{
    while (angle < 0)
        angle += TwoPi;
    while (angle > TwoPi)
        angle -= TwoPi;
    return angle;
}

Triangle::Triangle()
    : QGraphicsObject()
{
    setRotation(0);

    state = STOP;

    gameTimer = new QTimer();   // Инициализируем игровой таймер
    // Подключаем сигнал от таймера и слоту обработки игрового таймера
    connect(gameTimer, &QTimer::timeout, this, &Triangle::slotGameTimer);
    gameTimer->start(5);   // Стартуем таймер
}

QRectF Triangle::boundingRect() const
{
    return QRectF(-12,-15,24,30);
}

void Triangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    // Отрисовка треугольника
    QPolygon polygon;
    polygon << QPoint(0,-15) << QPoint(12,15) << QPoint(-12,15);
    painter->setBrush(Qt::red);
    painter->drawPolygon(polygon);

    Q\_UNUSED(option);
    Q\_UNUSED(widget);
}

void Triangle::slotGameTimer()
{
    if(state){
        QLineF lineToTarget(QPoint(0,0), mapFromScene(target));
        if(lineToTarget.length() > 2){
             setPos(mapToParent(0, -2));
        }
        /* Проверка выхода за границы поля
         * Если объект выходит за заданные границы, то возвращаем его назад
         * */
        if(this->x() - 30 < 0){
            this->setX(30);         /// слева
            state = STOP;           // Останавливаемся
        }
        if(this->x() + 30 > 520){
            this->setX(520 - 30);   /// справа
            state = STOP;           // Останавливаемся
        }

        if(this->y() - 30 < 0){
            this->setY(30);         /// сверху
            state = STOP;           // Останавливаемся
        }
        if(this->y() + 30 > 520){
            this->setY(520 - 30);   /// снизу
            state = STOP;           // Останавливаемся
        }
    }
}

void Triangle::slotTarget(QPointF point)
{
    // Определяем расстояние до цели
    target = point;
    QLineF lineToTarget(QPointF(0, 0), mapFromScene(target));
    // Угол поворота в направлении к цели
    qreal angleToTarget = ::acos(lineToTarget.dx() / lineToTarget.length());
    if (lineToTarget.dy() < 0)
        angleToTarget = TwoPi - angleToTarget;
    angleToTarget = normalizeAngle((Pi - angleToTarget) + Pi / 2);

    // Поворачиваем героя к цели
    if (angleToTarget >= 0 && angleToTarget < Pi) {
        // Rotate left
        setRotation(rotation() - angleToTarget * 180 /Pi);
    } else if (angleToTarget <= TwoPi && angleToTarget > Pi) {
        // Rotate right
        setRotation(rotation() + (angleToTarget - TwoPi )* (-180) /Pi);
    }

    state = GO; // Разрешаем идти
}

Барлығы

Нәтижесінде сіз басты кейіпкердің қозғалысын Diablo сияқты RPG сияқты бір тінтуірмен басқаратын қолданба аласыз. Қосымшаның демонстрациясын бейне оқулықтан көре аласыз.

Жобаны zip мұрағатында жүктеп алу сілтемесі: QGraphicsObjectExample

Бейне оқулық

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

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

m
  • Наурыз 6, 2018, 8:08 Т.Ж.

Добрый день! Пожалуйста подскажите, что может означать ошибка - ~\customscene.h:17: ошибка: 'void CustomScene::signalTargetCoordinate(QPointF)' is protected

Evgenii Legotckoi
  • Наурыз 6, 2018, 8:47 Т.Ж.

Добрый день! По какой-то причине у вас данный сигнал оказался в protected секции, а не в секции сигналов, то есть скорее всего он объявлен в заголовочнике так

protected:
    void signalTargetCoordinate(QPointF point);
А не так
public:
    void signalTargetCoordinate(QPointF point);
А вы видимо пытаетесь вызвать его извне объекта. Или что-то типо того...
m
  • Наурыз 6, 2018, 9:51 Т.Ж.

Большое спасибо. Файл был Ваш, но принудительное добавление public: перед void signal эту ошибку устранило. Но есть еще ошибка -

~\widget.cpp:27: ошибка: no matching function for call to 'Widget::connect(CustomScene*&, void (CustomScene::*)(QPointF), Triangle*&, void (Triangle::*)(QPointF))'

Если можно помогите пожалуйста - я в Qt вторую неделю всего.

Evgenii Legotckoi
  • Наурыз 6, 2018, 10:01 Т.Ж.

Скорее всего в одном из классов не объявлена нужная функция (слот или сигнал). Нужно, чтобы сигнатуры сигнала и слота совпадали в данном конкретном примере. А в одном из классов видимо отсутствует нужный метод ( сигнал или слот - почитайте эту статью, чтобы разобраться с теорией сигналов и слотов).

m
  • Наурыз 6, 2018, 10:40 Т.Ж.

Большое спасибо, удачи Вам, здоровья, и всего доброго.

m
  • Наурыз 7, 2018, 5:40 Т.Ж.

Добрый день! Еще раз спасибо за уроки. Все заработало, помог ваш урок 24. Public был ни при чем, нужно было две строки проекта с connect записать в стиле Qt 4.8.5. Правда - стрелками на клавиатуре треугольник двигается с точностью наоборот. Но это мелочи. Всего доброго.

Evgenii Legotckoi
  • Наурыз 7, 2018, 5:43 Т.Ж.

Добрый день!
Что? А почему? Вы используете Qt 4.8?

m
  • Наурыз 8, 2018, 2:34 Т.Ж.

Добрый день! Это требование руководства, увы!

Evgenii Legotckoi
  • Наурыз 8, 2018, 3:24 Т.Ж.

Вы случаем не в ОНИИПе работаете?

m
  • Наурыз 9, 2018, 2:20 Т.Ж.

Добрый день! Точно так, в НИИ, только не О...П. Остальное, к сожалению, не моя информация. Всего доброго.

i
  • Қар. 7, 2024, 9:08 Т.Қ.

Levi bQUxntHwuarMTVjjXj 6 18 2022 donde comprar priligy mexico

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
m
  • molni99
  • Қаз. 26, 2024, 1:37 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:80ұпай,
  • Бағалау ұпайлары4
m
  • molni99
  • Қаз. 26, 2024, 1:29 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

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

C++ - Тест 003. Условия и циклы

  • Нәтиже:42ұпай,
  • Бағалау ұпайлары-8
Соңғы пікірлер
i
innorwallҚар. 8, 2024, 12:50 Т.Ж.
ЖАМАНДЫҚ ЯРЕК. Google reCAPTCHA пайдалану buy priligy 60 urea in 50 patients treated by urea for mild hyponatremia developed it in the intensive care unit mean age 71 20 years
i
innorwallҚар. 7, 2024, 9:45 Т.Қ.
PyQt5 - Урок 001. QLineEdit IP мекенжайы priligy fda approval The second question is how successful is fertility treatment and that pertains
i
innorwallҚар. 7, 2024, 9:42 Т.Қ.
QML - Сабақ 004. Qt QML-дегі сигналдар мен слоттар J Clin Endocrinol Metab 1977; 45 240 priligy buy Packer M, Rouleau J L, Swedberg K, et al
Енді форумда талқылаңыз
i
innorwallҚар. 8, 2024, 12:48 Т.Ж.
добавить qlineseries в функции Uncommon but potentially severe adverse events include profound electrolyte and water loss, dehydration leading to hypotension and syncope, electrolyte depletion with hypokalemia, hypomagnesemia…
9
9AnonimҚаз. 25, 2024, 9:10 Т.Ж.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…
F
FynjyШілде 22, 2024, 4:15 Т.Ж.
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

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