Box2D- Best way to get Entity from Body

Hi, I’ve got several entities on my map, these have got a “box2d -Body”.
Now I would like to use the contactLister to get the entities, which collide.
At the moment I would use a Hashmap with the Body as key and the entity as value to get the entity, but that doesn’t seem to be a fast solution ::slight_smile:
How would you solve this problem?
best regards

Just put entity reference to body/fixture user data.

How would you do that?
I am using libgdx, should I download the sourcecode and add a variable to body.class?
best regards

body.setUserData(). There’s already a generic Object variable that you’re supposed to use just for that purpose.

thx ;D
Strange that I haven’t found this function.
Therefore it’s a newbie question :clue:
best regards

Hey. Sorry for butting in. I’ve completely missed this function too, and have just made the move to create entity-classes that can, from a name only, pull a body from the pool and load the correct fixture “unto themselves”, making the entity itself hold the Body, which is the other way around compared to what the userData-method is suggesting. If I do not use the userData-method, but stick with my own setup, is there still a way to register if 2 entities have hit eachother, and identify them? I’m having a hard time seeing it. Will I still have to register the entity with the Body attached to it, and will that be terribly weird, having an entity have a body, which has a reference to the entity which has the body?
Wow, that last sentence reminds me of “Inception”.

I have a singleton Physics class that wraps the functionality of Box2d. It implements ContactListener which exposes the body contact events – beginContact and endContact being the methods of interest. Both of these callbacks receieve a Contact object which has getFixtureA().getBody() and getFixtureB().getBody().

public final class Physics implements ContactListener {
    private static Physics _physics = null;

    private final World _world;
    private final ArrayList<HitWatcher> _hitWatchers;
    private final ArrayList<Body> _bodyQueue;
    private final ArrayList<HitWatcher> _hitWatcherRemovalQueue;

    private Physics() {
        _world = new World(new Vec2(0, Constants.GAME_PHYSICSGRAVITY), false);
        _hitWatchers = new ArrayList<>();
        _bodyQueue = new ArrayList<>();
        _hitWatcherRemovalQueue = new ArrayList<>();
        _world.setContactListener(this);
    }

    public synchronized void registerHitWacher(final HitWatcher hitWatcher) {
        _hitWatchers.add(hitWatcher);
    }

    public synchronized void removeHitWatcher(final HitWatcher hitWatcher) {
        _hitWatcherRemovalQueue.add(hitWatcher);
    }

    public static Physics getInstance() {
        if (_physics == null) {
            reset();
        }
        return _physics;
    }

    public static float toMeters(final int pixels) {
        return pixels * 0.02f;
    }

    public static int toPixels(final float meters) {
        return (int)(meters * 50.0f);
    }

    public Body createBody(final BodyDef bodyDef) {
        return _world.createBody(bodyDef);
    }

    public synchronized void removeBody(final Body body) {
        _bodyQueue.add(body);
    }

    public static void reset() {
        if (_physics != null) {
            Body b2Body = getInstance()._world.getBodyList();
            while(b2Body != null) {

                getInstance()._world.destroyBody(b2Body);
                b2Body = b2Body.getNext();
            }
        }
        _physics = new Physics();
        Player.getInstance().initializePhysics();
    }

    public synchronized void step() {

        // Please note that when we remove bodies, there is a chance that the bodies
        // won't actually exist anymore. This typically happens when stages have changed while
        // dynamic bodies are in play in a thread. This will ensure that this special scenario
        // is handled -- by checking the bodies before we actually remove them.
        if ((_bodyQueue.size() > 0) && !_world.isLocked()) {
            for(HitWatcher hitWatcher : _hitWatcherRemovalQueue) {
                _hitWatchers.remove(hitWatcher);
            }
            _hitWatcherRemovalQueue.clear();

            for(Body body : _bodyQueue) {

                // Make sure this body still actually exists...
                Body b = _world.getBodyList();

                do {
                    if (b == body) {
                        _world.destroyBody(body);
                        break;
                    }
                } while ((b = b.getNext()) != null);

            }

            _bodyQueue.clear();
        }

        final int _velocityIterations = 12;
        final int _positionIterations = 4;
        _world.step(Constants.GAME_PHYSICSTIME, _velocityIterations, _positionIterations);

    }

    @Override
    public void beginContact(final Contact contact) {
        for (final HitWatcher hitWatcher : _hitWatchers) {

            if (
                    (hitWatcher.getBody() != contact.getFixtureA().getBody()) &&
                    (hitWatcher.getBody() != contact.getFixtureB().getBody())
            ) { continue; }

            hitWatcher.getHitHandler().HitOccured(
                    contact.getFixtureA().getBody(),
                    contact.getFixtureB().getBody()
            );
        }
    }

    @Override
    public void endContact(final Contact contact) {
    }

    @Override
    public void preSolve(final Contact contact, final Manifold manifold) {
    }

    @Override
    public void postSolve(final Contact contact, final ContactImpulse contactImpulse) {
    }
}

With this, I have created two support classes. HitWatcher is used to store a body to watch for, and a handler callback to call when this body is involved in a collision event. I define it as so:

final class HitWatcher {
    private final HitHandler _hitHandler;
    private final Body _body;

    public HitWatcher(final HitHandler hitHandler, final Body body) {
        _hitHandler = hitHandler;
        _body = body;
    }

    public HitHandler getHitHandler() {
        return _hitHandler;
    }

    public Body getBody() {
        return _body;
    }
}

Then of course is the HitHandler, which is simply an interface any class can implement to support hit events:

public interface HitHandler {
    public void HitOccured(Body body1, Body body2);
}

With that, I can do very easy hit detection:

public final class Coin implements HitHandler {
    private Body _body;
    private HitWatcher _hitWatcher;
    private final int _startX;
    private final int _startY;
    private final Vec2 _force;

    public Coin(final int x, final int y, final Vec2 force) {
        _startX = x;
        _startY = y;
        _force = force;
    }

    public void initializePhysics() {
        BodyDef bodyDef = new BodyDef();
        bodyDef.type = BodyType.DYNAMIC;
        bodyDef.position.set(Physics.toMeters(_startX), Physics.toMeters(_startY));
        _body = Physics.getInstance().createBody(bodyDef);
        CircleShape dynamicBox = new CircleShape();
        float width = Physics.toMeters(Constants.GAME_TILESIZE)/ 2.0f;
        dynamicBox.m_radius = width * 0.8f;
        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.shape = dynamicBox;
        fixtureDef.density = 0.5f;
        fixtureDef.friction = 0.1f;
        _body.createFixture(fixtureDef);
        _body.setFixedRotation(true);
        _body.applyForce(_force, _body.getWorldCenter());
        _hitWatcher = new HitWatcher(this, _body);
        Physics.getInstance().registerHitWacher(_hitWatcher);
    }

    public void freePhysics() {
        Physics.getInstance().removeBody(_body);
    }

    public int getX() {
        return Physics.toPixels(_body.getPosition().x) + 5;
    }

    public int getY() {
        return Physics.toPixels(_body.getPosition().y) + 5;
    }

    @Override
    public void HitOccured(final Body body1, final Body body2) {

        if ((body1 != Player.getInstance().getBody())
            && (body2 != Player.getInstance().getBody())){
            return;
        }
        MusicPlayer.playSound(SoundEffect.Coin);
        Player.getInstance().setCoins(Player.getInstance().getCoins() + 1);
        Physics.getInstance().removeHitWatcher(_hitWatcher);
        Messenger.getInstance().pushMessage(new Message(MessageClass.Stage, MessageType.CoinDestroyed, this));
    }
}

When the above object is initiated, the code calls the theObect.initalizePhysics() method which sets up the physical body for box2d. The very last line of that code is:

        _hitWatcher = new HitWatcher(this, _body);
        Physics.getInstance().registerHitWacher(_hitWatcher);

This is all I have to do to attach to the physics engine and listen in to hit events without adding bulk to the physics class itself.

When this object is destroyed you do have to remember to remove the watcher from the physics engine (which I do on the HitOccured event in the above case):

Physics.getInstance().removeHitWatcher(_hitWatcher);

This is how I implemented collision in my game and it seems to work great, and keeps my code clean and object oriented :smiley:

In the game loop you just call Physics.getInstance().step() to keep the physics engine moving along.

@LunaticEdit: Thanks for writing that up! :slight_smile: I like this approach, and I might rewrite my own code to reflect some of your structure. But it seems there should be a better way to control this hit-detection, with all these listeners already on the Body’s and Fixtures. I’ll keep digging through examples and source, though. I might learn something.