Evgenii Legotckoi
Evgenii LegotckoiҚыр. 28, 2015, 12:29 Т.Қ.

GameDev on Qt - 1-сабақ. QGraphicsScene ішінде тінтуірдің қозғалысын бақылау

Кримсонленд ойыны бәрінің есінде ме? Онда құбыжықтарды үйіп-қонып түсіру керек болды. Ойын алаңында қозғалу үшін біз W, A, S, D, пернелерін және түсіру бағыты үшін курсор тышқан , одан кейін бақылауды қолдандық. Сонымен, бұл тінтуірді бақылаудың жұмыс механизмі өте қарапайым. Бағдарламалауда қолданылатын құралдарға байланысты көптеген іске асырулар болуы мүмкін, бірақ егер біз әдеттегі QGraphicsScene туралы айтатын болсақ, онда мен сізге осындай механизмді енгізуді көрсетуге рұқсат етіңіздер. .

Жоба құрылымы

Негізгі файлдардан басқа, бұл жоба екі қосымша сыныпты пайдаланады. Біріншісі - курсор орнын бақылайтын және оның орны туралы ақпаратты беретін реттелетін QGraphicsScene , ал екіншісі - басты кейіпкер, біздің сүйікті Қызыл үшбұрыш , біз оны арқылы басқарамыз. W пернелері, A, S, D.

Жоба құрылымы:

  • TargetMotion.pro - Жоба профилі;
  • widget.h - Негізгі қолданба терезесінің тақырып файлы;
  • widget.cpp - Негізгі қолданба терезесі үшін бастапқы код файлы;
  • triangle.h - Басты кейіпкердің тақырып файлы Қызыл үшбұрыш;
  • triangle.cpp - Қызыл үшбұрыштың негізгі таңбасының бастапқы код файлы;
  • customscene.h - теңшелген графикалық көрініс тақырыбы файлы;
  • customscene.cpp - теңшелген графикалық көріністің бастапқы код файлы;
  • cursor.qrc - теңшелген тінтуір курсоры бар ресурс файлы.

Тінтуірді бақылауды жазу

widget.ui

Қолданбаның негізгі терезесіне арналған пішін файлы. Біз жай ғана оған QGraphicsView класының объектісін лақтырып, оны бүкіл терезеге созамыз.

customscene.h

Бұл тақырып файлында тек тінтуірдің mouseMoveEvent() қозғалысын бақылау әдісін және сыныпты мұрагер етуді есте сақтай отырып, тінтуір орнының координаталары берілетін сигналды жариялау ғана қажет. QGraphicsScene. сайтынан

#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);
};

#endif // CUSTOMSCENE\_H

customscene.cpp

Сенсеңіз де, сенбесеңіз де, бастапқы файлда mouseMoveEvent. әдісіндегі координаттары бар сигналды шақырамыз.

#include "customscene.h"

CustomScene::CustomScene(QObject *parent) :
    QGraphicsScene()
{
    Q\_UNUSED(parent);
}

CustomScene::~CustomScene()
{

}

void CustomScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    emit signalTargetCoordinate(event->scenePos());
}

үшбұрыш.сағ

Енді біз кейіпкерімізді дұрыс көрсету және ойында курсорды бақылауды жүзеге асыру үшін қажетті барлық нысандар мен функцияларды жариялаймыз. Осы сыныптың жұмысын және оның шығу тегі туралы толығырақ түсіну үшін [Qt оқулықтары] бөлімінде ұсынылған «Qt ойынын қалай жазуға болады» мақалалар сериясын оқуды ұсынамын (https). ://evileg.com/knowledge/qt/).

Ескерту . WinAPI кітапханалары түймелерді басуды өңдеу үшін пайдаланылады.

#ifndef TRIANGLE\_H
#define TRIANGLE\_H

#include <QObject>
#include <QGraphicsItem>
#include <QPainter>
#include <QPolygon>
#include <QTimer>

#include <windows.h>

class Triangle : public QObject, public QGraphicsItem
{
    Q\_OBJECT
public:
    explicit Triangle(QObject *parent = 0);
    ~Triangle();

signals:

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

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

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

private:
    QTimer *gameTimer;      // Игровой таймер
    QPointF target;         // Положение курсора
};

#endif // TRIANGLE\_H

triangle.cpp

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

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

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(QObject *parent) :
    QObject(parent), QGraphicsItem()
{
    setRotation(0);      // Устанавливаем исходный разворот треугольника
    gameTimer = new QTimer();   // Инициализируем игровой таймер
    // Подключаем сигнал от таймера и слоту обработки игрового таймера
    connect(gameTimer, &QTimer::timeout, this, &Triangle::slotGameTimer);
    gameTimer->start(10);   // Стартуем таймер
    target = QPointF(0,0);  // Устанавливаем изначальное положение курсора
}

Triangle::~Triangle()
{

}

QRectF Triangle::boundingRect() const
{
    return QRectF(-20,-30,40,60);
}

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

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

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);
    }
}

void Triangle::slotGameTimer()
{
    /* Перемещаем треугольник в зависимости от нажатых кнопок
     * */
    if(GetAsyncKeyState('A')){
        this->setX(this->x() - 2);
    }
    if(GetAsyncKeyState('D')){
        this->setX(this->x() + 2);
    }
    if(GetAsyncKeyState('W')){
        this->setY(this->y() - 2);
    }
    if(GetAsyncKeyState('S')){
        this->setY(this->y() + 2);
    }

    /* Проверка выхода за границы поля
     * Если объект выходит за заданные границы, то возвращаем его назад
     * */
    if(this->x() - 30 < 0){
        this->setX(30);         // слева
    }
    if(this->x() + 30 > 500){
        this->setX(500 - 30);   // справа
    }

    if(this->y() - 30 < 0){
        this->setY(30);         // сверху
    }
    if(this->y() + 30 > 500){
        this->setY(500 - 30);   // снизу
    }

    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);
    }
}

виджет.h

Енді сіз барлығын негізгі қолданба терезесінің класында орналасатын ойын өзегіне біріктіруіңіз керек.

#ifndef WIDGET\_H
#define WIDGET\_H

#include <QWidget>
#include <QGraphicsScene>
#include <QGraphicsItem>

#include <triangle.h>
#include <customscene.h>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q\_OBJECT

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

private:
    Ui::Widget *ui;
    CustomScene  *scene;    // Объявляем графическую сцену
    Triangle *triangle;     // Объявляем треугольник
};

#endif // WIDGET\_H

widget.cpp

Бұл файл барлық ойын объектілерін (графикалық көрініс пен үшбұрыш) жариялайды және инициализациялайды, сонымен қатар графикалық көріністен үшбұрышқа сигнал жіберілетін Bridge типті дизайн үлгісін пайдаланады.

#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);  /// Устанавливаем графическую сцену в graphicsView
    ui->graphicsView->setRenderHint(QPainter::Antialiasing);    /// Устанавливаем сглаживание
    ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); /// Отключаем скроллбар по вертикали
    ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); /// Отключаем скроллбар по горизонтали

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

    // Создаем кастомизированный курсор из ресурсного файла
    QCursor cursor = QCursor(QPixmap(":/cursor/cursorTarget.png"));
    ui->graphicsView->setCursor(cursor);    // Устанавливаем курсор в QGraphicsView
    triangle = new Triangle();  // Инициализируем треугольник
    triangle->setPos(250,250);  // Устанавливаем стартовую позицию треугольника
    scene->addItem(triangle);   // Добавляем треугольник на графическую сцену

    /* Разрешаем отслеживание положение курсора мыши
     * без необходимости нажатия на кнопки мыши
     * Применяем это свойство именно для QGraphicsView,
     * в котором установлена графическая сцена
     * */
    ui->graphicsView->setMouseTracking(true);

    // Подключаем сигнал от графической сцены к слоту треугольника
    connect(scene, &CustomScene::signalTargetCoordinate, triangle, &Triangle::slotTarget);
}

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

Барлығы

Нәтижесінде сіз графикалық көріністе үшбұрыш аласыз, ол W, A, S, D пернелерінің әсерінен оның бойымен қозғалады және графикалық көрініс ішінде болса, әрқашан тінтуір курсорына қарайды. .

Бұл мысалдың демонстрациясы осы мақалаға арналған бейне оқулықта берілген.

Бейне оқулық

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

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

r
  • Ақп. 10, 2018, 10:12 Т.Ж.

А где можно найти полный код проекта (проектов)? У меня ошибки линковки типа ( LNK2019: ссылка на неразрешенный внешний символ "public: void __cdecl Triangle::slotTarget(class QPointF)" (?slotTarget@Triangle@@QEAAXVQPointF@@@Z) в функции "public: __cdecl Widget::Widget(class QWidget *)" ).  И может кто подскажет как поправить?

Evgenii Legotckoi
  • Ақп. 11, 2018, 9:21 Т.Ж.

Вот в этой статье в конце есть полный проект.

r
  • Ақп. 11, 2018, 10:45 Т.Ж.

спасибо

r
  • Ақп. 11, 2018, 10:47 Т.Ж.

а если например я хочу сделать вместо треугольников - текстурки, я могу это сделать в этом виджете Qt? или надо брать что то другое?

Evgenii Legotckoi
  • Ақп. 11, 2018, 11:22 Т.Ж.

Для отрисовки используется объект класса QPainter  методе paint у треугольника. А этот класс QPainter имеет метод drawPixmap(), который может отрисовывать изображение из png файла например. Поэтому да, можете лишь переписать метод paint, и отрисовывать текстуры.

r
  • Ақп. 11, 2018, 11:28 Т.Ж.

еще такой вопрос. у меня Qt ругается на GetAsyncKeyState (ошибка линковки). Надо либу какую то подключить? 2) а есть такая функция н кросс платформенная (зачем в таком достаточно высокоуровневом фреймворке использовать winApi?)?

Evgenii Legotckoi
  • Ақп. 11, 2018, 11:35 Т.Ж.

Для MSVC пропишите в pro файле проекта следующие строчки

win32-msvc*{
    LIBS += -luser32
}
Видите ли, фреймворк может и достаточно высокоуровневый, но некоторый особенности работы в нём не реализованы в кросплатформенном варианте.
Например, нет тех же самых глобальных хоткеев . Я сам занимался реализацией подобного функционала для одного своего проекта.
 
Поэтому и проверка статуса клавиш тоже из этого разряда. А если говорить конкретнее, то проблема в том, что состояния клавиш проходят через цепочку событий
Evgenii Legotckoi
  • Ақп. 11, 2018, 11:39 Т.Ж.

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

r
  • Ақп. 11, 2018, 11:50 Т.Ж.

я собираю под win64.    LIBS += -luser32 и  LIBS += -luser64 не помогает

Evgenii Legotckoi
  • Ақп. 12, 2018, 1:22 Т.Ж.

Вы вообще что-то своё уже пишите, или как? Я скачал проект, запустил его на работе на Win64 и он работает.

А так по факту заголовочник нужен
#include <windows.h>
r
  • Ақп. 12, 2018, 12:39 Т.Қ.

Да нет. Чет у меня с qt только проблемы. Ваш проект так в qt не смог собрать (из за GetAsyncKeyState). Собрал его в visual studio, но там почему то пришлось в ручную кидать .dll в каталог (хотя путь добавлял) (может тут что изменить см скрин https://yadi.sk/i/-D9CsBhh3SL2eQ ).

r
  • Ақп. 12, 2018, 1:01 Т.Қ.

Еще пару вопросов по code-style

1)override в qt не используется?
2)почему 0 а не nullptr ?
3)макрос Q_UNUSED. Почему нельзя просто не давать переменным имя и тд?
4)Зачем объявлять что то если там пустое тело?  (2)
5)Зачем прописывать вызов конструктора по умолчанию? (2)
6)Почему иногда не чистится динамическая память? это ошибка? не лучше ли использовать std::unique_ptr указатели вместо обычных?
7)почему нужно объявлять именно указатели на объекты и вызывать new в конструкторе, а не просто делать объекты членами класса (а не их указатели)?
8) такие штуки как public slots: , где  slots макрос который раскрывается в ничего. Для чего нужны? (просто для оформления)?
9) такие штуки как emit. Это пустые макросы. Они для оформления, или код сначала прогоняется в компиляторе qt который понимает эти "ключевые слова" ?

Evgenii Legotckoi
  • Ақп. 12, 2018, 4:21 Т.Қ.

Честно говоря... не знаю... Я не работаю с Visual Studio вообще. В основном Qt Creator, да иногда с CLion. Больше походит на то, что у вас некорректно установлены пути к библиотекам Qt в операционной системе. Либо сама Visual Studio криво встала.

Evgenii Legotckoi
  • Ақп. 12, 2018, 4:56 Т.Қ.

По code-style

Признаюсь честно, сам находился в плавающем состоянии, когда писал ранние статьи, как раз чтобы всё уложить в голове по полочкам, поэтому многие ваши замечания весьма к месту. Но сейчас могу более адекватно и развёрнуто Вам ответить на ваши вопросы.
  1. override в Qt используется, но они в своей странной манере в очередной раз всё переопределили своими макросами, хотя наверняка были ещё какие-то причины, которые сейчас можно считать морально устаревшими. По факту у них есть макрос Q_OVERRIDE, но я всегда пишу override (до кучи ещё и virtual добавляю), а в использовании Q_OVERRIDE не вижу смысла.
  2. На момент изучения всей этой кухни Qt не особо обратил внимание на этот момент, да и не работал плотно в рамках стандарта C++11, а так да, лучше использовать nullptr . Сейчас всегда его использую.
  3. Это уже вопрос вкусовщины. Я придерживался рамок code-style Qt, а по факту можно и не писать имя переменной, разницы принципиально никакой не будет. Q_UNUSED всё равно приводит переменную к void и типо она используется.
  4. Относительно конструкторов и деструкторов - это привычка, писать их реализацию.
  5. Там лучше передать parent`а в конструктор базового класса, мой косяк.
  6. Насчёт памяти в Qt такая ситуация, у всех классов, наследованных от Qt желательно передавать parent. Тогда при уничтожении, parent будет прибирать за собой всех потомков, поэтому и не потребуется использовать умные указатели. В этом примере некоторые недочёты имеются, нужно передавать парента при создании объекта, чего я не везде сделал, тогда утечек не будет.
  7. Лучше, как вы и сказали объявлять объекты членами класса, там например QTimer можно объявить  на стеке. Не помню, только с графической сценой как лучше будет, точно помню есть проблемы с объектами QGraphicsItem , их всегда приходится объявлять в куче, на стеке память не выделить. Работать просто не будет. С графической сценой кажется тоже какие-то проблемы в отображении были, не помню уже.
  8. Объявление в качестве slots нужно было для формирования moc файлов, когда использовался старый синтаксис сигналов и слотов на основе макросов. Скомпилироваться-то скомпилируется, если слот не объявлен в секции слотов, но работать не будет... А вот в случае с новым синтаксисом на основе указателей на методы уже да, не обязательно писать slots и т.д. Но по мне здесь лучше оставить их, это уже вопрос код стайла и разделения по секциями методов, которые должны использоваться как слоты, а какие нет.
  9. а вот emit - это действительно пустышки, я пытался найти адекватное объяснение, для чего они, но кроме того, что это синтаксический сахар, который призван указать вызов именно метода сигнала в коде, ничего не нашёл. Обычно всегда пишу их, чтобы глазу было за что зацепиться. Возможно раньше, в более ранних версиях Qt это было обязательным, сейчас точно нет. Но я застал только Qt 4.8, да и то только вскользь.
r
  • Ақп. 13, 2018, 11:35 Т.Ж.

Спасибо за ответы. Еще хотел спросить. Вы занимались программированием сетевых игр? вот например если у нас 2 клиента (у каждого свой треугольник). Как например синхронизируется картинка, сколько раз в секунду передаются действия? просто не оч понимаю как удается избегать задержек и делать плавную картинку

r
  • Ақп. 13, 2018, 3:24 Т.Қ.

А и по библиотеке. Зачем у qt своя библиотека вещей которые есть в в stl, boost и тд. Например зачем использовать всякие вектора Qt и тд когда они есть в stl? Или это зачем то нужно?

Evgenii Legotckoi
  • Ақп. 13, 2018, 3:38 Т.Қ.

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


По факту синхронизация изображения должна соответствовать как минимум FPS, в идеале не ниже 60 раз в секунду, лучше больше. Но для очень динамичных игр используется не только передача данных о положении объектов, но и методологии предсказания будущего положения игроков и объектов в самой игре без получения данных от сервера или другого игрока. Именно поэтому иногда возникают лаги, когда вашего игрока перекидывает в другое место карты. Просто предсказание сработало неправильно, а при очередном обновлении данных от сервера игра скорректировала положения игрока на карте.  Это очень большая и обширная тема... к сожалению я тут профан.

Моё основное направление сейчас - это программное обеспечение для расчётов нагрузок строительных конструкций и зданий. В основном модели данных и взаимодействие всех компонентов системы. И т.д.
Evgenii Legotckoi
  • Ақп. 13, 2018, 3:48 Т.Қ.

Ммм... здесь за версту отдаёт желанием написать всё своё. Кстати, голос разума у них всё-таки проснулся в Qt 5. Например, для сортировки там используется и рекомендуется уже std::sort , вместо qSort, который они пометили как deprecated. Что касается контейнеров, то у контейнеров Qt есть кое-какие удобные методы. Но последнее время я перехожу на контейнеры stl. Они гораздо функциональнее. Что касается boost, то сигналы и слоты, которые есть в boost, как говорят в интернетах, слизали именно с Qt. Так что все понемножку друг у друга заимствуют.



r
  • Ақп. 14, 2018, 12:35 Т.Қ.

я переопределил paint треугольника. сделал рисование танчика и его пушки.

painter->drawPixmap(-30, -50, *spriteImage, 40, 0, 60, 100);
painter->drawPixmap(-20, -50, *spriteImage, 0, 0, 40, 100);
но текстура пушки белым фоном закрашивает часть танка (см скрины https://yadi.sk/d/QKmAHw8e3SL5A4 ). Как это исправить?
r
  • Ақп. 14, 2018, 12:57 Т.Қ.

разобрался. заменил белый фон на альфаканал.  теперь другой вопрос. вот  Pixmap пушки я хочу поворачивать вокруг своей оси. можно это сделать както через setRotation например? (тоесть нарисовал корпус, повернул обьект, нарисовал пушку)

r
  • Ақп. 14, 2018, 2:32 Т.Қ.

Фух и с этим разобрался. Теперь такой вопрос, а можно ли как-то по лучше обрабатывать столкновения обьектов, и чтоб к стене например можно было подъехать в плотную, и при этом не вьехать в ней повернувшись на месте?

Evgenii Legotckoi
  • Ақп. 14, 2018, 4:28 Т.Қ.

Здесь уже нужно обрабатывать очертания танка и не давать возможность ему разворачиваться, если есть риск въехать в стену.

Но для этого нужно немного изменить логику обработки коллизий. Дело в том, что в данном варианте коллизии обрабатываются по факту, когда коллизии уже произошли.
А вот следующим шагом можете начать обрабатывать коллизии с предсказанием. То есть условно взять будущее положение танка и проверить на коллизии. У графической сцены есть метод items(), в этот метод можно передать объект QPolygonF, который можете описывать очертания танка в его будущем положении на карте. Если будет возвращён хотя бы один объект, то моно считать, что коллизия имеет место быть, а значит танк нельзя подвинуть или повернуть, а тогда просто не выполняете движение танка в заданном положении.
r
  • Ақп. 16, 2018, 11:22 Т.Ж.

А не подскажите как сделать плавность анимации или как то так. например танк (прямоугольник) едет вверх и вертикален. Потом игрок нажимает клавишу влево и он должен уже ехать вертикально. Можно конечно плавно поворачивать текстуру но я думаю можно сделать лучше. Просто играл в танчики где корпус и пушка могут вращатся и ехать мгновенно на любой градус, и при этом там не было видимого резкого скачка (может это какоето сглаживание?)

Evgenii Legotckoi
  • Ақп. 16, 2018, 3:46 Т.Қ.

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


Нечто подобное я сделал вот в этой статье . Посмотрите следующий метод void Spider::slotGameTimer().

И ещё, у меня просьба. Создавайте, пожалуйста, новые вопросы на форуме . Там можно при создании вопроса указать статью, к которой имеет отношение данный вопрос. Так будет лучше для развития ресурса. Спасибо.
a
  • Мамыр 7, 2018, 1:45 Т.Ж.

forgetting otnasledovat class from QGraphicsScene :D

Evgenii Legotckoi
  • Мамыр 7, 2018, 6:09 Т.Ж.

Ну да, поленился внимательно посмотреть перевод после Google Translate :D

Спасибо, поправил
P.
  • Шілде 11, 2019, 4:08 Т.Ж.

Добрый день!
Я хотел объединить 2 ваших уроков: "GameDev на Qt" и "Как написать игру на Qt", а именно:
1) Передвижение персонажа и его оружия;
2) Вращение оружия с помощью мыши.
Но чтобы я не делал, у меня уже на постоянной основе 10 внутренних, непонятных мне, ошибок.
Если есть возможность, не могли бы вы мне подсказать, что я делаю не так и как это можно это исправить.
Для удобства скидываю всю программу и скриншот ошибок.

NoNameGames.rar NoNameGames.rar

Evgenii Legotckoi
  • Шілде 11, 2019, 4:13 Т.Ж.
  • (өңделген)

Добрый день! На сам проект у меня пока нет времени посмотреть, но судя по ошибке, вам нужно добавить макрос Q_OBJECT в triangle и в widget.

Обычно выглядит так

class Triangle
{
    Q_OBJECT
public:
    // остальной код
};

P.
  • Шілде 11, 2019, 4:22 Т.Ж.

В том то и дело, я добавлял, удалял, миксовал, но всё равно эти ошибки появляются раз за разом.
Если во всех файлах оставить "Q_OBJECT", то появляются данные ошибки:

G
  • Жел. 10, 2021, 11:22 Т.Ж.

Здравствуйте! Прохожу 1ю часть GameDev на Qt. Сделал код, однако выдает ошибки. Не подскажете что с этим делать?

ЛД
  • Шілде 13, 2022, 2:04 Т.Қ.
  • (өңделген)

Вполне возможно, что ты не закинул graphicsView в дизайнере в виджет

ЛД
  • Шілде 13, 2022, 2:07 Т.Қ.

Кому интересно, поворот в slotTarget можно в одну строку организовать

this->setRotation(90 + rotation() + qRadiansToDegrees(qAtan2(mapFromScene(point).y(), mapFromScene(point).x())));
ЛД
  • Шілде 13, 2022, 2:10 Т.Қ.

Вполне возможно, что ты не закинул graphicsView в дизайнере в виджет

Пікірлер

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

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 Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

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