带有一个或多个GIF动画的QGraphicsView在Android上运行缓慢

问题描述

上下文

我正在使用c ++ / Qt5开发跨平台游戏。它必须可以在Windows,Linux,Macos,Android和iOS上运行。到目前为止,我已经在Windows上开发了该游戏,并且没有任何问题。但是,昨天在Android上进行部署时,QGraphicsView上存在性能和停顿的巨大问题。经过调查,我发现删除动画gif可以解决我的表演问题。

此外,我在QGraphicsView上做的动画也口吃。现在已经解决了,但是口吃动画的代码可能会提示问题:

void Renderer::move(QGraphicsItem *item,const QPoint &destination,int totalTime)
{
    if (totalTime >= 0 && item->pos() != destination) {
        QVector2D diff = QVector2D(destination - item->pos());

        float time = (float)totalTime / 10;

        if (time < 1)
            time = 1;

        float speed = (std::sqrt(std::pow(diff.x(),2) + std::pow(diff.y(),2))) / time;

        diff.normalize();
        QPointF nextPos = item->pos() + (diff.toPoint() * speed);

        item->setPos(nextPos);

        QTimer::singleShot(10,[this,item,destination,totalTime]() {
            move(item,totalTime - 10);
        });
    }
}

对于那些感兴趣的人,我已经按照this question

的答案解决了这个问题

问题

我已从资产中删除了所有动画gif,以制作演示版本。但是它已经变得真正静止了。动态的gif文件使游戏看起来非常酷。我该如何解决性能问题?

我尝试过的事情

这是QGraphicsView内第一个动画gif的实现:

// pixmapitem.hxx
class PixmapItem : public QObject,public QGraphicsPixmapItem {
    Q_OBJECT
  public:
    explicit PixmapItem(const Sprite::Asset asset,const QSize &size,QGraphicsItem *parent = nullptr);

    ~PixmapItem();

  private:
    QMovie *_gif;
};

// pixmapitem.cxx
PixmapItem::PixmapItem(const Sprite::Asset asset,QSize const &size,QGraphicsItem *parent)
    : QObject(),QGraphicsPixmapItem(parent),_gif(nullptr)

{
    // Sprite is a class that manages the assets. It loads a bunch of things from a folder,and it 
    // verifies the extension to load the right asset. This way,the graphists can provide me 
    // PNG,GIF,or JPG,and the Sprite class will load it automatically.
    auto sprite = new Sprite(asset);
    sprite->setLoadPixmap(false);
    sprite->setFixedSize(size);
    sprite->tryLoad();

    if (sprite->format() == Sprite::Extension::GIF) {
        _gif = new QMovie(sprite->imagePath());
        _gif->setScaledSize(size);
        _gif->start();

        connect(_gif,&QMovie::frameChanged,[this] {
            setPixmap(_gif->currentPixmap());
            update();
        });
    }
    else {
        setPixmap(QPixmap(sprite->imagePath())
                      .scaled(size,Qt::KeepAspectRatio,Qt::SmoothTransformation));
    }
}

~PixmapItem() 
{
    if (_gif != nullptr && _gif->isValid()) {
        _gif->stop();
        _gif->deleteLater();
    }

}

我认为重新粉刷QGraphicsView的矩形不会造成任何问题,我是错的。

我尝试做的第一件事是遵循here发布的优化。它改善了性能,但结结声仍在发生。因此,我改变了处理 gif 的方式,从重新绘制QGraphicsPixmapItem到只设置QGraphicsProxyWidget widget 注意: SpriteQLabel 的子代):

// pixmapitem.hxx
class PixmapItem : public QGraphicsProxyWidget {
    Q_OBJECT
  public:
    explicit PixmapItem(const Sprite::Asset asset,QGraphicsItem *parent = nullptr);

    QPixmap pixmap();

  private:
    Sprite *_sprite;
};

// pixmapitem.cxx
PixmapItem::PixmapItem(const Sprite::Asset asset,QGraphicsItem *parent)
    : QGraphicsProxyWidget(parent),_sprite(nullptr)

{
    _sprite = new Sprite(asset);
    _sprite->setFixedSize(size);
    _sprite->tryLoad();

    // Without it,transparent assets were white on Android. It wasn't needed on PC.
    _sprite->setAttribute(Qt::WA_NoSystemBackground);

    setWidget(_sprite);
}

QPixmap PixmapItem::pixmap()
{
    if (_sprite->movie() != nullptr) {
        return _sprite->movie()->currentPixmap();
    }
    else {
        return _sprite->pixmap(Qt::ReturnByValueConstant());
    }
}

它仍然不能解决我的问题。有人建议我,在QGraphicsPixmapItem内加载gif的所有像素图后,性能可能会得到改善。这是我的实现:

// pixmapitem.hxx
class PixmapItem : public QObject,public QGraphicsPixmapItem {
    Q_OBJECT
  public:
    explicit PixmapItem(
        const Sprite::Asset asset,QGraphicsItem *parent = nullptr);

    ~PixmapItem();

    QPixmap pixmap() const;

  private:
    QList<QGraphicsPixmapItem *> _items;
    int _currentItem;
    int _fps;
    QTimer *_timer;
};

// pixmapitem.cxx

// ----------------------------------------------------------------------------
// Constructor.

PixmapItem::PixmapItem(const Sprite::Asset asset,_items(),_currentItem(0),_fps(30),_timer()

{
    auto sprite = new Sprite(asset);
    sprite->setLoadPixmap(false);
    sprite->tryLoad();

    if (sprite->format() == Sprite::Extension::GIF) {
        auto movie = new QMovie(sprite->imagePath());
        movie->setScaledSize(size);
        _timer = new QTimer;
        connect(_timer,&QTimer::timeout,[this] {
            if (++_currentItem >= _items.count())
                _currentItem = 0;
            setPixmap(pixmap());
        });

        for (int i = 0; i < movie->frameCount(); ++i) {
            movie->jumpToFrame(i);
            _items.push_back(new QGraphicsPixmapItem(movie->currentPixmap(),parent));
        }
        setPixmap(pixmap());
        _timer->start(1000.0 / _fps);

        movie->deleteLater();
    }
    else {
        _items.push_back(new QGraphicsPixmapItem(
            QPixmap(sprite->imagePath())
                .scaled(size,Qt::SmoothTransformation),parent));
        setPixmap(pixmap());
    }

    setCacheMode(QGraphicsItem::ItemCoordinateCache);
    sprite->deleteLater();
}

// ----------------------------------------------------------------------------
// Destructor.

PixmapItem::~PixmapItem()
{
    if (_timer) {
        if (_timer->isActive())
            _timer->stop();
        delete _timer;
    }
}

// ----------------------------------------------------------------------------
// Public method.

QPixmap PixmapItem::pixmap() const
{
    return _items.at(_currentItem)->pixmap();
}

您可能已经猜到了,我仍然遇到表演问题(如果没有的话,我不会在这里发布)。我现在不知道该怎么做才能优化我的游戏。任何帮助将不胜感激。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...