n
npukoluctҚаң. 30, 2019, 12: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, 5:28 Т.Қ.
  • (өңделген)

Добрый день!

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

    Пікірлер

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

    Qt - Тест 001. Сигналы и слоты

    • Нәтиже:84ұпай,
    • Бағалау ұпайлары4
    Ua

    Qt - Тест 001. Сигналы и слоты

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

    Qt - Тест 001. Сигналы и слоты

    • Нәтиже:47ұпай,
    • Бағалау ұпайлары-6
    Соңғы пікірлер
    ИМ
    Игорь МаксимовҚар. 22, 2024, 9:51 Т.Қ.
    Django - Оқулық 017. Теңшелген Django кіру беті Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
    Evgenii Legotckoi
    Evgenii LegotckoiҚаз. 31, 2024, 11:37 Т.Қ.
    Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
    A
    ALO1ZEҚаз. 19, 2024, 5:19 Т.Қ.
    Qt Creator көмегімен fb3 файл оқу құралы Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
    ИМ
    Игорь МаксимовҚаз. 5, 2024, 4:51 Т.Қ.
    Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
    d
    dblas5Шілде 5, 2024, 8:02 Т.Қ.
    QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
    Енді форумда талқылаңыз
    f
    firstlunoxodАқп. 15, 2025, 1:46 Т.Қ.
    Рисование на QGraphicsScene при зажатой кнопке мыши Подскажите, пожалуйста! Как данный класс можно дополнить, чтобы созданные объекты можно было перемещать мышкой по сцене?
    Дмитрий
    ДмитрийАқп. 3, 2025, 4:24 Т.Қ.
    Создание deb-пакета. Как создать ярлык на рабочем столе после установки собственного deb-пакета? Всем привет. Сделал свой deb-пакет с программой. Всё устанавливается и работает. Ставлю по пути /usr/bin/my_application. Как для пользователя при установке пакета сразу создать ярлык на раб…
    NW
    Nayo WaiҚаң. 30, 2025, 7:22 Т.Қ.
    не запускается компьютер!!! Не запускается компьютер (точнее работает блок , но сам монитор вообще жесть)В общем я ничего с интернета не скачивала в последнее время. На компе никаких левых пр…
    n
    nklyҚаң. 3, 2025, 12:52 Т.Қ.
    Нужно запретить перемещение только некоторых итемов, остальные перемещать можно. Вопрос решен. Узнать QModelIndex элемента на который мы перетаскиваем другой элемент, можно с помощью функции indexAt(event->position().toPoint()) представления QTreeViev вызываемой в переопр…
    M
    MarselТам. 17, 2023, 12:26 Т.Ж.
    OAuth2.0 через VK, получение email Спасибо большое за помощь и простите за то что отнял время своей невнимательностью.

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