n
npukoluctҚаң. 29, 2019, 1:40 Т.Қ.

Движение персонажа на сцене (Qt+QML)

c++, QML, qt

Добрый день реализовал перемещение персонажа по сцене (и персонаж и сцена унаследованы от QQuickItem), но возникло 2 вопроса:
1)При отпускании клавиши движения(в одну из сторон) хочу чтобы анимация (состоит из четырех кадров) доигрывалась до конца, сейчас персонаж может замереть в любом положении. Как это реализовать? Сам вижу способ реализации, путем выставления флага в методе keyReleaseEvent о том что клавиша отпущена, а остоновку таймера отвечающего за отрисовку анимации перенисти в метод nextFrameHero(), добавив условие, что если флаг в методе keyReleaseEvent выставлен и число кадров кратно 4. Может есть какой-то иной способ этого достичь, или мой способ вполно приемлем?

2)Сейчас слишком большая задержка между нажатиями клавиш движения в разные стороны, при быстрой смене направления движения, как ее снизить?

GameBoxes_wd1R9Io.rar GameBoxes_wd1R9Io.rar

logicscene.h:

#ifndef LOGICSCENE_H
#define LOGICSCENE_H

#include <QQuickItem>
#include <QSGSimpleTextureNode>
#include <QSGTexture>
#include <QQuickWindow>
#include <QKeyEvent>
#include <QTimer>

//подключаем классы объектов
#include "door.h"
#include "hero.h"
#include "box.h"

class LogicScene : public QQuickItem
{
    Q_OBJECT
public:
    LogicScene();
    //установка объектов
    void buildLevel();
    void clearGameScene();

private slots:
    void nextFrameHero();

protected:
    virtual QSGNode* updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) override;
    virtual void keyPressEvent(QKeyEvent *event);
    virtual void keyReleaseEvent(QKeyEvent *event);
signals:

public slots:

private:
    QString backgroundPuth;
    Door *door;
    Hero *hero;
    Box *box;
    QVector <QVector<QQuickItem*>> gameItem; //стакан элементов

    const int sizeItem = 96;
    bool moveRightHero; //кадр вправо? или влево, для спрайта вида как у меня
    QTimer *timerHero; //для смены кадров
    int countTimerHero = 0; //счетчик когда отключить
    int currentDirHero = 0; //направление

};

#endif // LOGICSCENE_H

logicscene.cpp:

#include "logicscene.h"

LogicScene::LogicScene()
{
    setFlag(QQuickItem::ItemHasContents);
    backgroundPuth = ":/gameboxes/background_2.png";
    buildLevel();

    timerHero = new QTimer(this);
    connect(timerHero, &QTimer::timeout, this, &LogicScene::nextFrameHero);
}

void LogicScene::buildLevel()
{
    clearGameScene();
    door = new Door();
    door->setParentItem(this);


    hero = new Hero(96, 96, sizeItem);
    hero->setParentItem(this);


    box = new Box(192, 96);
    box->setParentItem(this);



}

void LogicScene::clearGameScene()
{
    for (int i = 0; i < 10; i++)
    {
        QVector <QQuickItem*> temp;
        for (int j = 0; j<20; j++)
        {
            temp.push_back(new QQuickItem());
        }
        gameItem.push_back(temp);
    }
}

void LogicScene::nextFrameHero()
{
    //увеличваем счетчик кадров
    countTimerHero++;
    //определяем позицию кадра по оси y
    hero->setCurrentFrame_y(sizeItem*currentDirHero); //!!!Потом возможно передавать лишь направление, так как перс знает размер
    //определяем сторону анимации влево или вправо по спрайту
    int tempFrame_x = hero->getCurrentFrame_x();
    if (tempFrame_x == 0)
    {
        moveRightHero = true;
    }
    if (tempFrame_x == (sizeItem*2))
    {
        moveRightHero = false;
    }
    if (moveRightHero)
    {
        //смещаем вправо на кадр
        hero->setCurrentFrame_x(tempFrame_x+sizeItem);
    }
    else
    {
        //смещаем влево на кадр
        hero->setCurrentFrame_x(tempFrame_x-sizeItem);
    }
    //само смещение на сцене
    if (currentDirHero==0)
    {
        int tempPos_y = hero->getCurrentPos_y();
        hero->setCurrentPos_y(tempPos_y+sizeItem/8);
    }
    else if (currentDirHero==1)
    {
        int tempPos_x = hero->getCurrentPos_x();
        hero->setCurrentPos_x(tempPos_x-sizeItem/8);
    }
    else if (currentDirHero==2)
    {
        int tempPos_x = hero->getCurrentPos_x();
        hero->setCurrentPos_x(tempPos_x+sizeItem/8);
    }
    else
    {
        int tempPos_y = hero->getCurrentPos_y();
        hero->setCurrentPos_y(tempPos_y-sizeItem/8);
    }
    hero->update();

}

QSGNode *LogicScene::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *updatePaintNodeData)
{
        //этот параметр не используем
        Q_UNUSED(updatePaintNodeData)

        QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode *>(oldNode);
        //если нода не существует
        if (!node) {
         node = new QSGSimpleTextureNode();
         QImage img(backgroundPuth);
         QSGTexture *texture = window()->createTextureFromImage(img);
         node->setTexture(texture);
        }


        node->setRect(boundingRect());


        return node;

}

void LogicScene::keyPressEvent(QKeyEvent *event)
{
    if ((event->isAutoRepeat()))
        {
            return;
        }
    switch (event->key())
    {
        case Qt::Key_Down:
        {

            if (countTimerHero ==0) //чтоб не было ложных срабатываний при частых нажатиях
            {
                currentDirHero = 0;
                moveRightHero = true;

                timerHero->start(50);
            }

            break;
        }
        case Qt::Key_Up:
        {

            if (countTimerHero ==0) //чтоб не было ложных срабатываний при частых нажатиях
            {
                currentDirHero = 3;
                moveRightHero = true;

                timerHero->start(50);
            }
            break;
        }
        case Qt::Key_Left:
        {
            if (countTimerHero ==0) //чтоб не было ложных срабатываний при частых нажатиях
            {
                currentDirHero = 1;
                moveRightHero = true;

                timerHero->start(50);
            }
            break;
        }
        case Qt::Key_Right:
        {
            if (countTimerHero ==0) //чтоб не было ложных срабатываний при частых нажатиях
            {
                currentDirHero = 2;
                moveRightHero = true;

                timerHero->start(50);
            }
            break;
        }
    }
    QQuickItem::keyPressEvent(event);
}

void LogicScene::keyReleaseEvent(QKeyEvent *event)
{

    if ((event->isAutoRepeat()))
        {
            return;
        }

    switch (event->key())
    {
        case Qt::Key_Down:
        case Qt::Key_Up:
        case Qt::Key_Left:
        case Qt::Key_Right:
        {

            timerHero->stop();
            countTimerHero = 0;
            break;
        }


    }
    QQuickItem::keyReleaseEvent(event);
}

hero.h:

#ifndef HERO_H
#define HERO_H

#include <QQuickItem>
#include <QSGSimpleTextureNode>
#include <QSGTexture>
#include <QQuickWindow>
#include <QTimer>

class Hero : public QQuickItem
{
    Q_OBJECT
public:
    Hero(int pos_x, int pos_y, int sizeItem);
    void animationMove(int direction, int step);

    int getCurrentPos_x() const;
    void setCurrentPos_x(int value);

    int getCurrentPos_y() const;
    void setCurrentPos_y(int value);

    void setCurrentFrame_x(int value);

    void setCurrentFrame_y(int value);

    int getCurrentFrame_x() const;

    int getCurrentFrame_y() const;

protected:
    virtual QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) override;

signals:

public slots:

private:
    QString imgPuth;
    int currentPos_x; //текущая позиция х - на сцене
    int currentPos_y; //текущая позиция у - на сцене

    int currentFrame_x; // текущий кадр по х
    int currentFrame_y; // текущий кадр по у
    int size = 0;



};

#endif // HERO_H

hero.cpp:

#include "hero.h"

Hero::Hero(int pos_x, int pos_y, int sizeItem)
{
    setFlag(QQuickItem::ItemHasContents);
    imgPuth = ":/gameboxes/people2.png";
    currentPos_x = pos_x;
    currentPos_y = pos_y;
    size = sizeItem;
    currentFrame_x = size * 1;
    currentFrame_y = size * 0;

}

QSGNode *Hero::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *updatePaintNodeData)
{
    Q_UNUSED(updatePaintNodeData)

    QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode *>(oldNode);
    //если нода не существует
    if (!node) {
     node = new QSGSimpleTextureNode();
     QImage img(imgPuth);
     QSGTexture *texture = window()->createTextureFromImage(img);
     //node->setSourceRect(96,0,96,96); //показывает часть текстуры
     node->setSourceRect(currentFrame_x,currentFrame_y,size,size);
     node->setTexture(texture);

    }
    else
    {
        node->setSourceRect(currentFrame_x,currentFrame_y,size,size);
    }

    //
    //node->setRect(0,96,96,96); // размер области
    node->setRect(currentPos_x,currentPos_y,size,size);
    return node;
}

int Hero::getCurrentFrame_y() const
{
    return currentFrame_y;
}

int Hero::getCurrentFrame_x() const
{
    return currentFrame_x;
}

void Hero::setCurrentFrame_y(int value)
{
    currentFrame_y = value;
}

void Hero::setCurrentFrame_x(int value)
{
    currentFrame_x = value;
}

int Hero::getCurrentPos_y() const
{
    return currentPos_y;
}

void Hero::setCurrentPos_y(int value)
{
    currentPos_y = value;
}

int Hero::getCurrentPos_x() const
{
    return currentPos_x;
}

void Hero::setCurrentPos_x(int value)
{
    currentPos_x = value;
}

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

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

1
Evgenii Legotckoi
  • Ақп. 1, 2019, 6:28 Т.Ж.
  • (өңделген)

Добрый день!

Первое, что стоит вам сделать, так это сделайте кэш для QSGTexture - создание этих текстур является очень накладной операцией. При этом эти текстуры могут использоавться где угодно, и сколько угодно раз. То есть имея один единственный инстанс текстуры, вы можете использовать этот инстанс где угодно и сколько угодно раз. Для кэша можно использовать синглетон. Проверьте, как будет работать с кэшем, возможно, что всё будет гораздо быстрее и вам уже не понадобится улучшение кода.

    Пікірлер

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

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

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