How can I detect collision among QPixmaps and QGraphicsItems objects



  • I have QGraphicsEllipse items as bullets in a scene. Targets are QPixmap images and I want just the bullets and images to interact, NOT target on target collision. Bullets are created in my scene class and QPixmaps are created in my dialog class.

    This deletes my bullets that leave outside of my sceneRect. I tried adding a QList for the QPixmaps created similar to the QList QGraphicsItem * but don't think the compiler liked that. Is there a way to gather all pixmaps in scene and only have them detect bullets. Also tried collidesWithItem with no luck. Any suggestions would be appreciated.

    @void Scene::advance()
    {
    QList <QGraphicsItem *> itemsToRemove;
    foreach( QGraphicsItem * item, this->items())
    {

            if( !this->sceneRect().intersects(item->boundingRect()))
            {
                // The item is no longer in the scene rect, get ready to delete it
                itemsToRemove.append(item);
            }
        }
    
        foreach( QGraphicsItem * item, itemsToRemove )
        {
            this->removeItem(item);
            delete(item);
        }
        QGraphicsScene::advance();
    

    }@



  • It should be QGraphicsPixmapItems (or similar), not QPixmap.
    Collision detection can only work between subclasses of QGraphicsItem.



  • If I change to a QGraphicsPixmapItem can I make another list and collide the two. i.e. collideWithItem?



  • Yes, it should work that way.



  • I understand what you're saying about collision but the issues is I have the images stored in an array.

    @ main_targets[0] = QPixmap(":images/darkbluelogo.jpg");
    main_targets[1] = QPixmap(":images/graylogo.jpg");
    main_targets[2] = QPixmap(":images/lightbluelogo.jpg");
    main_targets[3] = QPixmap(":images/lime.jpg");
    main_targets[4] = QPixmap(":images/pink.jpg");
    main_targets[5] = QPixmap(":images/purple.jpg");
    main_targets[6] = QPixmap(":images/redlogo.jpg");
    main_targets[7] = QPixmap(":images/yellow.jpg");
    main_targets[8] = QPixmap(":images/brown.jpg");@

    I ran into alot of errors trying to store this array in a QGraphicsPixmapItem



  • @
    QVector<QGraphicsPixmapItem*> targetItems;
    foreach(QPixmap pix, main_targets) {
    QGraphicsPixmapItem* item = QGraphicsPixmapItem(pix);
    targetItems.append(item);
    }
    @

    Hope it help.



  • Thanks it helps but implementation throws @In instantiation of 'class QForeachContainer<QPixmap [9]>':@
    The main_target array, QPixmap and targetitems array, QGraphicsPixmapItem seem to not play well together.



  • How did you define main_targets?
    Is it
    @
    QVector<QPixmap> main_targets;
    or
    QPixmap main_targets[9];
    @

    Qt specific keyword foreach works only with container classes like first definition. If you have second definition then you should use standard C++ for or while loop.


  • Lifetime Qt Champion

    Hi,

    foreach must be used with a containers. A c array is not considered a container.

    In your case you can use a classic for loop or change your array to a QList of QPixmap

    Hope it helps



  • Changing to containers I get the index is out of range error. Can I not assign each QPixmap an array value?



  • If you use containers then you should use append() method to add pixmaps to your container.



  • I thought the @QVector<QGraphicsPixmapItem*> targetItems;
    foreach(QPixmap pix, main_targets) {
    QGraphicsPixmapItem* item = QGraphicsPixmapItem(pix);
    targetItems.append(item);
    }@ takes each instance of the main_targets array, and creates QGraphicsPixmapItems of them.



  • Could you show the code where you are getting "index is out of range" error.



  • I pass the pmap to the MainTarget class by pointer, which was previously by reference. There isn't a specific line that the compiler is showing. It crashes on execution. I replaced main_targets[index] with targetItems since that should hold the QGraphicsPixmapItem items.

    @void Dialog::setPixmaps()
    {
    //Targets are delivered every 1sec
    Five_timer->start(1000);

    QList<QGraphicsPixmapItem*> targetItems;
    foreach(QPixmap pix, main_targets) {
    QGraphicsPixmapItem* p_item = new QGraphicsPixmapItem(pix);
    targetItems.append(p_item);
    }
    
    int StartY = 0;
    
    //Random starting Y point between -140 and -389
    StartY = (qrand() % (-400 + 150) -140);
    
    index = (qrand() % 9);
    {
        if(index % 2 == 0)
        {
            //When even is selected start at far right
            pmap = new MainTargets(targetItems[index], 0);
            pmap->setPos(345,StartY);
        }
    
        else
        {
            //When odd is selected start at far left
            pmap = new MainTargets(targetItems[index], 1);
            pmap->setPos(-325,StartY);
    
        }
    }
    
    scene->addItem(pmap);
    

    }@



  • Does it always crash on the same place?
    Try to step through the function using a debugger.

    What is the type of main_targets in line #9?



  • QList<QPixmap> main_targets is the type.

    Seems to fail at the QList::operator[].

    That is why I think the main_target array seems to be the issue.



  • How do you fill main_target?



  • Guess that is where the problem is I thought the @ QList<QGraphicsPixmapItem*> targetItems;
    foreach(QPixmap pix, main_targets) {
    QGraphicsPixmapItem* p_item = new QGraphicsPixmapItem(pix);
    targetItems.append(p_item);@ fills the main_target list. If not what is the purpose of this line?



  • In this code you take the pixmaps from main_target and create qlist of qgraphicsitems.
    So, the main_target must be populated by the qpixmaps before this code.



  • @ main_targets[0] = QPixmap(":images/darkbluelogo.jpg");
    main_targets[1] = QPixmap(":images/graylogo.jpg");
    main_targets[2] = QPixmap(":images/lightbluelogo.jpg");
    main_targets[3] = QPixmap(":images/lime.jpg");
    main_targets[4] = QPixmap(":images/pink.jpg");
    main_targets[5] = QPixmap(":images/purple.jpg");
    main_targets[6] = QPixmap(":images/redlogo.jpg");
    main_targets[7] = QPixmap(":images/yellow.jpg");
    main_targets[8] = QPixmap(":images/brown.jpg");@

    The main_targets are created and stored in the constructor initially before anything is done. So the qlist should have 9 qpixmaps.



  • If I'm not mistaken you need to use .append() method to add elements to the QList. QList::opeartor[] does not work for adding new elements.

    EDIT: Yep, you have to use append() or operator+=() to extend a list "operator[]":http://qt-project.org/doc/qt-5/qlist.html#operator-5b-5d requires an index to be valid (0 <= i < qlist.size())



  • Thank you finally have it switched over to QGraphicsPixmapItems. Now the initial problem and see if I can get the collision working.



  • Ok the original problem of colliding the two objects. My thinking at the beginning of this post was to have something along the lines of:

    @if(pellets->collidesWithItem(targets){
    remove(pellets)
    remove(targets)

    }@



  • I wouldn't delete the items right away, but only hide them, and delete them later on. But otherwise, it might be something like this.

    Have you taken a look at the Colliding Mice example?



  • Yeah I've looked at that example a lot. Doesn't seem to be in the realm of what I'm trying to accomplish.



  • So you have some QGraphicsItem subclass and come QGraphicsPixmap. You check whether they collide. That part you should be able to take from the example.

    If they collide, you hide those items and add them to a list of items "to be deleted" (or "to be re-used", if you prefer).

    You either clean up the list from time to time (using e.g. a timer), or you re-use the items in the list if you need to add a new item (which would be a performance optimization, since creating GraphicsItems isn't free).

    Where specifically do you have problems?



  • The collision is comparing every item on the screen. It only removes one item not both that collide. It's not item specific.



  • If you only want to compare two items, you can use their shape() and QPainterPath::intersects



  • Is there any way to remove and delete the pellet target from within the QGraphicsRectItem. I'm just hiding the two when they collide, but that doesn't remove it and since the class inherits from the QGraphicsItem base class there isn't a removeitem() function.

    @class GraphicsCircle : public QGraphicsRectItem
    // class for the fire bullets
    {

    public:
    GraphicsCircle(qreal dirx, qreal diry)
    : m_Speed(5)
    , m_DirX(dirx)
    , m_DirY(diry)
    {
    setRect(-3.0,-3.0,8.0,8.0);
    setPos(-140, 235);
    QRadialGradient rGrad( 0.0, 0.0, 20.0, 0.0, 0.0);
    rGrad.setColorAt(0.0, QColor(255,255,255));
    rGrad.setColorAt(0.7, QColor(255,255,225));
    rGrad.setColorAt(1.0, QColor(255,0,0,0));
    setBrush(QBrush(rGrad) );
    setPen(QPen(Qt::NoPen));

        w = 7;
        h = 7;
    }
    
    QRectF boundingRect() const
    {
        qreal shift = 1;
            return QRectF(-w/2 -shift, - h/2
                          - shift, w + shift, h + shift);
    }
    
    QPainterPath shape() const
    {
        QPainterPath path;
        path.addRect(boundingRect());
        return path;
    }
    
    virtual ~GraphicsCircle() {}
    
    void advance(int phase)
    {
        if(phase == 0) return;
        setPos(x()+m_Speed*m_DirX, y()+m_Speed*m_DirY);
    
    
        foreach( QGraphicsItem * item, this->collidingItems())
        {
             item->hide();
             this->hide();
    
        }
    
    }@


  • How about this:

    @
    QList<QGraphicsItem*> collisionList = this->collidingItems();
    qDeleteAll(collisionList);

    this->hide();
    // Now it gets tricky: delete this isn't a very good idea within the context of this.
    // One way to solve it: Derive the class from QObject AND QGraphicsRectItem, and use the deleteLater() call
    @


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.