Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Collision Detection Run-time bug (Following along with the SFML BOOK)  (Read 1621 times)

0 Members and 1 Guest are viewing this topic.

Zereo

  • Newbie
  • *
  • Posts: 2
    • View Profile
Hey everyone first time poster here, but love working with SFML. Anyways I have been reading the SFML book and found it quite good and it has it been very informative though I am stuck on the collision detection aspect in the book.

Which brings me to my problem. I have been trying to debug a collision detection error for a while now and just can't seem to find out what it is. I have a feeling it is something little I am missing.

But was hoping maybe someone more experienced with SFML then me can help me out. I'll post what I have been able to find out and the code related to the bug (If you need more just let me know and I can provide whatever is needed).

The bug seems to be that the game isn't detecting when the collision of 2 bounding boxes collide. The collision function never evalutes to true even when it should.


Collision Helper Function - From the SFML book used to help find if there is a collision between scene nodes.
bool collision(const SceneNode& lhs, const SceneNode& rhs)
{
        return lhs.getBoundingRect().intersects(rhs.getBoundingRect());
}

checkNodeCollision - Basically it does a few optimizations as far as I can tell and also tests for the collision with the helper function.
void SceneNode::checkNodeCollision(SceneNode& node, std::set<Pair>& collisionPairs)
{
        if (this != &node && collision(*this, node) && !isDestroyed() && !node.isDestroyed())
                collisionPairs.insert(std::minmax(this, &node));

        for (Ptr& child : children)
                child->checkNodeCollision(node, collisionPairs);
}

Checks the collision for the whole scene graph.
void SceneNode::checkSceneCollision(SceneNode& sceneGraph, std::set<Pair>& collisionPairs)
{
        checkNodeCollision(sceneGraph, collisionPairs);

        for (Ptr& child : sceneGraph.children)
                checkNodeCollision(*child, collisionPairs);
}

This is the base bounding rectangle for each scene node. By default it has no bounding rectangle
sf::FloatRect SceneNode::getBoundingRect() const
{
        return sf::FloatRect();
}

Then all other entities in the game (Like the ships, projectiles, ect) have this overload
sf::FloatRect Aircraft::getBoundingRect() const
{
        return getWorldTransform().transformRect(sprite.getGlobalBounds());
}

I believe that is all the code that deals with the actual collision detection. The handling of the collision I believe is fine (Though can't test it since no collisions register yet). IF more is needed I can post whatever is requested.

Now I also am displaying the bounding boxes on screen with a draw function so I don't believe they are the problem (Though I could be wrong I am quite new with SFML). Also have put cout statements in the collision function and it never tests true for any collision. So that leads me to think something is wrong with how I am navigating the scene graph but am not sure.

 Also I am currently getting rid of entities that leave the screen using a collision detection system which works (Which is what gets me confused). That method looks like this.
void World::destroyEntitiesOutsideView()
{
        Command command;
        command.category = Category::Projectile | Category::EnemyAircraft;
        command.action = derivedAction<Entity>(
        [this] (Entity& entity, sf::Time)
        {
                [b]if (!getBattlefieldBounds().intersects(entity.getBoundingRect()))
                {
                        entity.destroy();
                }[/b]
        });

        commandQueue.push(command);
}

// Return a rectangle of what is currently in view
sf::FloatRect World::getBattlefieldBounds() const
{
        return sf::FloatRect(worldView.getCenter() - worldView.getSize() / 2.f, worldView.getSize());
}

So when entities go off screen they are destroyed right away since they are not in the rectangle of battleBounds which is a tiny bit bigger then the window. So I  am not really sure why that works and the others don't.

I'm not really sure what other information would help with this one so if there is anything else I am not mentioning feel free to ask. Also thank you so much in advance for any advice you can give. I'm not so much looking for a solution to the problem more along the lines of learning what I did wrong and how I can fix it.
« Last Edit: August 25, 2013, 02:41:24 pm by Zereo »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Collision Detection Run-time bug (Following along with the SFML BOOK)
« Reply #1 on: August 25, 2013, 03:27:11 pm »
Since the code originates from the SFML book, can you clarify where it differs? As collision works in the book, these are the places where you can start searching for the bug.

You say collision() always returns false -- check the values of the involved rectangles (either using standard output or the debugger).
« Last Edit: August 25, 2013, 03:29:22 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Zereo

  • Newbie
  • *
  • Posts: 2
    • View Profile
Re: Collision Detection Run-time bug (Following along with the SFML BOOK)
« Reply #2 on: August 26, 2013, 12:26:09 pm »
EDIT 2: I found the bug which was little like I knew it would be since all the most painful bugs for me seem to be little mistakes. The problem was in checkSceneCollision() I was calling child->checkNodeCollision() on every child instead of child->checkSceneCollision().

Thanks for the help (It always helps me to explain the problem in detail to someone else to help myself wrap my head around what is going wrong. I really should by myself a little rubber ducky ;p) and again very great book was worth every penny.





Quote
Since the code originates from the SFML book, can you clarify where it differs? As collision works in the book, these are the places where you can start searching for the bug.

I believe most of the code except a few name changes is the same from the book and the downloadable source code. Though more then likely I might have missed a key concept.


Quote
You say collision() always returns false -- check the values of the involved rectangles (either using standard output or the debugger).

Thank you for this suggestion. I took your advice and it seems the reason why collision() always is returning false is because rhs.getBoundingRect() is always returning a 0, 0, 0, 0 rectangle... It seems rhs never holds a bounding rect that is not 0. It seems as though lhs always holds the bounding rects for the objects in the game and never rhs.

Going to try to research this a bit further in the code. Thank you for the help. Would also like to thank you for writing the SFML book ;p Probably one of the best Game Development books I have ever read and has taught me a lot of neat concepts I never knew about.\


EDIT: So I looked into it a bit more before work and I believe I found out what is happening (Correct me if I am wrong). I believe it is only checking the against the parent nodes and their children (Which would explain why rhs.getBoundingRect() always returns a 0,0,0,0 rectangle because it is a just a parent node which holds that group of on screen entities).

So for example I have a scene graph which looks like this


                         Root
                            |
                           / \
                         /     \
         Background     Air
                                 /\
                                /  \
                               /     \
                       player   enemies
                          /              \
                  player          enemy 
                  bullets         bullets

So Root has the children background (Background sprite) and Air(Which is just a normal scene node which will hold all the entities that in the Air). Background has no children. Air has has a bunch of children (The player and all the enemies on the screen). Player has children when he is firing projectiles and enemies have children when they are firing projectiles.

So if it is only checking children to parent for collision it would never check for player to enemy collision or player bullet to enemy collision and so on. Which is why no collisions are registering I believe.

I think the collision checks are looking like this

Root - Root = No collision
Background - Root = No collision
Air - Root = No Collision
Player - Air = No collision
Enemy1 - Air = No collision
Enemy2 - Air = No collision
...
...

That is just what I think is happen though I could be wrong since this is a weak spot of mine in programming.

Also this is how checkSceneCollision() is called inside world.

sceneGraph.checkSceneCollision(sceneGraph, collisionPairs);

sceneGraph is the root node for the scene graph and is of type SceneNode and collisionPairs is a set of pointers of SceneNodes.

Now I am even more confused about what the problem is and how to fix it ;p Looks like I will be researching this for awhile :(.
« Last Edit: August 26, 2013, 05:39:41 pm by Zereo »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Collision Detection Run-time bug (Following along with the SFML BOOK)
« Reply #3 on: August 27, 2013, 11:43:28 am »
Good that you found the bug! In general, using the standard output for logging or the debugger for inspecting variables at runtime is very helpful ;)
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

 

anything