I'm moving from QGraphicsScene/QGraphicsView to QQuickItem for rendering my 
game objects. One of the things this involves is setting up a scene and the 
view onto that scene, as this was previously managed by QGraphicsScene and 
QGraphicsView.

My naive attempt was to do the following:

void SceneView::centerOn(const QPointF &pos)
{
    if (mScene) {
        mScene->setX(-(pos.x() - width() / 2));
        mScene->setY(-(pos.y() - height() / 2));
    }
}

This works, but it produces this odd effect where some game objects "jump 
around" between neighbouring pixels while the camera comes to a halt while 
following the player:

http://i.imgur.com/AP1yIoO.gif

The player's movement is fine. The crate also does not seem to exhibit this 
problem (though its Box2D debug drawing marker does).

This is what it looks like when the player moves without the camera following 
it:

http://i.imgur.com/mA4JTC7.gif

This is what I'd expect from the other game objects when the camera is moving; 
no movement whatsoever relative to the scene.

The old, correct movement looked like this:

http://i.imgur.com/7yMcVpS.gif

The old code:

void MapView::centerOverFollowedItem()
{
    QRectF geometry(mFollowing->pos(), mFollowing->boundingRect().size());
    centerOn(geometry.center());
}

I thought I'd take a look at how QGraphicsView does it:

void QGraphicsView::centerOn(const QPointF &pos)
{
    Q_D(QGraphicsView);
    qreal width = viewport()->width();
    qreal height = viewport()->height();
    QPointF viewPoint = d->matrix.map(pos);
    QPointF oldCenterPoint = pos;

    if (!d->leftIndent) {
        if (isRightToLeft()) {
            qint64 horizontal = 0;
            horizontal += horizontalScrollBar()->minimum();
            horizontal += horizontalScrollBar()->maximum();
            horizontal -= int(viewPoint.x() - width / 2.0);
            horizontalScrollBar()->setValue(horizontal);
        } else {
            horizontalScrollBar()->setValue(int(viewPoint.x() - width / 2.0));
        }
    }
    if (!d->topIndent)
        verticalScrollBar()->setValue(int(viewPoint.y() - height / 2.0));
    d->lastCenterPoint = oldCenterPoint;
}

http://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/graphicsview/qgraphicsview.cpp#n1904

It casts the x and y position of its view to integers, so I tried doing that 
too:

void SceneView::centerOn(const QPointF &pos)
{
    if (mScene) {
        mScene->setX(int(-(pos.x() - width() / 2)));
        mScene->setY(int(-(pos.y() - height() / 2)));
    }
}

This fixes the movement of objects that shouldn't move, but produces a subtle 
yet irritating effect where the movement of the camera looks "blocky":

http://i.imgur.com/Z3Wc66h.gif

It's mostly noticeable when the player is coming to a stop.

Why does this happen with a Qt Quick scene, but not QGraphicsView, when they 
are both using integer positioning in this case?

(All objects are Images in the new code, and I set smooth to false on them 
because my assets will be pixel art)
_______________________________________________
Interest mailing list
Interest@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest

Reply via email to