Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (527)
Games in Android Showcase (127)
games submitted by our members
Games in WIP (593)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Box2D- Best way to get Entity from Body  (Read 1203 times)
0 Members and 1 Guest are viewing this topic.
Offline Phibedy

Senior Devvie


Medals: 9



« Posted 2012-12-27 13:18:49 »

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  Roll Eyes
How would you solve this problem?
best regards
Offline pitbuller
« Reply #1 - Posted 2012-12-27 19:11:29 »

Just put entity reference to body/fixture user data.
Offline Phibedy

Senior Devvie


Medals: 9



« Reply #2 - Posted 2012-12-27 21:13:05 »

How would you do that?
I am using libgdx, should I download the sourcecode and add a variable to body.class?
best regards
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline theagentd

« JGO Bitwise Duke »


Medals: 361
Projects: 2
Exp: 8 years



« Reply #3 - Posted 2012-12-27 23:59:04 »

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

Myomyomyo.
Offline Phibedy

Senior Devvie


Medals: 9



« Reply #4 - Posted 2012-12-28 10:38:28 »

thx  Grin
Strange that I haven't found this function.
Therefore it's a newbie question  Clueless
best regards
Offline Ultroman

JGO Knight


Medals: 25
Projects: 1


Snappin' at snizzes since '83


« Reply #5 - Posted 2012-12-28 18:19:13 »

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".

- Jonas
Offline LunaticEdit

Senior Devvie


Medals: 8
Projects: 1



« Reply #6 - Posted 2012-12-28 18:51:50 »

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().

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
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:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
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:

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


With that, I can do very easy hit detection:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
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:

1  
2  
        _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):

1  
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 Cheesy

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

Offline Ultroman

JGO Knight


Medals: 25
Projects: 1


Snappin' at snizzes since '83


« Reply #7 - Posted 2012-12-28 23:16:00 »

@LunaticEdit: Thanks for writing that up! Smiley 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.

- Jonas
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

PocketCrafter7 (12 views)
2014-11-28 16:25:35

PocketCrafter7 (7 views)
2014-11-28 16:25:09

PocketCrafter7 (8 views)
2014-11-28 16:24:29

toopeicgaming1999 (74 views)
2014-11-26 15:22:04

toopeicgaming1999 (64 views)
2014-11-26 15:20:36

toopeicgaming1999 (15 views)
2014-11-26 15:20:08

SHC (29 views)
2014-11-25 12:00:59

SHC (27 views)
2014-11-25 11:53:45

Norakomi (32 views)
2014-11-25 11:26:43

Gibbo3771 (28 views)
2014-11-24 19:59:16
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!