QGraphicsItem中的碰撞检测描述

QGraphicsItem中的碰撞检测描述

2011-12-08 15:04:28 ykm0722 阅读数 10607更多

分类专栏: QT

 

QGraphicsItem中的碰撞检测描述

    QGraphicsItem是图元基类。QGraphics View框架提供了几种标准的图元,如矩形(QGraphicsRectItem、椭圆(QGraphicsEllipseItem)和文本图元(QGraphicsTextItem)等。用户可以继承QgraphicItem实现符合自己需要的图元。

QGraphicsItem具有以下功能:

  • 处理鼠标按下、移动、释放、双击、悬停、滚轮和右键菜单事件

  • 处理键盘输入事件

  • 处理拖放事件

  • 分组

  • 碰撞检测

  图元有自己的坐标系统,也提供场景和图元、图元与图元之间的坐标转换函数。图元可以包含子图元。

 

    要创建自己的图元,必须首先创建QGrahicsItem的一个子类,然后开始实现他的2个纯虚函数。一个是boundingRect(),用于返回图元绘制所需要的估测区域。另一个是paint,它实现实际的绘图操纵。举例:

QGraphicsScene的碰撞检测

2017-05-22 12:19:54 allenxguo 阅读数 3021更多

分类专栏: QT

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/gx864102252/article/details/72625300

实现效果如下 
这里写图片描述 
图1 移动的Item碰撞显示 
这里写图片描述 
图2 碰撞的Item都显示

使用Scene的碰撞检测函数

QList< QGraphicsItem *> collidingItems(const QGraphicsItem *item, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const

文档解释

Returns a list of all items that collide with item. Collisions are determined by calling QGraphicsItem::collidesWithItem(); the collision detection is determined by mode. By default, all items whose shape intersects item or is contained inside item's shape are returned.
The items are returned in descending stacking order (i.e., the first item in the list is the uppermost item, and the last item is the lowermost item).

可以查看一下collidingItems的源码

QList<QGraphicsItem *> QGraphicsScene::collidingItems(const QGraphicsItem *item, Qt::ItemSelectionMode mode) const                                  
{
    Q_D(const QGraphicsScene);//宏通过d_func()获取d指针
    if (!item) {
        qWarning("QGraphicsScene::collidingItems: cannot find collisions for null item");
        return QList<QGraphicsItem *>();
    }

    // Does not support ItemIgnoresTransformations.
    QList<collidingItems *> tmp;
    //获取Scene全部范围的Item
    const auto itemsInVicinity = d->index->estimateItems(item->sceneBoundingRect(), Qt::DescendingOrder);
    for (QGraphicsItem *itemInVicinity : itemsInVicinity) {
    //使用QGraphicsItem的碰撞检测函数测试返回值
        if (item != itemInVicinity && item->collidesWithItem(itemInVicinity, mode))
            tmp << itemInVicinity;
    }
    return tmp;
}

首先实现移动的Item碰撞显示 
主要代码如下:

//重写mouseMoveEvent函数,当有碰撞Item时让其变色
void GraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *ev)
{
    scene()->collidingItems(this).isEmpty() ?
                setBrush(QBrush(QColor(0,191,255))) :
                setBrush(QBrush(QColor(255,215,0)));
    QGraphicsRectItem::mouseMoveEvent(ev);
}

实现碰撞的Item都显示

//重写paint
//由于paint是每次界面重绘都需要调用的函数,所以当2个Item碰撞时,两者都触
//发相同的函数(代码)所以两者都变色
void GraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    scene()->collidingItems(this).isEmpty() ?
                setBrush(QBrush(QColor(0,191,255))) :
               setBrush(QBrush(QColor(255,215,0)));

    QGraphicsRectItem::paint(painter, option, widget);
}

    boundingRect函数有几个目的。QGraphicsScene的图元索引就是建立在boundingRect的基础上。QGraphicsView也使用这个函数来从视图上将不可见的图元移去,以及在绘制重叠的图元时决定需要重新组织的区域。另外,QGraphicsItem的碰撞检测机制(collision detection)使用boundingRest来提高高效的处理。更好的碰撞检测算法是基于shape函数的调用,shape函数将图元的形状的准确外观以QPainterPath返回。

    QGraphicsScene认为所有图元的boundingRect函数与shape函数都是不发生改变的,除非用户进行通知。如果你想改变一个图元的范围,必需先调用prepareGeometryChange以允许QGraphicsScene进行更新。

碰撞检测可以通过以下两种方式实现:

  • 重新实现shape函数返回一个准确的图元外观形状,依赖collidesWithItem函数进行缺省的碰撞检测,如果形状非常的复杂,该检测将是非常耗时的。
  • 重新实现collidesWithItem函数,为自己的定制图元编写碰撞检测算法。

 

对于多点成线的图元可以使用下面的方式返回shape。

QPainterPath path;
//直线的绘制路径
if (m_pointList.count()>0)
{

int iSize;
iSize = m_pointList.size();
path.moveTo (m_pointList[0]);

for(int i=1;i<iSize/2;i++)
{
    path.lineTo (m_pointList[i*2]);
}
for(int i=iSize/2;i>=1;i--)
{
    path.lineTo (m_pointList[i*2-1]);
}
path.closeSubpath();

}
return path;

  • 0
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
QGraphicsItem碰撞检测失效,可能是因为你没有正确地实现碰撞检测函数。 在自定义 QGraphicsItem ,你需要实现 `shape()` 函数来指定该 item 的形状,这个形状用于在碰撞检测计算碰撞。如果你没有正确地实现 `shape()` 函数,那么在碰撞检测就会出现问题。 具体来说,你需要在 `shape()` 函数返回一个 `QPainterPath` 对象,该对象描述了该 item 的形状。这个形状应该是一个不包含任何透明部分的完整形状。 例如,如果你的自定义 QGraphicsItem 是一个圆形,那么可以这样实现 `shape()` 函数: ```cpp QPainterPath MyItem::shape() const { QPainterPath path; path.addEllipse(boundingRect()); // 添加一个椭圆形状 return path; } ``` 如果你的自定义 QGraphicsItem 是一个矩形,那么可以这样实现 `shape()` 函数: ```cpp QPainterPath MyItem::shape() const { QPainterPath path; path.addRect(boundingRect()); // 添加一个矩形形状 return path; } ``` 如果你的自定义 QGraphicsItem 是一个复杂形状,那么你需要使用更多的 QPainterPath 函数来构建这个形状。 实现 `shape()` 函数后,你可以使用 `collidesWithItem()` 函数来检测两个 item 是否发生了碰撞。例如: ```cpp bool MyItem::collidesWithItem(const QGraphicsItem *other, Qt::ItemSelectionMode mode) const { return shape().intersects(other->shape()); } ``` 这个函数会在两个 item 的形状相交时返回 true,否则返回 false。 如果你仍然无法解决问题,请提供更多的代码和详细的描述,以便更好地帮助你解决问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值