n
Jan. 29, 2019, 12:40 p.m.

Движение персонажа на сцене (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;
}

10% refund of hotel reservation amount on Booking
10% refund of hotel reservation amount on Booking
We offer a link with a 10% return on the amount of the order when booking a hotel through Booking
1

Добрый день!

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

Comments

Only authorized users can post comments.
Please, Log in or Sign up
D
Aug. 16, 2019, 11:58 a.m.
Damir

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

  • Result:92points,
  • Rating points8
D
Aug. 16, 2019, 11:46 a.m.
Damir

C++ - Test 005. Structures and Classes

  • Result:75points,
  • Rating points2
u
Aug. 14, 2019, 1:55 p.m.
unrealproro

C++ - Test 005. Structures and Classes

  • Result:83points,
  • Rating points4
Last comments
Aug. 19, 2019, 6:41 a.m.
Andrej Jankovich

это проблема дистрибутива, попробуйте установить через пакетный менеджер snap Суть проблемы: libQt5Core которая лежит в дистрибутиве требует версию glibc >= 2.25 у вас видимо …
b
Aug. 18, 2019, 5:09 a.m.
bbb116

cqtdeployer /home/aleks/CQtDeployer/bin/cqtdeployer: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.25' not found (required by /home/aleks/CQtDeployer/lib/libQt5Core.so.5) linux mint …
D
Aug. 17, 2019, 8:04 a.m.
Damir

github ChekableTView Правой групповая смена значения при перетаскивании левой как обычно.
Aug. 16, 2019, 12:03 p.m.
Evgenij Legotskoj

Потому, что в минуте 60 секунд
Aug. 16, 2019, 11:16 a.m.
Dmitrij

а почему делитель 60000, а не 1000?
Now discuss on the forum
Aug. 19, 2019, 10:29 a.m.
Aleksej Vnukov

я в дороге, по тому примеру что в есть выше вам чтоб заработало нужно примерно следующее ListModel{ id: list_model } в ListView добавить model:list_model там где кноп…
Aug. 19, 2019, 8:47 a.m.
Pavel K.

bool YourClass::chekIfEmpty(const QString& table) { return getCount(table) == 0;}int YourClass::getCount(const QString& table, const QString& where) { QString command =…
Aug. 19, 2019, 8:29 a.m.
Pavel K.

посмотрите тут , практически тоже самое делал(пробегал по документу). А так в принципе : QFile file(Path);if(file.exist){ file.open(QIODevice::WriteOnly); // ReadWrite for…
Aug. 19, 2019, 2:39 a.m.
grig_p

Здравствуйте! Хотелось бы в своем приложении сделать цетрализованную обработку исключительных ситуаций для их логирования. Переопределил метод notify(): static const int EC_MAINLOOP…
Aug. 15, 2019, 2:19 a.m.
Mihailll

Плюсы и qml отличаются, с++ логичней
Looking for a Job?
14,000.00 руб. - 40,000.00 руб.
Разработчик Qt
Annino, Moscow Oblast, Russia
5,000.00 руб. - 15,000.00 руб.
Дизайнер
Moskovskiy, Moscow, Russia
25,000.00 руб. - 30,000.00 руб.
Разработчик Qt/C++
Barnaul, Altai Krai, Russia

For registered users on the site there is a minimum amount of advertising

EVILEG
About
Services
© EVILEG 2015-2019
Recommend hosting TIMEWEB