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,所以你需要的大部分功能应该都在那里。
我一直在 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,所以你需要的大部分功能应该都在那里。