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 Т.Ж.

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

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
OI
  • Ora Iro
  • Жел. 24, 2024, 6:38 Т.Ж.

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

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

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

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

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

  • Нәтиже:80ұпай,
  • Бағалау ұпайлары4
Соңғы пікірлер
ИМ
Игорь МаксимовҚар. 22, 2024, 11:51 Т.Ж.
Django - Оқулық 017. Теңшелген Django кіру беті Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii LegotckoiҚаз. 31, 2024, 2:37 Т.Қ.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEҚаз. 19, 2024, 8:19 Т.Ж.
Qt Creator көмегімен fb3 файл оқу құралы Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовҚаз. 5, 2024, 7:51 Т.Ж.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Қар. 15, 2024, 6:04 Т.Ж.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectМаусым 4, 2022, 3:49 Т.Ж.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9AnonimҚаз. 25, 2024, 9:10 Т.Ж.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

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