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.
For fine collision detection you have to use:
bool QGraphicsItem::collidesWithItem(const QGraphicsItem * other, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const
which you can also reimplement, because checking for collision between circles is faster than checking painterpaths for intersection.
I haven't used that myself, but it seems like the function you use will only give you "coarse detection" so then you must manually check if any of those actually intersect with the fine grained method. This saves on performance, you use the rough check to isolate potential collision candidates, and then check only those items using the slower method. In your case it is not a convenience, because a circle collision test would be as fast, if not faster than the bounding box test, but that's how Qt is designed. Ideally, you should be able to pass your own collision detection function to collidingItems()
.
Also last but not least, once you get the collidingItems
list you can easily check for circle collisions on the spot, without using shape()
and collidesWithItem()
... It will actually save you some CPU time from not having to call extra virtual functions, plus the time to reimplement those...
So you can use something like this:
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;
}
... and do it on the spot:
if (circCollide(this, collidingItems())) ... we have a collision