Results 1 to 5 of 5

Thread: Need Help Regarding Qt GraphicsItem Collision

  1. #1
    Join Date
    Sep 2012
    Posts
    2
    Qt products
    Qt4

    Angry Need Help Regarding Qt GraphicsItem Collision

    Hi. So I am a complete beginner with Qt. I am tasked to make a Plant vs. Zombie esque game from my professor and I am at complete loss about the collision detection.

    I have been doing Google searches everywhere regarding the use of Qt Timeline, GraphicsItem, GraphicsScene for collision handling and I gave up.

    A short description about my game: There are three sprites on the playing field: Towers, Cannonballs and Mobs. Towers are placed by player to guard the left side of the screen and mobs appear from the right side of the screen. Towers constantly fire cannonballs every few seconds.

    Qt Code:
    1. cannonball::cannonball()
    2. {
    3. QTimeLine * timer = new QTimeLine(4000);
    4.  
    5. animation->setItem(this);
    6. animation->setTimeLine(timer);
    7.  
    8. timer->setLoopCount(0);
    9.  
    10. for (int i = this->pos().x(); i < 640; ++i)
    11. {
    12. animation->setPosAt(i / 640.0, QPointF(i, this->pos().y() ));
    13. if (hits_enemy())
    14. timer->setCurrentTime(0);
    15. }
    16.  
    17. timer->start();
    18. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. bool cannonball::hits_enemy()
    2. {
    3. for (int i=0; i<this->collidingItems().count(); i++)
    4. if (qgraphicsitem_cast<mobs*>(this->collidingItems()[i]) ) return true;
    5.  
    6. return false;
    7. }
    To copy to clipboard, switch view to plain text mode 

    Basically, those are some codes from the cannonball class.

    I would like the cannonball upon collision to a mob sprite to disappear, damage the mob and fire again once the cooldown cleared.

    I am pretty desperate right now as I have been looking for similar solutions for over 6 hours with no solid result. Please help!

  2. #2
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Need Help Regarding Qt GraphicsItem Collision

    You probably won't want to do this:

    Qt Code:
    1. bool cannonball::hits_enemy()
    2. {
    3. for (int i=0; i<this->collidingItems().count(); i++)
    4. if (qgraphicsitem_cast<mobs*>(this->collidingItems()[i]) ) return true;
    5.  
    6. return false;
    7. }
    To copy to clipboard, switch view to plain text mode 

    because you'll be retrieving the "collidingItems" collection *twice* for every pass through the loop. Retrieve it *once* before the loop starts and assign it to some temporary variable, then use that variable to get the count, etc.

    What do you want to happen when the cannonball hit detection returns true? The cannonball goes away? Then you simply need to remove the cannonball instance from the scene. QGraphicsScene::removeItem()
    Qt Code:
    1. for (int i = this->pos().x(); i < 640; ++i)
    2. {
    3. animation->setPosAt(i / 640.0, QPointF(i, this->pos().y() ));
    4. if (hits_enemy())
    5. timer->setCurrentTime(0);
    6. }
    To copy to clipboard, switch view to plain text mode 

    And why is this code in the cannonball constructor? The instance isn't even in the scene at this point, so how can it collide with anything?

    You need to set up a timer in your main window (or in your QGraphicsView, if you have derived a custom one) that fires a couple of times per second so the animation looks smooth. In the slot that handles each time step timeout, you retrieve all the cannonball instances from the scene, and *then* do the hit detection on them.

    Qt Code:
    1. // pseudocode:
    2.  
    3. for each cannonball
    4. {
    5. QList<QGraphicsItem *> colliders = scene.collidingItems( cannonball );
    6. if ( colliders is not empty && colliders contains a mob )
    7. add cannonball to list of items to be deleted
    8. }
    9.  
    10. for each cannonball on the deletion list
    11. {
    12. scene.removeItem( cannonball )
    13. delete cannonball;
    14. }
    To copy to clipboard, switch view to plain text mode 

    You might also consider putting a timer inside each cannonball; at each timeout, it updates the cannonball's position by moving it further along its trajectory. If you derive your cannonballs from QGraphicsObject, then you can handle the x/y/zChanged() signals from each cannonball and do the collision detection there instead of in a slot driven by a master clock. Use QObject::sender() to determine which cannonball sent the signal, or use QSignalMapper to associate the cannonball instance.

  3. #3
    Join Date
    Sep 2012
    Posts
    2
    Qt products
    Qt4

    Smile Re: Need Help Regarding Qt GraphicsItem Collision

    Quote Originally Posted by d_stranz View Post
    You probably won't want to do this because you'll be retrieving the "collidingItems" collection *twice* for every pass through the loop. Retrieve it *once* before the loop starts and assign it to some temporary variable, then use that variable to get the count, etc.

    What do you want to happen when the cannonball hit detection returns true? The cannonball goes away? Then you simply need to remove the cannonball instance from the scene. QGraphicsScene::removeItem()
    Qt Code:
    1. for (int i = this->pos().x(); i < 640; ++i)
    2. {
    3. animation->setPosAt(i / 640.0, QPointF(i, this->pos().y() ));
    4. if (hits_enemy())
    5. timer->setCurrentTime(0);
    6. }
    To copy to clipboard, switch view to plain text mode 

    And why is this code in the cannonball constructor? The instance isn't even in the scene at this point, so how can it collide with anything?

    You need to set up a timer in your main window (or in your QGraphicsView, if you have derived a custom one) that fires a couple of times per second so the animation looks smooth. In the slot that handles each time step timeout, you retrieve all the cannonball instances from the scene, and *then* do the hit detection on them.

    Qt Code:
    1. // pseudocode:
    2.  
    3. for each cannonball
    4. {
    5. QList<QGraphicsItem *> colliders = scene.collidingItems( cannonball );
    6. if ( colliders is not empty && colliders contains a mob )
    7. add cannonball to list of items to be deleted
    8. }
    9.  
    10. for each cannonball on the deletion list
    11. {
    12. scene.removeItem( cannonball )
    13. delete cannonball;
    14. }
    To copy to clipboard, switch view to plain text mode 

    You might also consider putting a timer inside each cannonball; at each timeout, it updates the cannonball's position by moving it further along its trajectory. If you derive your cannonballs from QGraphicsObject, then you can handle the x/y/zChanged() signals from each cannonball and do the collision detection there instead of in a slot driven by a master clock. Use QObject::sender() to determine which cannonball sent the signal, or use QSignalMapper to associate the cannonball instance.
    Hi, thanks for the reply.

    I apologize if my code seems to be rather crude. The professor was like "You guys make this. Ask Google how to do it, use any C++ Library. I expect results in 2 days", Hence I am doing self-learning with limited time.

    The original intent was if the cannonball detection returns true, The cannonball will be simply loop itself because I set timer->setLoopCount(0); for the TimeLine (unlimited loop). That is done via if (hits_enemy()) timer->setCurrentTime(0); code, although I seem to misunderstood the code runtime (Currently, I ended up putting that setCurrentTime and the loop detection code inside painter function because it seem that only that part of the code is being run over and over again.)

    I never knew that you should set the timer in the main widget instead on individual classes. I'll take note on that. Also, I derive my cannonballs from QGraphicsItem instead of QGraphicsObject so I haven't touched on that.

    I have another question, when I create my QGraphicsScene outside the main widget / as a global variable, (so that it can be accessed by these sprites for remote deletion / etc.) the program crashes. Is there any workaround on it?

    Thanks again.

    EDIT: Here are the codes so far. Currently I am having trouble about deleting the enemy whenever they reach 0 HP upon collision with the cannons because I honestly don't have an idea about how to notify the main widget that a collision has happened and delete the object from the scenes there.
    Attached Files Attached Files
    Last edited by RE; 27th September 2012 at 20:39.

  4. #4
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Need Help Regarding Qt GraphicsItem Collision

    I honestly don't have an idea about how to notify the main widget that a collision has happened and delete the object from the scenes there.
    If you derive your cannonball object from QGraphicsObject instead of QGraphicsItem, then it can have slots and signals. So, if you do your collision detection inside the cannonball code, then have it emit a signal "uhOhIAmAGoner( cannonball * unlucky )" that can be handled by a slot in the main window, view, or scene. Since the signal passes itself (this), you don't have to resort to tricks to find out which cannonball hit the mob.

    Qt Code:
    1. class cannonball : public QGraphicsObject
    2. {
    3. Q_OBJECT;
    4.  
    5. // ...
    6.  
    7. signals:
    8. void uhOhIAmAGoner( cannonball * unlucky );
    9.  
    10. protected slots:
    11. void hitEnemy();
    12.  
    13. protected:
    14. QTimer timer;
    15. };
    16.  
    17. cannonball::cannonball( QGraphicsItem * parent ) :
    18. : QGraphicsObject( parent )
    19. , timer( this )
    20. {
    21. timer.setInterval( 100 );
    22.  
    23. connect( &timer, SIGNAL( timeout() ), this, SLOT( hitEnemy() ) );
    24. timer.start();
    25. }
    26.  
    27. void cannonball::hitEnemy()
    28. {
    29. if ( collidedWithAMob() ) // You can figure this part out
    30. {
    31. timer.stop();
    32. emit uhOhIAmAGoner( this );
    33. }
    34. else
    35. updatePosition();
    36. }
    37.  
    38. class MainWindow: public QMainWindow
    39. {
    40. // ...
    41.  
    42. public slots:
    43. void killThatCannonball( cannonball * cball );
    44.  
    45. protected:
    46. void addACannonball();
    47.  
    48. private:
    49. QGraphicsScene mobScene;
    50. };
    51.  
    52.  
    53. void MainWindow::addACannonball()
    54. {
    55. cannonball * cBall = new cannonball();
    56. // establish initial trajectory, etc.
    57.  
    58. mobScene.addItem ( cBall );
    59.  
    60. connect( cBall, SIGNAL( uhOhIAmAGoner( cannonball * ) ), this, SLOT( killThatCannonball( cannonball * ) ) );
    61. }
    62.  
    63. void MainWindow::killThatCannonball( cannonball * cBall )
    64. {
    65. mobScene.removeItem ( cBall );
    66. delete cBall;
    67. }
    To copy to clipboard, switch view to plain text mode 

    Of course, none of this code has been compiled and certainly not tested. That's why your professor gave it to you as a homework project...

  5. #5
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Need Help Regarding Qt GraphicsItem Collision

    Collisions should be detected from within the scene. Then notifying anyone you want is easy since the scene is derived from QObject. Depending on what your architecture looks like, you might want to do this from within QGraphisScene::advance().
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Similar Threads

  1. Collision between QGraphicsItem -
    By been_1990 in forum General Discussion
    Replies: 6
    Last Post: 19th November 2010, 12:32
  2. collision detection...
    By Muffin in forum Newbie
    Replies: 1
    Last Post: 8th January 2010, 10:28
  3. Collision detect in QGraphicsScene
    By sophister in forum Qt Programming
    Replies: 6
    Last Post: 5th December 2009, 01:38
  4. turn off collision detection?
    By Deacon in forum Qt Programming
    Replies: 14
    Last Post: 30th December 2008, 17:37
  5. Collision handling 101
    By Morea in forum Qt Programming
    Replies: 9
    Last Post: 25th November 2006, 20:17

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.