【问题标题】:QGraphicsItem collision jitter/trembleQGraphicsItem 碰撞抖动/颤抖
【发布时间】:2016-11-07 09:33:09
【问题描述】:

大家好,我需要你们的帮助,

我正在基于 QGraphics 框架在 Qt 中创建类似小部件的时间线。我的问题是在我的时间轴轨道中处理项目(继承自 QGraphicsRectItem)的冲突。

我使用 itemChange() 函数来跟踪碰撞。为了将项目保留在父 boundingRect 我使用下面的代码就像一个魅力

if (change == ItemPositionChange && scene())
   if (thisRect.intersects(parentRect)) {
        const QPointF offset(mapFromParent(thisRect.topLeft()));
        QPointF newPos(value.toPointF());

        if (snapToGrid) {
            newPos.setX(floor(qMin(parentRect.right() - offset.x() - thisRect.width(),
                                   qMax(newPos.x(), parentRect.left() / 2 - offset.x())) / (snapValue * pxPerSec(duration))) * snapValue * pxPerSec(duration));
        }
        else {             
            newPos.setX(qMin(parentRect.right() - offset.x() - thisRect.width(),
                             qMax(newPos.x(), parentRect.left() - offset.x())));
        }

        newPos.setY(parentItem()->boundingRect().height() * 0.1);
        return newPos;
    }
}

如果项目到达我的时间线轨道的左边界或右边界,这会立即停止项目,即使我将鼠标移到我的视图/场景之外。就像一堵看不见的墙。 现在,如果轨道中的一个项目与另一个项目发生冲突,我想要相同的行为。

const QRectF parentRect(parentItem()->sceneBoundingRect());
const QRectF thisRect(sceneBoundingRect());

    foreach (QGraphicsItem *qgitem, collidingItems()) {
        TimelineItem *item = qgraphicsitem_cast<TimelineItem *>(qgitem);
        QPointF newPos(value.toPointF());

        if (item) {
            const QRectF collideRect = item->sceneBoundingRect();
            const QPointF offset(mapFromParent(thisRect.topLeft()));

            if (thisRect.intersects(collideRect) && thisRect.x() < collideRect.x()) {
                newPos.setX(collideRect.left() - offset.x() - thisRect.width());
            }

            if (thisRect.intersects(collideRect) && thisRect.x() > collideRect.x()) {
                newPos.setX(collideRect.right() + offset.x());
            }

        }

        newPos.setY(parentItem()->boundingRect().height() * 0.1);
        return newPos;
    }

问题是,如果我通过鼠标将一个项目移动到另一个项目上,您会看到它们相交/重叠,然后我移动的项目会迅速恢复到最小不相交距离。如果移动的物品撞到另一个物品(没有颤抖的前后运动相交的东西),我如何设法立即停止它。就像项目保存在父母boundingRect(第一个代码块)中的方式一样,隐形墙的行为?

【问题讨论】:

    标签: c++ qt collision qgraphicsitem


    【解决方案1】:

    我认为这里的问题在于“thisRect”。如果您从 ItemPositionChange 调用它,则 sceneBoundingRect 将返回项目在其先前位置的边界矩形,而不是新位置。发生的情况是,即使发生碰撞,当前位置也会成功,但下一个位置会失败,因为您总是检查以前的结果,然后它会回弹以避免碰撞。

    获取本地项目的场景矩形后,您需要将其转换为项目的新未来位置:

    QPointF new_pos (value.toPointF ());
    QRectF thisRect (sceneBoundingRect());
    thisRect.translate (new_pos - pos());
    

    我已将“new_pos”的创建移到循环之外,以便它可用于矩形平移。它也更快。

    【讨论】:

    • 感谢您的回复,好点子,但并没有解决问题。
    • 这些项目是否有父项?如果是这样,那么你有一个混合坐标系,即“newPos”和“offset”在父坐标中,但“thisRect”和“collideRect”在场景坐标中。如果它们没有父级,那么这都是场景坐标,在这种情况下,我认为这看起来是正确的。如果涉及到父项,请使用 mapToScene 代替 mapToParent,然后还将 newPos 映射到场景坐标以进行所有比较和调整,然后在返回之前返回父坐标。
    • 这些项目是轨道项目的父级,但它与场景具有相同的宽度,并且它的矩形也设置为 (0,0)。所以x,y原点应该是一样的。
    • 删除了“偏移”,但行为仍然相同。编辑:在第一篇文章中添加了一个 gif。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-20
    • 1970-01-01
    • 2020-11-11
    • 1970-01-01
    相关资源
    最近更新 更多