我一直在用Qt中的圆圈进行物理模拟。到目前为止,我发现定义圆的最简单方法是创建一个QRect
对象,然后用该矩形绘制椭圆作为“蓝图”。现在我遇到的问题是它画了一个圆圈,但是命中检测的命中框仍然是一个正方形,看起来很尴尬。到目前为止,我还没能找到解决方案,希望能在这里找到一些帮助。
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);
}
答案 0 :(得分:6)
QPainterPath QGraphicsItem::shape() const
以本地坐标中的QPainterPath形式返回此项的形状。 形状用于许多事情,包括碰撞检测,命中 测试,以及QGraphicsScene :: items()函数。
默认实现调用boundingRect()返回一个简单的 矩形形状,但子类可以重新实现此功能 为非矩形项目返回更准确的形状。
对于精细碰撞检测,您必须使用:
bool QGraphicsItem::collidesWithItem(const QGraphicsItem * other, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const
你也可以重新实现,因为检查圆之间的碰撞比检查交叉的画家路径要快。
我自己还没有使用它,但看起来你使用的功能只会给你"粗略检测"所以你必须手动检查是否有任何实际上与细粒度方法相交的。这样可以节省性能,使用粗略检查来隔离潜在的碰撞候选,然后使用较慢的方法仅检查这些项目。在你的情况下,这不是一个方便,因为圆形碰撞测试会比边界框测试快,如果不快,但这就是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
答案 1 :(得分:2)
阅读文档!只需挖掘基类及其祖先的文档。 请参阅QGraphicsItem::contains和shape
还有一件事。有一个班级QGraphicsEllipseItem,所以你需要的大部分功能都应该包含在那里。