Qt - 用于碰撞检测的圆圈

Qt - circles for collision detection

我一直在 Qt 中用圆圈进行物理模拟。到目前为止,我发现定义圆的最简单方法是制作一个 QRect 对象,然后用该矩形绘制椭圆作为 "blueprint"。现在我遇到了一个问题,它画了一个圆圈,但命中检测的命中框仍然是一个正方形,这看起来很尴尬。到目前为止,我还没有找到解决方案,希望能在这里找到一些帮助。

QRectF Ball::boundingRect() const
{    
  return QRect(0,0,20,20);
}
void Ball::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QRectF rec = boundingRect();
    QBrush Brush(Qt::gray);

    //basic Collision Detection

    if(scene()->collidingItems(this).isEmpty())
    {
        //no collision
        Brush.setColor(Qt::green);
    }
    else
    {
        //collision!!!!!
        Brush.setColor(Qt::red);

        //Set position
        DoCollision();
    }

    //painter->fillEllipse(rec,Brush);
    painter->drawEllipse(rec);
}
QPainterPath QGraphicsItem::shape() const

Returns the shape of this item as a QPainterPath in local coordinates. The shape is used for many things, including collision detection, hit tests, and for the QGraphicsScene::items() functions.

The default implementation calls boundingRect() to return a simple rectangular shape, but subclasses can reimplement this function to return a more accurate shape for non-rectangular items.

要进行精细碰撞检测,您必须使用:

bool QGraphicsItem::collidesWithItem(const QGraphicsItem * other, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const

您也可以重新实现,因为检查圆之间的碰撞比检查画家路径的交点更快。

我自己没用过,但你使用的函数似乎只会给你 "coarse detection" 所以你必须手动检查是否有任何这些实际上与细粒度方法相交。这样可以节省性能,您可以使用粗略检查来隔离潜在的碰撞候选对象,然后使用较慢的方法仅检查那些项目。在您的情况下,这并不方便,因为圆形碰撞测试即使不比边界框测试快,也一样快,但这就是 Qt 的设计方式。理想情况下,您应该能够将自己的碰撞检测功能传递给 collidingItems().

最后但并非最不重要的一点是,一旦获得 collidingItems 列表,您就可以轻松地当场检查圆圈碰撞,而无需使用 shape()collidesWithItem()...实际上为您节省了一些 CPU 时间,因为不必调用额外的虚函数,加上重新实现这些虚函数的时间...

所以你可以使用这样的东西:

inline bool circCollide(QGraphicsItem * item, QList<QGraphicsItem *> items) {
    QPointF c1 = item->boundingRect().center();
    foreach (QGraphicsItem * t, items) {
        qreal distance = QLineF(c1, t->boundingRect().center()).length();
        qreal radii = (item->boundingRect().width() + t->boundingRect().width()) / 2;
        if ( distance <= radii ) return true; 
    }
    return false;
}

...当场做:

if (circCollide(this, collidingItems())) ... we have a collision

阅读文档!只需挖掘 base class 及其祖先的文档。 参见 QGraphicsItem::contains and shape

还有一件事。有一个 class QGraphicsEllipseItem,所以你需要的大部分功能应该都在那里。