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

    Пікірлер

    Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
    Кіріңіз немесе Тіркеліңіз
    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 аналогично. Могу предположить, что из-за более новой верси…
    Енді форумда талқылаңыз
    n
    nklyҚаң. 3, 2025, 2:52 Т.Ж.
    Нужно запретить перемещение только некоторых итемов, остальные перемещать можно. Вопрос решен. Узнать QModelIndex элемента на который мы перетаскиваем другой элемент, можно с помощью функции indexAt(event->position().toPoint()) представления QTreeViev вызываемой в переопр…
    AW
    Ayden WatkinsҚаң. 2, 2025, 12:09 Т.Ж.
    Why Paying for a Research Paper Can Be a Smart Choice Writing a research paper can be a daunting task, especially when faced with tight deadlines, complex topics, or a lack of resources. For many students, paying for a research paper is a practical…
    p
    pimacontrols85Жел. 31, 2024, 9:39 Т.Ж.
    Finding the Right Rittal Small Enclosure for Your Needs Rittal is a leading manufacturer of enclosures for industrial and IT applications. Their small enclosures offer a compact and reliable solution for a wide range of needs, from housing electronic…
    Donald Randolph
    Donald RandolphЖел. 30, 2024, 2:59 Т.Ж.
    Personal Injury lawyer Santa Monica As an experienced Santa Monica personal injury lawyer, Donald C. Randolph has recovered over $100 Million in verdicts and settlements for our clients. In severe injury cases, this compensation i…
    Nirvana Yoga School
    Nirvana Yoga SchoolЖел. 30, 2024, 5:13 Т.Ж.
    OAuth2.0 через VK, получение email Nirvana Yoga School is one of the most trusted and reputed traditional Rishikesh yoga courses , India certified by Yoga Alliance, USA. We aim to spread traditional yoga teachings so t…

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