The identity of a contact?

Posts that don't fit into other categories.
johnson
Posts: 14
Joined: Sat Apr 07, 2012 10:50 am
Contact:

The identity of a contact?

Postby johnson » Sun Apr 08, 2012 12:25 pm

Hello!

When implementing the ContactListener interface, the begin, end and persist methods take contact points as arguments. Assuming that I want to maintain a list of the current contacts for a body, adding and removing elements when begin and end methods are called, how do I determine that a given contact has "ended"? I can't compare the contact points passed to begin and end with reference equality as they're never the same object. I can't compare the positions of the contacts as those change, and there doesn't seem to be any sort of definitive "id" field in the ContactPoint structure...

This is mainly an issue when implementing traditional "character" movement: The player should not be allowed to jump when it does not have contact with the "ground". This would seem to necessitate maintaining a list of the current contacts (removing the ground contact from the list when the player jumps, etc).

William
Site Admin
Posts: 378
Joined: Sat Feb 06, 2010 10:23 pm

Re: The identity of a contact?

Postby William » Mon Apr 09, 2012 10:16 am

Yeah, I can see what you mean. I wonder if something like this would work:

Code: Select all

// setup
Body ground = new Body();
Body character = new Body();

// when the jump action is initiated
if (character.isInContact(ground)) {
  // apply a force to make the character jump
  // not sure what the force would need to be
  character.apply(new Vector2(0.0, 10.0);
}


This may still allow the player to jump more than once while the bodies separate (since there is a bit of overlap allowed for all collisions). If that's the case I would suggest storing a flag somewhere to not allow jumping when the flag is set. Then, when the jumping action is complete (you could check for renewed contact via the contact listener and == on the bodies of the contact point) reset the jumping flag.

Code: Select all

// something like this:
public boolean begin(ContactPoint p) {
  if ((p.body1 == character && p.body2 == ground)
    || (p.body1 == ground && p.body2 == character)) {
    // then we know that the body and character are in contact again
    allowJumping = true;
  }
}


William

johnson
Posts: 14
Joined: Sat Apr 07, 2012 10:50 am
Contact:

Re: The identity of a contact?

Postby johnson » Mon Apr 09, 2012 10:45 am

Ok, I'll see if I can duplicate the movement model with this method.

As an aside, I'm evaluating Box2D and Dyn4j for a commercial project. I've written a small proof-of-concept system involving basic character movement (walking, running, jumping, climbing) and buoyancy and am attempting to recreate this in Dyn4j. So far, Dyn4j has shown itself to be of vastly better quality than Box2D in terms of stability and lack of "surprising" results. It also has a working wheel joint. Nice work!

johnson
Posts: 14
Joined: Sat Apr 07, 2012 10:50 am
Contact:

Re: The identity of a contact?

Postby johnson » Sun Nov 04, 2012 11:00 am

Hello.

I've returned to the project after a few months delay and have still not found a satisfactory solution to this problem.

The problem is essentially that of unambiguously determining whether or not a given biped character is touching the "ground". The original suggestion posted was not really sufficient because it only dealt with the problem of jumping, whereas we have a more general need (in terms of gameplay mechanics) to determine whether or not a biped is on the ground or not. Of course, "touching the ground" is pretty subjective, so we've basically come up with the following:

A biped is touching the ground if:

1. Its small foot sensor is touching a solid object (see the tiny square below the circle representing the "legs"):

Image

OR

2. Its "legs" have at least two contacts with one or more solid objects, and the angles of the two points relative to the center of the circle fall within a certain range. This may be somewhat mysterious and difficult to understand, but the intention is to allow
the biped to "balance" over gaps:

Image

If either of the above conditions are true, then the biped is considered to be "balancing" and the joint that allows the legs to spin is locked in place by disabling the motor on the joint and fixing the angular velocity to 0. This prevents the biped from falling down slopes. We don't use a foot sensor the same width as the biped itself, as we found that this allowed bipeds to "lean" over the edges of platforms unrealistically far and not fall off. The biped in the following diagram will obviously fall off if it moves a tiny amount to the right, as the foot sensor will no longer be in contact with the platform:

Image

Previously, we used a pair of perpendicular rectangles, forming a cross shape, as the "legs" and then simply checked to see if the two rectangles each had a contact. If so, the biped was considered to be "balancing". Unfortunately, this cross shaped leg didn't really didn't behave very well, and was very "bumpy" when moving (unsurprising, really).

Image

So, we've replaced the legs with a simple circle as shown in the diagram and are now back to the original problem in that we can't unique identify contacts with the ContactListener interface. Right now, in the begin() method of the ContactListener, we determine the angle of the contact from the center of the circle, convert the angle to degrees, cast the value to an integer and use the integer as a key in HashMap. Each key is associated with a "timeout" value, and this value is decremented each frame for each contact in the map. We perform the same operation in the persist() method, except that we just reset the timeout value for a contact if one exists with the same angle. I believe that this approach only works because we can essentially uniquely identify a contact on a circle by the angle alone; it obviously won't work for any other shape. Because we can't unique identify contacts to remove them immediately when the end() callback fires in the ContactListener, we're regularly storing 10-20 redundant contacts in the set whilst waiting for each of them to "time out". It's pretty ugly stuff, and this is a very simple problem!

We really, really, really would prefer to just get a unique contact id: Created once in begin() by dyn4j, and then passed to us in persist() and end() for a given contact. Box2D and other physics engines do give the developer this information, so I don't believe there's anything intrinsically difficult about providing it: Presumably dyn4j does track this information internally in order to be able to call the persist() callback of the ContactListener at all!

William
Site Admin
Posts: 378
Joined: Sat Feb 06, 2010 10:23 pm

Re: The identity of a contact?

Postby William » Mon Nov 05, 2012 10:26 am

Thank you for your detailed post. This will surely help others that are trying to solve the same problem.

If I understand correctly your are wanting, from the ContactListener, on begin, end, and persist, a contact has a unique id. I have implemented this in the attached .jar and would like you test it out. I did a little of my own testing and it seems to be working.

There are two gotchas however that may or may not matter to you:
  1. The sensed contacts are not stored in the ContactManager so if you are looking for these "contacts" to persist you will need to store these and use the ContactPointId.equals method to test if they are the same contact
  2. There are times where the contacts move too much or move from one edge of a fixture to another. In these cases, the ContactPointId.equals method will return false. This may not be a problem if all you are doing is storing current contacts on the begin and removing them on the end method (then checking a count to determine if the two entities are in contact)

Let me know if this is working for you and I will do another release.

William
Attachments
ExampleContactPointId.java
My super simple test case for the changes
(15.77 KiB) Downloaded 295 times
dyn4j-v3.1.2-beta.jar
Test dyn4j for contact ids
(311.85 KiB) Downloaded 283 times

johnson
Posts: 14
Joined: Sat Apr 07, 2012 10:50 am
Contact:

Re: The identity of a contact?

Postby johnson » Mon Nov 05, 2012 1:40 pm

Thank you very much!

I'm about to attempt an implementation with the new contact ID code, and then I'll get back to you.

johnson
Posts: 14
Joined: Sat Apr 07, 2012 10:50 am
Contact:

Re: The identity of a contact?

Postby johnson » Mon Nov 05, 2012 2:01 pm

Works flawlessly. Exactly what we were looking for.

Thanks again for this! I look forward to the new release. I'll publish Maven packages for it, of course.

William
Site Admin
Posts: 378
Joined: Sat Feb 06, 2010 10:23 pm

Re: The identity of a contact?

Postby William » Mon Nov 05, 2012 8:08 pm

A new version is available now! Thanks for detailed report and testing.

William

johnson
Posts: 14
Joined: Sat Apr 07, 2012 10:50 am
Contact:

Re: The identity of a contact?

Postby johnson » Tue Nov 06, 2012 5:44 am

Packages pushed to Maven Central. Should be available within two hours.

http://search.maven.org/#search|ga|1|dyn4j


Return to “General Discussion”

Who is online

Users browsing this forum: No registered users and 1 guest