【问题标题】:Qt - circles for collision detectionQt - 用于碰撞检测的圆圈
【发布时间】:2015-08-11 13:17:55
【问题描述】:

我一直在用 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);
}

【问题讨论】:

    标签: c++ qt collision-detection qpainter


    【解决方案1】:
    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
    

    【讨论】:

    • 好吧,我将代码更改如下,但它似乎仍然不应该发生碰撞。还有输入吗? void Ball::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { // QRectF circ = boundingRect(); QBrush 画笔(Qt::gray); QPainterPath path0; path0.addPath(shape()); //基本碰撞检测 if(scene()->collidingItems(this).isEmpty())painter->drawPath(shape());还有比这样更好的方式来回复你吗?
    • 由于字符限制,我这样做无法添加它。 QPainterPath Ball::shape() { QPainterPath 路径; path.addEllipse(boundingRect());返回路径; } 无效球::paint
    【解决方案2】:

    阅读文档!只需挖掘基类及其祖先的文档。 见QGraphicsItem::containsshape

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-08
      • 1970-01-01
      • 2017-10-02
      • 1970-01-01
      • 2010-10-16
      • 1970-01-01
      • 1970-01-01
      • 2016-08-08
      相关资源
      最近更新 更多