5
\$\begingroup\$

The Problem:

I have the following setup:

enter image description here

A, B and C are rectangular static bodies in box2d. p is a circular dynamic body in box2d.

The movement of 'p' is solely controlled by the current gravity force of the world.

When 'p' collides with a static body (A, B or C) I play a bouncy sound. I handle this through a standard ContactListener. No problems there.

The problem arises when 'p' is on 'A' and traveling left towards 'B'. This causes another collision to fire (on 'B') which results in another bouncy sound which is unwanted. If however 'p' was to be traveling right and contacted 'C' I would want the sound to play (given enough velocity, etc).

TL;DR - When sliding across multiple static bodies how do I effectively ignore collisions from a body that is on the same 'line' I'm already on?

What I've Tried:

I've tried numerous different approaches such as on collision tracking that normal as my 'ground' normal and ignoring collisions from the same normal. This works until I do something like make contact with 'C' which then becomes my new 'ground' normal. But having never lost contact with 'A' if I go back towards 'B' I will trigger another collision and we're back to square one.

The Plea:

Looking for code-based solutions or ideas if at all possible. I've considered trying something like a chain shape around my level's collidable areas, but with certain parts of my world being dynamic I don't feel like that's an adequate solution.

Thanks!

\$\endgroup\$
2
  • \$\begingroup\$ Could you make the B and A the same object? I've never used libgdx so i have no idea what i'm talking about. :P \$\endgroup\$
    – ruckus
    Commented Jan 15, 2016 at 18:11
  • \$\begingroup\$ @VinceScalia Unfortunately not! Thanks for the suggestion. \$\endgroup\$
    – Matt Sams
    Commented Jan 15, 2016 at 18:23

4 Answers 4

2
\$\begingroup\$

If I understand the problem correctly, you were close to properly solving it.

Your approach with the normals is what you want, but instead of only saving the normal of the last collision, save a list of normals from all current collisions/overlappings. Then, play the sound whenever the new normal of the new collision is not yet present in the list.

In further detail, a "pseudo-implementation" would be like the following (to be applied regarding each obstacle with which collision happens/stops happening):

Vec2<> normals_list; //create a list to hold the normals
OnCollisionEnter(){
    Vec2 col_normal = Get.Collision.normal; //get the normal of the new collision
    int presence_in_list = 0;
    for(i=0; i < normals_list.Length; i++)
    {
        if(col_normal  == normals_list[i]){ presence_in_list; += 1; } //check how many times current collision's normal is already present within the list
    }
    if(presence_in_list == 0) { play.sound; } //if not present, play the sound
    normals_list.Add(col_normal); //add the normal of current collision to the list
}

OnCollisionExit{
    Vec2 col_normal = Get.Collision.normal; //get the normal of the new collision
    for(i=0; i < normals_list.Length; i++)
    {
        if(col_normal  == normals_list[i]){
            normals_list.Remove(normals_list[i]); //remove the normal from the list
            col_normal = Vec2(0,0); //to avoid deleting more than once, in case there were repeated normals in the list
        }
    }
}
\$\endgroup\$
4
  • \$\begingroup\$ I like this approach! I'll give it a try in a bit and see if that hits what I need. Thanks. \$\endgroup\$
    – Matt Sams
    Commented Jan 19, 2016 at 0:35
  • \$\begingroup\$ @deadpixelsociety Great. Hope it has helped. The logic will work, even if minor adjustments are necessary depending on your specific implementation. \$\endgroup\$
    – MAnd
    Commented Jan 19, 2016 at 8:23
  • \$\begingroup\$ @deadpixelsociety I got curious: did you happen to solve that problem properly in any way? If you did with something you came up, I suggest you put your own answer because this is a question that many beginners might have been struggling with. \$\endgroup\$
    – MAnd
    Commented Jan 23, 2016 at 0:53
  • \$\begingroup\$ It has not been solved on my side yet. When it is I'll update this question accordingly. \$\endgroup\$
    – Matt Sams
    Commented Jan 23, 2016 at 19:32
3
\$\begingroup\$

Have you considered playing the sound when the direction of the ball changes? Or like add that as a condition, in addition to the already "collide with object" condition.

\$\endgroup\$
4
  • \$\begingroup\$ I like this answer because it's a slightly out-of-the box idea that works well and shouldn't be that hard to implement. \$\endgroup\$
    – anon
    Commented Jan 15, 2016 at 21:46
  • \$\begingroup\$ It's out of the box, but what if the gravity vector is variable in the OP's game? E.g. the gravity vector is reversed in the middle of the fall and the ball changes direction midair -> the bouncing sound will play. \$\endgroup\$ Commented Jan 18, 2016 at 19:13
  • \$\begingroup\$ As I wrote; "add that as a condition, in addition to the already "collide with object" condition." Something like this is what I meant: if (directionChange && collisionDetected){playBouncingSound} \$\endgroup\$
    – Skitskraj
    Commented Jan 18, 2016 at 21:36
  • \$\begingroup\$ My rep is apparently too low to add comment on your question, it is meant as a followup on Vince Scalia's question. I've never used libgdx either, but looking at the javadocs, it seems that PolygonShape might be usable instead of the Box2D. Also, have you tried the ContactImpulse class? Maybe that is exactly what you are after, without having to redo the geometry... \$\endgroup\$
    – Skitskraj
    Commented Jan 20, 2016 at 16:01
2
\$\begingroup\$

Ok, I'm piggy-backing on Skitskraj's answer here so if you like mine, upvote his/hers too.

Solution: Play the sound only if there is a new contact and there is a significant velocity change. I would suggest using the postSolve callback on the first iteration of the collision to determine if the impulse is above some threshold value required to generate the bouncing sound.

\$\endgroup\$
1
\$\begingroup\$

Since you're not strictely looking for code-based answers you might want to try: only one ground static box

Of course assuming it doesn't constrict your level design. (Skitskraj's answer is pretty good too tho)

\$\endgroup\$
1
  • 1
    \$\begingroup\$ The problem here is that my world rotates. So the problem circle now moves to the left at the intersection of B and A again. :) \$\endgroup\$
    – Matt Sams
    Commented Jan 19, 2016 at 18:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .