I have just learned JBox2D and figured I would make a little physics based puzzle game. I have all the knowledge besides collision detection so far. So is it possible for a JBox2D body to know what it is colliding with and act upon that collision?
No personal experience - but is that not what it is supposed to do?
I want say a crate to collide with a star. Right now, if i made the crate and start the would just bounce off of each other. I’d want them to know what type of object it is and then go to the next level.
You can either make it simple or you can make it complicated.
Basically you need to implement the “ContactListener” into one of your classes like so:
public class CollisionHandler implements ContactListener {
}
This will implement the following methods:
public void beginContact (Contact contact);
public void endContact (Contact contact);
public void preSolve (Contact contact, Manifold oldManifold);
public void postSolve (Contact contact, ContactImpulse impulse);
It is very important to know what each of these do, I will give you the skinny.
begingContact will be triggered when 2 fixtures collide, it will only be called once per touch. In order for it to be re-called you would need to separate the fixtures and re-collide them.
endContact is the opposite, it is called when 2 fixtures stop colliding.
The next 2 are a little more complicated and I will focus on mostly the post solve one, as this deals with continuous collision AFTER the contact impulse.
Basically this method gets called every single time a current contact is changed, so it goes like this >
beginContact > postSolve > endContact
When to use each one
If for instance you want to trigger a one time event, such as picking up an item or triggering a sensor callback, you would use the begin contact. If you used the postSolve, it would pickup tons of the same item or trigger the callback several times, causing issues.
So far the best thing I have bee using endContact for is sensors, such as door proximity sensors that surround the door in a circle, if the player touches it, beginContact is called and the door is open and remains open until he leaves the vicinity of the sensor, calling endContact closes the door.
A use for the postSolve would be if you had a side scrolling racing game (Hill Climb Racing), whenever the contact is changed you would want to do something, in this case create particles of mud.
How to tell if 2 specific fixtures are touching
This is the part that you can either make complicated or simple.
Each method has a Contact parameter, this holds reference to the 2 fixtures currently colliding, you can retrieve them by doing the following:
Fixture fixtureA = contact.getFixtureA();
Fixture fixtureB = contact.getFixtureB();
Now you can do some nifty if checks to see if the fixtures that are colliding belong to a certain object, the most simplest way of doing this is either to use the UserData of the fixture or the body itself, depending on how specific you need the collisions to be.
Here is an example of that:
public class Foo extends Box2DObject{
public Foo(float x, float y) {
/** Some helper methods I have, they do the same as doing it normally but easier to read */
createBody(BodyType.DynamicBody, x, y, 0);
createPolyFixture(1, 1, 0.50F, 1, 0.25f, false);
/* Here you can now set the body or the fixture UserData */
body.setUserData(this);
// or
fixture.setUserData(this);
}
}
So now the fixture or body user data holds a reference to your object, we can now do equality tests to see the object type. However it can get as advanced or as simple from here, I personally have an enum setup that holds types of collidable entities that can be assigned to anything I create. For the sake of this, we will just use a .equals check, even an instanceof check would be fine for messing around.
So from here I could do something like this:
public class FooTest extends Box2DObject {
/* Our world */
public static World world = new World(new Vector2(0, -9.81f), true);
/* Our own implementation of the contact listener */
FooCollide collide = new FooCollide();
/* All the foos! */
public static Array<Foo> foos = new Array<Foo>();
public FooTest() {
/* Add foos to the array */
float y = 0;
for (int x = 0; x < 10; x++) {
foos.add(new Foo(x, y));
y++;
}
}
public class Foo extends Box2DObject {
public Foo(float x, float y) {
/**
* Some helper methods I have, they do the same as doing it normally
* but easier to read
*/
createBody(BodyType.DynamicBody, x, y, 0);
createPolyFixture(1, 1, 0.50F, 1, 0.25f, false);
/*
* Here you can now set the body or the fixture UserData, both if
* you like
*/
body.setUserData(this);
// or
fixture.setUserData(this);
}
public void doSomethingCool() {
// Do something awesome
}
}
public class FooCollide implements ContactListener {
public FooCollide() {
/* Set the contact listener for the world to this */
FooTest.world.setContactListener(this);
}
@Override
public void beginContact(Contact contact) {
/* Lets cut down code here but putting these in a local */
Object object1 = contact.getFixtureA().getUserData();
Object object2 = contact.getFixtureB().getUserData();
/*
* Lets just be cheap and check everything in the array, there are
* better ways of doing it but this is just an example and will be
* fine as long as you don't have 1000000000's of shit
*/
for (Foo foos : FooTest.foos) {
/* Equality check! */
if (object1.equals(foos)) {
// The object in the user data is the same as one of our
// foos, lets do something
foos.doSomethingCool();
}
/* Equality check */
if (object2.equals(foos)) {
// The object in the user data is the same as one of our
// foos, lets do something
foos.doSomethingCool();
}
}
}
@Override
public void endContact(Contact contact) {
// TODO Auto-generated method stub
}
@Override
public void preSolve(Contact contact, Manifold oldManifold) {
// TODO Auto-generated method stub
}
@Override
public void postSolve(Contact contact, ContactImpulse impulse) {
// TODO Auto-generated method stub
}
}
}
From here I will leave it to you to figure out the rest, there are some complications involved with the above code, for instance. The 2 foos collided, that is great but how do we tell them a part? They are the same object, perhaps they have different fields? Maybe 1 foo is BETTER than the other foo and should cause it to explode…
Maybe 1 foo is a bullet and the other is a wall, now what?
Tons of ways you can do it, you just need to find an effective way to check is all.
I said there are better ways than checking through loops, well there is but so far I have not found a need to be that efficient and my arrays contain between 10 and 1000 items, and I check at least 3 of them for every begin contact. It is instantly with no FPS loss, this is with me throwing 10 grenades in my game, each which explode with 360 bodies all being created and flying out at a given angle.