Движение персонажа на сцене (Qt+QML)
Добрый день реализовал перемещение персонажа по сцене (и персонаж и сцена унаследованы от QQuickItem), но возникло 2 вопроса:
1)При отпускании клавиши движения(в одну из сторон) хочу чтобы анимация (состоит из четырех кадров) доигрывалась до конца, сейчас персонаж может замереть в любом положении. Как это реализовать? Сам вижу способ реализации, путем выставления флага в методе keyReleaseEvent о том что клавиша отпущена, а остоновку таймера отвечающего за отрисовку анимации перенисти в метод nextFrameHero(), добавив условие, что если флаг в методе keyReleaseEvent выставлен и число кадров кратно 4. Может есть какой-то иной способ этого достичь, или мой способ вполно приемлем?
2)Сейчас слишком большая задержка между нажатиями клавиш движения в разные стороны, при быстрой смене направления движения, как ее снизить?
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
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.Вам це подобається? Поділіться в соціальних мережах!
- Akiv Doros
- 11 листопада 2024 р. 14:58
C++ - Тест 004. Указатели, Массивы и Циклы
- Результат:50бали,
- Рейтинг балів-4
- molni99
- 26 жовтня 2024 р. 01:37
C++ - Тест 004. Указатели, Массивы и Циклы
- Результат:80бали,
- Рейтинг балів4
- molni99
- 26 жовтня 2024 р. 01:29
C++ - Тест 004. Указатели, Массивы и Циклы
- Результат:20бали,
- Рейтинг балів-10
Добрый день!
Первое, что стоит вам сделать, так это сделайте кэш для QSGTexture - создание этих текстур является очень накладной операцией. При этом эти текстуры могут использоавться где угодно, и сколько угодно раз. То есть имея один единственный инстанс текстуры, вы можете использовать этот инстанс где угодно и сколько угодно раз. Для кэша можно использовать синглетон. Проверьте, как будет работать с кэшем, возможно, что всё будет гораздо быстрее и вам уже не понадобится улучшение кода.